ch13 포인터와 배열

암영·2022년 5월 24일
0

c언어

목록 보기
14/21

13-1 포인터와 배열

배열의 이름은 무엇을 의미하는가?

배열의 이름도 포인터이다. 단, 그 값을 바꿀수 없는 '상수형태의 포인터'이다.

예제1)

#include <stdio.h>
int main()
{
	int arr[3] = { 0,1,2 };
	printf("배열의 이름 : %p \n", arr);
	printf("첫번째요소 %p \n", &arr[0]);
	printf("두번째요소 %p \n", &arr[1]);
	printf("세번째요소 %p \n", &arr[2]);
	//arr=&arr[i]; 이문장은 컴파일 에러를 일으킨다.

	return 0;	
}

%p:주소값을 출력하기 위한 서식문자

실행결과

실행결과를 총해 알수 있는 것
: int형 배열 요소간의 주소값의 차는 4바이트 이다.

arr의 메모리 공간 할당 형태

결론
:배열의 이름은 배열의 시작 주소 값을 의미하며,그 형태는 값의 저장이 불가능한 상수이다.
배열의 이름==포인터 상수
포인터이기 때문에 배열의 이름을 피 연산자로 하는 * 연산도 가능하다.

  • 포인터 별수와 배열이름의 비교

1차원 배열이름의 포인터 형과 배열이름을 대상으로 하는 *연산

  • 1차원 배열이름의 포인터형은 배열이름이 가리키는 대상을 기준으로 결정하면 된다.
#include <stdio.h>
int main()
{
	int arr1[3] = { 1,2,3 };
	double arr2[3] = {1.1,2.2,3.3};

	printf("%d %g \n", *arr1, *arr2);
	*arr1 += 100;
	*arr2 += 120.5;
	printf("%d %g\n", arr1[0], arr2[0]);
	return 0;
	
}

결과

printf("%d %g \n", *arr1, *arr2);

arr1과 arr2가 가리키는 대상을 출력하고 있다. 따라서 arr1과 arr2가 가리키는 배열의 첫번째 요소가 출력된다.

#include <stdio.h>
int main()
{
	int arr1[3] = { 1,2,3 };
	
	arr1[0] += 5;
	arr1[1] += 7;
	arr1[2] += 9;
	....
}

위의 코드에서 배열이름 arr은 int형 포인터이니, 포인터 대상으로 배열의 모든 요소를 arr[0],arr[1],arr[2]로 접근했다.
포인터 변수 ptr대상으로 ptr[0],ptr[1],ptr[2]와 같은 형태로 메모리 공간에 접근이 가능하다.

포인터를 배열의 이름처럼 사용할 수 있다.

  • 포인터 변수로 할수 있는 연산은 배열의 이름으로도 할 수 있고, 배열의 이름으로 할 수 있는 연산은 포인터 변수로도 할 수 있다.
#include <stdio.h>
int main()
{
	int arr[3] = { 15,25,35 };
	int* ptr = &arr[0]; //int* ptr = arr;과 동일한 문장

	printf("%d %d \n", ptr[0], arr[0]);
	printf("%d %d \n", ptr[1], arr[1]);
	printf("%d %d \n", ptr[2], arr[2]);
	printf("%d %d \n", *ptr, *arr);
	return 0;
}

위예제에서 보듯이 포인터 변수를 배열의 이름처럼 사용하는 경우는 거의 없고 마찬가지로 배열의 이름을 포인터 변수처럼 사용하는 경우도 거의 없다. 하지만 이런 일이 가능하다는 사실은 알고 있어야한다. 포인터를 정확히 이해하는데 중요한 지식이다.

13-2 포인터 연산

포인터를 대상으로 하는 증가 및 감소연산

포인터 변수를 대상으로 다음과 같이 다양한 형태의 증가 및 감소 연산을 진행할 수 있다.

  • int형 포인터를 대상으로 1을 증가시키면 4가 증가하고, double형 포인터를 대상으로 1을 증가시키면 8이 증가한다.
    <포인터를 대상으로 하는 연산의 결과>
    int형 포인터 대상으로 n증가/감소 nsizeog(int)의 크기만큼증가/감소
    double형 포인터 대상으로 n증가/감소 n
    sizeog(double)의 크기만큼증가/감소
#include <stdio.h>
int main()
{
	int* ptr1 = 0x0010;
	double* ptr2 = 0x0010;

	printf("%p %p\n", ptr1 + 1, ptr1 + 2); //4가 증가하고 8이 증가한다.
	printf("%p %p\n", ptr2 + 1, ptr2 + 2); //8이 증가하고 16이 증가한다

	printf("%p %p\n", ptr1, ptr2);
	ptr1++;
	ptr2++;
	printf("%p %p\n", ptr1, ptr2);
	return 0;
}

이런 연산 특성으로 인해 다음예제에서 보이는 배열 접근이 가능하다.

#include <stdio.h>
int main()
{
	int arr[3] = { 11,22,33 };
	int* ptr = arr;
	printf("%d %d %d\n", *ptr, *(ptr + 1), *(ptr + 2));

	printf("%d ", *ptr); ptr++;
	printf("%d ", *ptr); ptr++;
	printf("%d ", *ptr); ptr--;
	printf("%d ", *ptr); ptr--;
	printf("%d", *ptr); printf("\n");
	return 0;
}

