본문 바로가기

c언어 기초

c언어 포인터 pointer - 나도코딩

유튜브 나도코딩 c언어 기초 강의 내용입니다.

 

포인터 : 주소값을 저장하는 변수

 

메모리에서 주소는 숫자이므로 포인터 변수는 그냥 숫자가 들어가는 정수 변수일 뿐이다.

숫자가 주소일 뿐 단순하다.

포인터 변수 앞에 ' * ' 연산자가 붙고, 그 변수가 가지고 있는 정수값을 주소로 생각하면 된다.

' * '는 포인터를 선언하겠다는 의미와, 해당포인터가 가리키는 값을 가져온다는 의미를 가지고

' & '는 ' * '와 반대방향으로, 그 변수가 가리키던 주소의 위치를 받겠다는 의미를 가진다.

 

· 포인터 변수 선언 : int *ptr

· 포인터 변수에 주소 저장 : ptr = &a

· 포인터 변수 주소가 가리키는 메모리의 값 : *ptr;

 

int a = 1; // 

int *ptr;

ptr = &a;

printf(" a의 주소 : %d\n ptr의 값 : %d\n", &a, ptr);
printf("ptr이 가리키는 값 : %d\nptr의 주소 : %d", *ptr, &ptr);

위 예제를 보면 포인터 변수는 a값의 주소를 저장하게 됐고, *ptr을 통해 그 주소가 가지는 값을 보니 a 값과 같았다.

그리고 포인터 변수를 저장해두는 메모리 또한 있기 때문에 ptr변수 자체의 주소 또한 존재한다.

 

 

#include <stdio.h>

int main(void)
{
	// [철수] : 101호
	// [영희] : 201호
	// [민수] : 301호

	int 철수 = 1; // 암호
	int 영희 = 2;
	int 민수 = 3;

	printf("철수네 주소 : %d , 암호 : %d\n", &철수, 철수);
	printf("영희네 주소 : %d , 암호 : %d\n", &영희, 영희);
	printf("민수네 주소 : %d , 암호 : %d\n", &민수, 민수);


	// 미션맨
	// 첫번째 미션 : 아파트의 각 집에 방문하여 문에 적힌 암호 확인

	int* 미션맨;

	미션맨 = &철수;
	printf("미션맨이 방문하는 곳 주소 : %d , 암호 : %d\n", 미션맨, *미션맨);
	// 철수의 주소와 철수의 암호

	미션맨 = &영희;
	printf("미션맨이 방문하는 곳 주소 : %d , 암호 : %d\n", 미션맨, *미션맨);
	// 영희의 주소와 영희의 암호

	미션맨 = &민수;
	printf("미션맨이 방문하는 곳 주소 : %d , 암호 : %d\n", 미션맨, *미션맨);
	// 민수의 주소와 민수의 암호


	// 두 번째 미션 : 각 암호에 3을 곱해라

	미션맨 = &철수;
	*미션맨 = *미션맨 * 3;
	printf("미션맨이 암호를 바꾼 곳 주소 : %d, 암호 : %d\n", 미션맨, *미션맨);

	미션맨 = &영희;
	*미션맨 = *미션맨 * 3;
	printf("미션맨이 암호를 바꾼 곳 주소 : %d, 암호 : %d\n", 미션맨, *미션맨);

	미션맨 = &민수;
	*미션맨 = *미션맨 * 3;
	printf("미션맨이 암호를 바꾼 곳 주소 : %d, 암호 : %d\n", 미션맨, *미션맨);

	printf("\n");
	printf("민수네 주소 : %d , 민수네 암호 : %d\n", &민수, 민수); // 민수의 값 자체가 바뀌어있네
	printf("\n");


	// 스파이
	// 미션맨이 바꾼 암호에서 1을 빼라
	int* 스파이 = 미션맨;
	
	스파이 = &철수;
	*스파이 = *스파이 - 1;
	printf("스파이가 방문하는 곳 주소 : %d, 암호 : %d\n", 스파이, *스파이);

	스파이 = &영희;
	*스파이 = *스파이 - 1;
	printf("스파이가 방문하는 곳 주소 : %d, 암호 : %d\n", 스파이, *스파이);

	스파이 = &민수;
	*스파이 = *스파이 - 1;
	printf("스파이가 방문하는 곳 주소 : %d, 암호 : %d\n", 스파이, *스파이);

	printf("\n\n......철수 영희 민수는 집에 와서 바뀐 암호보고 놀램......\n\n");

	printf("철수네 주소 : %d , 암호 : %d\n", &철수, 철수);
	printf("영희네 주소 : %d , 암호 : %d\n", &영희, 영희);
	printf("민수네 주소 : %d , 암호 : %d\n", &민수, 민수);


	// 미션맨이 사는 곳의 주소는 &미션맨으로 확인
	printf("미션맨의 주소 : %d\n", &미션맨);
	printf("스파이의 주소 : %d\n", &스파이);

	return 0;
}

두번째 미션(미션맨)을 통해서 변수에 저장된 값을 직접 바꾸는게 아닌 포인터 변수를 이용해서 바꿀 수도 있다는 것을 알 수 있다.

포인터변수(미션맨)을 다른 포인터 변수(스파이)에 저장해서도 값을 바꿀 수 있다.

그리고 마지막 철수,영희,민수,미션맨,스파이의 주소를 보면 모두 다른 주소값을 가지고 있는데, 포인터 또한 하나의 변수기 때문에 그 자체로 주소를 가지고 있다.

 

 

만약 변수a에 저장된 데이터가 엄청 크다면 메모리를 많이 차지하니까 포인터변수를 만들어서 변수a 주소를 저장해두고 사용하면 메모리관리가 더 수월하지않을까....

#include <stdio.h>

int main(void)
{
	int arr[3] = { 5, 10, 15 };
	int* ptr = arr;
	for (int i = 0; i < 3; i++)
	{
		printf("배열 arr[%d] 의 값 : %d\n", i, arr[i]);
	}

	for (int i = 0; i < 3; i++)
	{
		printf("포인터 ptr[%d] 의 값 : %d\n", i, ptr[i]);
	}

	printf("\n");

	ptr[0] = 100;
	ptr[1] = 200;
	ptr[2] = 300;

	for (int i = 0; i < 3; i++)
	{
		printf("배열 arr[%d] 의 값 : %d\n", i, arr[i]);
	}

	for (int i = 0; i < 3; i++)
	{
		//printf("포인터 ptr[%d] 의 값 : %d\n", i, ptr[i]);
		printf("포인터 ptr[%d] 의 값 : %d\n", i, *(ptr +i)); // ptr[i] == *(ptr +i)
	}

	printf("\n");

	// arr == arr 배열의 첫번째 값의 주소와 동일 == &arr[0]
	
	printf("arr 자체의 값 : %d\n", arr);
	printf("arr[0]의 주소 : %d\n", &arr[0]);

	printf("arr 자체의 값이 가지는 주소의 실제 값 : %d\n", *arr);
	printf("arr[0]의 실제 값 : %d\n", *&arr[0]);
    
    
    
	return 0;
}

 

 

배열 arr은 크기만큼 메모리 주소를 연속으로 할당받은 것이다. arr 그 자체의 값은 arr[0]의 주소 값을 가지기 때문에

(arr = &arr[0]) 포인터변수에 배열을 저장할 때에는 주소연산자 '&'를 붙여줄 필요가 없다.