c언어 배열과 포인터 / 포인터를 변수명으로 활용 / 포인터배열 선언

 

포인터 기본 개념이해1, 2를 통해서 포인터가 무엇인지 공부했습니다. 이번에는 배열(Array)과 포인터에 대해서 공부해보는 시간을 가져보겠습니다. 

 

배열(Array)

2020/06/09 - [programming/C Programming] - c언어 배열의 선언과 사용(1차원 배열)

 

c언어 배열의 선언과 사용(1차원 배열)

이전에는 배열을 사용하기 앞서 함수의 사용법과 do ~ while을 사용한 반복문에 대해서 공부했습니다. do ~ while의 예제 소스중에서 국어, 수학, 영어, 사회, 과학 5개의 과목을 계속해서 입력받을 수

swpfun.tistory.com

배열에 대해서는 1차원 배열의 선언에 대해서 공부했었습니다. 

 

소스 코드를 통해서 변수선언과 배열선언시에 주소값이 어떻게 할당되어지는지 확인해 보도록 하겠습니다.

#include <stdio.h>

void main(void)
{
	int a;
	int b; 
	int c[5];

	printf("a의 주소값은 %d 입니다.\n", &a);
	printf("b의 주소값은 %d 입니다. \n", &b);

	printf("c[0]의 주소값은 %d 입니다.\n", &c[0]);
	printf("c[1]의 주소값은 %d 입니다.\n", &c[1]);
	printf("c[2]의 주소값은 %d 입니다.\n", &c[2]);
	printf("c[3]의 주소값은 %d 입니다.\n", &c[3]);
	printf("c[4]의 주소값은 %d 입니다.\n", &c[4]);

}

위 소스에서는 int a와 b 그리고 int형 배열인 c를 선언했습니다. 각각의 주소값에 대해서 한번 결과를 통해 알아보겠습니다. 

int a를 선언한 다음에 int b를 선언했는데 a의 주소값은 9697200이고 b의 주소값은 9697188 입니다. a와 b의 주소값에 어떠한 연속성도 없는 것을 확인 할 수 있습니다. 그렇다며 배열의 주소값은 어떻게 될까? 

 

배열을 선언한 'c'의 배열의 주소값을 보면 c[0]의 주소값은 9697160, c[1]의 주소값은 9697164, c[2]의 주소값은 9697168로 각각 자료형 int의 할당된 메모리 공간만큼의 할당을 받아 연속적인 주소값을 가지고 있는 것을 확인 할 수 있습니다. 

 

 각각의 int형 메모리 4byte를 연속적으로 할당 받아 만약 메모리 주소 100번에 c[0]이 생성되었다면 4byte의 공간을 두고 100, 104 ~ 116 까지 메모리를 할당받게 되는 것 입니다. 

 

#include <stdio.h>

void main(void)
{
	char c[5];

	printf("c[0]의 주소값은 %d 입니다.\n", &c[0]);
	printf("c[1]의 주소값은 %d 입니다.\n", &c[1]);
	printf("c[2]의 주소값은 %d 입니다.\n", &c[2]);
	printf("c[3]의 주소값은 %d 입니다.\n", &c[3]);
	printf("c[4]의 주소값은 %d 입니다.\n", &c[4]);

}

그렇다면 1byte의 문자 배열의 주소값은 어떻게 될까? 

자료형 char은 메모리 할당을 1byte씩 할당받기 때문에 c[0]의 주소값은 16317156 c[1]의 주소값은 16317157로 주소값이 1씩 증가되는 것을 확인할 수 있습니다. 

 

배열 포인터 활용
#include <stdio.h>

void main(void)
{
	int a[5] = { 0 };

	for (int i = 0; i < 5; i++) {
		printf("a[%d]의 값은? %d \n",i, a[i]);
	}

}

 먼저 배열 a[5]를 선언하고 0으로 초기화 시킨다음에 소스코드를 하나하나 추가하면서 값을 한번 살펴보겠습니다. 

 

0으로 초기화 시켰으니 값은 모두 0이 들어가있겠네요. 

#include <stdio.h>

void main(void)
{
	int a[5] = { 0 };

	int* ptr = a;        //포인터 변수 ptr선언

	*ptr = 5;          // ptr이 가리키는 곳의 값을 5로 변경! 

	for (int i = 0; i < 5; i++) {
		printf("a[%d]의 값은? %d \n",i, a[i]);
	}

}

포인터 변수 ptr을 선언하고 배열명 a값을 대입한뒤에 가리키는 곳의 값을 5로 변경하면 결과 값은 어떻게 될까?

첫번째로 포인터 변수 ptr이 가리키고 있는 a[0]의 주소가 가지고 있는 값을 5로 변경하게 됩니다. 그러면 ptr에는 어떤 값이 들어있을까?? 

 

#include <stdio.h>