(++ptr)=20; //ptr에 저장된 값 자체를 변경
(ptr+1)=20; //ptr에 저장된 값은 변경하지 않음

중요한 결론! arr[i]==*(arr+i)

나중에 배울 다차원 배열에도 유용한 식이니 꼭 기억해야 한다!

문제 13-1:포인터를 이용한 배열의 접근

1

내가 쓴답(정산 출력됨) 이게 2번 정답..!

#include <stdio.h>
int main()
{
	int arr[5] = { 1,2,3,4,5};
	int* ptr = arr;
	int len = sizeof(arr) / sizeof(int);

	for (int i = 0; i < len; i++)
	{
		*(ptr + i) += 2;
		
	}
	for (int i = 0; i < len; i++)
	{
		printf("%d ", arr[i]);

	}

	return 0;
}

정답

#include <stdio.h>
int main()
{
	int arr[5] = { 1,2,3,4,5};
	int* ptr = arr;
	int len = sizeof(arr) / sizeof(int);

	for (int i = 0; i < len; i++)
	{
		*ptr+=2;
        ptr++;
		
	}
	for (int i = 0; i < len; i++)
	{
		printf("%d ", arr[i]);

	}

	return 0;
}

2

#include <stdio.h>
int main()
{
	int arr[5] = { 1,2,3,4,5};
	int* ptr = arr;
	int len = sizeof(arr) / sizeof(int);

	for (int i = 0; i < len; i++)
	{
		*(ptr + i) += 2;
		
	}
	for (int i = 0; i < len; i++)
	{
		printf("%d ", arr[i]);

	}

	return 0;
}

3

#include <stdio.h>
int main()
{
	int arr[5] = {1,2,3,4,5 };
	int* ptr = &arr[4]; //배열이름이 아니니까 &를 써줘야 주소로 인식된다
	int i = 0;
	int sum = 0;
	for (i=0; i < 5; i++)
	{
		sum += *ptr;
		ptr--;
	}
	printf("합:%d", sum);

	return 0;
}

4

#include <stdio.h>
int main()
{
	int arr[6] = { 1,2,3,4,5,6 };
	int* start = arr;
	int* fin = &arr[5];
	int i, temp;
	for (i = 0; i < 3; i++)
	{
		temp = *start;/포인터가 가리키는 값에 접근할때 :*ptr;
		*start=*fin;
		*fin = temp;
		start++;
		fin--;

	}
	for (i = 0; i < 6; i++)
		printf("%d ",arr[i]);

	return 0;
}

13-3:상수 형태의 문자열을 가리키는 포인터

문자열의 선언방식
1.배열을 이용
2.char형 포인터 변수를 이용

두가지 형태의 문자열 표현

1.변수 형태의 문자열
배열을 대상으로는 값의 변경이가능하다

char str1[]="my string"; //배열의 길이는 자동적으로 저장된다

2.상수형태의 문자열

char*str2="your string";

포인터 변수str2가 가리키는 문자열은 그 내용의 변경이 불가능하다.

이렇게 선언하면 메모리 공간에 문자열이 저장되고, 문자열의 첫번째 문자y의 주소값이 반환된다. 그리고 그 반환 값이 포인터 변수 str2에 저장된다.

두 문자열 선언의 차이점

"배열이름 str1은 계속해서 문자 m이 저장된 위치를 가리키는 상태이여야 하지만 포인터 변수 str2는 다른 위치를 가리킬 수 있다."

어디서든 선언 할 수 있는 상수 형태의 문자열

char *str="const string";

문장이 처리되는 과정

1 문자열이 메모리 공간에 저장
2.메모리값 주소값이 반환

문자열이 저장된 이후 아래와 같은 형태가 됨.

//과정1
char *str=0x1234; //0x1234번지에 저장되었다고 가정. 

함수 호출과정에서 선언되는 문자열을 처리하는과정

마찬가지로 메모리 공간에 저장죈 후 그 주소값이 반환된다. 따라서 이 함수 호출 문장도 메모리 공간에 문자열이 저장된 이후 바로 과정1과 같은 형태가 된다.

printf("show your string");

printf함수는 문자열의 주소값을 전달받는 함수다!"

13-4 포인터 변수로 이뤄진 배열:포인터 배열

포인터 배열의 이해

포인터 배열
:포인터 변수로 이루어져 주소값의 저장이 가능한 배열

  • 선언 방식
int * arr1[20];
double * arr2[30];

예제

#include <stdio.h>
int main()
{
	int num1 = 10, num2 = 20, num3 = 30;
	int* arr[3] = { &num1,&num2,&num3 };
	printf("%d\n", *arr[0]);
	printf("%d\n", *arr[1]);
	printf("%d\n", *arr[2]);
	return 0;
}

문자열을 저장하는 포인터 배열

char형 포인터 배열
:문자열 주소값을 저장할수 있는 배열

char * strArr[3]; //길이가 3인 포인터 배열

예제

#include <stdio.h>
int main()
{
	char* strArr[3] = { "simple","string","arrary" };
	printf("%s\n", strArr[0]);
	printf("%s\n", strArr[1]);
	printf("%s\n", strArr[2]);
	return 0;
}

큰따옴표로 묶어서 표시되는 문자열은 그 형태에 상관없이 메모리 공간에 저장된후 그 주소값이 반환된다

profile
just do! -얼레벌레 굴러가는 공대생

0개의 댓글