void main(void)
{
	int a[5] = { 0 };

	int* ptr = a;        //포인터 변수 ptr선언

	*ptr = 5;          // ptr이 가리키는 곳의 값을 5로 변경! 

	printf("ptr의 값은 %d \n\n", ptr);
	
	for (int i = 0; i < 5; i++) {
		printf("a[%d]의 주소값 = %d\n", i, &a[i]);
	}

}

포인터 변수 ptr에는 배열 a의 첫번째 주소값의 정보를 가지고 있습니다. 따라서 간접참조연산자(*)를 사용해 값을 바꾸게 되면 현재의 ptr이 가리키고 있는 주소 a[0]의 값만 바뀌게 되는 것입니다. 

 

그러면 a[1] ~ a[4]까지의 값은 바꿀 수 없나?? 

#include <stdio.h>

void main(void)
{
	int a[5] = { 0 };

	int* ptr = a;        //포인터 변수 ptr선언
		
	
	for (int i = 0; i < 5; i++) {

		printf("ptr의 값은 %d \n", ptr);               // ptr의 주소값 출력 
		printf("a[%d]의 주소값 = %d\n", i, &a[i]);        // a[i]의 주소값 출력 

		*ptr = i;                                        // 간접참조연산자로 ptr이 가리키고 있는 주소의 값을 i값으로 대입
		printf("a[%d]의 값은? %d \n\n", i, a[i]);          // a[i]의 값을 출력 

		ptr = ptr + 1;                             // ptr에 1을 더함  
	
	}

}

해당 소스코드를 보면 ptr = ptr +1; 이라고 쓰여있는 코드를 볼 수 있습니다. ptr은 배열 a의 주소값을 가지고 있습니다. 예를 들어 a[0]의 주소값이 100이라면 처음 ptr의 값은 a[0]의 주소값인 100을 출력합니다. 하지만 ptr에 1을 더하게 되면 a[0]의 다음 주소인 a[1]의 주소값을 가지게 됩니다. 

 

처음 ptr은 a[0]의 주소를 가리키고 ptr +1은 a[1]을 ~~~ ptr +4는 a[4]를 가리키고 있게 되는 것입니다. 

 

배열명처럼 사용할 수 있는 포인터 
#include <stdio.h>

void main(void)
{
	int a[5] = { 0 };

	int* ptr = a;        //포인터 변수 ptr선언
		
	
	for (int i = 0; i < 5; i++) {

		printf("ptr의 값은 %d \n", &ptr[i]);               // ptr의 주소값 출력 
		printf("a[%d]의 주소값 = %d\n", i, &a[i]);        // a[i]의 주소값 출력 

		ptr[i] = i;                                        // 간접참조연산자로 ptr이 가리키고 있는 주소의 값을 i값으로 대입
		printf("a[%d]의 값은? %d \n\n", i, a[i]);          // a[i]의 값을 출력 
                           // ptr에 1을 더함  
	
	}

}

 

위에서 ptr의 값을 증가시켜 배열의 값을 변경하거나 배열의 주소값을 확인했다면 포인터 변수를 배열명처럼 사용하는 방법또한 가능합니다.  

 

a의 배열을 선언하고 사용할때에는 a[0] ~ a[4]까지 배열명 a의 각각의 배열요소를 통해서 사용했습니다. 

포인터 변수 ptr에 배열 a을 대입하게 되면 포인터 변수를 배열명으로 사용하는 방법또한 가능하게 됩니다. 

 

포인터 배열선언 

위에서는 배열을 선언하고 배열의 값을 포인터 변수에 대입하는 것을 봤습니다. 포인터 변수도 배열선언을 할 수 있습니다! 

#include <stdio.h>

void main(void)
{
	char* ptr[4] = { "hong","ji","kun","tistory"};

	for (int a = 0; a < 4; a++) {
		printf("ptr[%d]의 값은= %s \n", a, ptr[a]);
	}

}

포인터 배열의 선언은 배열의 선언방법과 동일하지만 앞에 *을 붙여 포인터라는 것을 명시해주기만 하면됩니다. 

포인터 배열 2차원 배열처럼 활용

위에서 포인터의 배열선언과 포인터 변수명을 배열명으로 사용할 수 있는 방법에 대해서 공부했습니다. 이걸 가지고 이제는 포인터 배열을 활용해 2차원 배열처럼 사용하는 방법에 대해서 알아보겠습니다. 

 

포인터 배열의 값을 초기화할때 일반 배열을 대입할 수 있습니다. 

포인터 배열 ptr[2]를 선언하게 되면 ptr[0], ptr[1]의 메모리를 할당받게 됩니다. 각각의 초기화를 ptr[0]에는 a배열의 주소값을 ptr[1]에는 b배열의 주소갑을 대입하게 되는데 위에서 사용했던 배열명으로 사용하는 방법과 동일하게 ptr[0]에 들어있는 [n번째] 값을 가지고 오게 되기 때문에 2차원 배열처럼 활용을 할 수 있게 됩니다. 

댓글

Designed by JB FACTORY