언어/C

[코딩자율학습] 12일차 포인터

홍시_코딩기록 2024. 3. 19. 23:38

📌 변수와 메모리

#include <stdio.h>

int main(void) {
	int 철수 = 1;
	int 영희 = 2;
	int 민수 = 3;
	printf("철수네 주소: %p, 암호 : %d\\n", &철수, 철수);

		//철수네 주소: 0000003D3211F8E4, 암호 : 1 << 출력
	//영희네 주소 : 00000011B72FF564, 암호 : 2
	//민수네 주소 : 00000011B72FF584, 암호 : 3

	return 0;
}
  • 101호 사는 철수를 우리는 101호라고 읽지만, 실제 메모리에서는 어떤 값인지 모름.
  • 이 값을 알아내려면? 변수명 앞에 **&**를 붙여 출력, 서식지정자는 포인터를 의미하는 %p
  • 철수의 주소 위치에 철수라는 이름으로 공간을 할당하고 그 안에 1이라는 값을 넣음.

 

📌 포인터로 다른 변수의 주소와 값 알아내기

#include <stdio.h>

int main(void) {
	int 철수 = 1;
	int 영희 = 2;
	int 민수 = 3;
	printf("철수네 주소: %p, 암호 : %d\\n", &철수, 철수);
	printf("영희네 주소: %p, 암호 : %d\\n", &영희, 영희);
	printf("민수네 주소: %p, 암호 : %d\\n", &민수, 민수);

	/*
	철수네 주소 : 000000C2FD70F714, 암호 : 1
	영희네 주소 : 000000C2FD70F734, 암호 : 2
	민수네 주소 : 000000C2FD70F754, 암호 : 3
	*/

	//포인터 변수 선언과 값 출력
	int* 미션맨;
	미션맨 = &철수;
	printf("미션맨이 방문한 곳의 주소: %p, 암호: %d\\n", 미션맨, *미션맨);
	//미션맨이 방문한 곳의 주소:  000000C2FD70F714, 암호 : 1

	return 0;
}
  • 포인터 변수는 메모리의 주소값을 저장하는 변수, 앞에 *가 있음.
  • 변수 미션맨에는 철수의 주소가 할당되어 있어서 이대로 출력하면 철수의 주소를 알 수 있음.
  • 암호는 철수의 주소에 들어있는 값이어서 포인터 변수명 앞에 *을 붙이면 됨.

 

 

📌 포인터로 다른 변수의 값 바꾸기

각 집의 암호에 3을 곱하라

#include <stdio.h>

int main(void) {
	int 철수 = 1;
	int 영희 = 2;
	int 민수 = 3;
	printf("철수네 주소: %p, 암호 : %d\\n", &철수, 철수);
	printf("영희네 주소: %p, 암호 : %d\\n", &영희, 영희);
	printf("민수네 주소: %p, 암호 : %d\\n", &민수, 민수);

	/*
	철수네 주소 : 000000C2FD70F714, 암호 : 1
	영희네 주소 : 000000C2FD70F734, 암호 : 2
	민수네 주소 : 000000C2FD70F754, 암호 : 3
	*/

	//포인터 변수 선언과 값 출력
	int* 미션맨;
	미션맨 = &철수;
	printf("미션맨이 방문한 곳의 주소: %p, 암호: %d\\n", 미션맨, *미션맨);
	//미션맨이 방문한 곳의 주소:  000000C2FD70F714, 암호 : 1	
	
	*미션맨 = *미션맨 * 3;
	printf("미션맨이 암호를 바꾼 곳의 주소: %p, 암호: %d\\n", 미션맨, *미션맨);
	//미션맨이 암호를 바꾼 곳의 주소:  000000C2FD70F714, 암호 : 3	

	return 0;
}
  • *미션맨 포인터 변수의 값을 곱하기 3으로 선언함.

 

 

📌 포인터 추가하기

미션맨들의 장소에 도둑이 등장이라니..

도둑이 등장해서 암호 -1씩 훔쳐감.

#include <stdio.h>

int main(void) {
	int 철수 = 1;
	int 영희 = 2;
	int 민수 = 3;
	printf("철수네 주소: %p, 암호 : %d\\n", &철수, 철수);
	printf("영희네 주소: %p, 암호 : %d\\n", &영희, 영희);
	printf("민수네 주소: %p, 암호 : %d\\n", &민수, 민수);

	/*
	철수네 주소 : 000000C2FD70F714, 암호 : 1
	영희네 주소 : 000000C2FD70F734, 암호 : 2
	민수네 주소 : 000000C2FD70F754, 암호 : 3
	*/

	//포인터 변수 선언과 값 출력
	int* 미션맨;
	미션맨 = &철수;
	printf("미션맨이 방문한 곳의 주소: %p, 암호: %d\\n", 미션맨, *미션맨);
	//미션맨이 방문한 곳의 주소:  000000C2FD70F714, 암호 : 1

	*미션맨 = *미션맨 * 3;
	printf("미션맨이 암호를 바꾼 곳의 주소: %p, 암호: %d\\n", 미션맨, *미션맨);
	//미션맨이 암호를 바꾼 곳의 주소:  000000C2FD70F714, 암호 : 3	

	printf("\\n=== 도둑 등장 === \\n");
	int* 도둑 = 미션맨;
	*도둑 = *도둑 - 1;
	printf("도둑이 방문한 곳의 주소: %p, 암호: %d\\n", 도둑, *도둑);
	//도둑이 방문한 곳의 주소:  000000C2FD70F714, 암호 : 2	

	return 0;
}
  • 철수네 암호는 1이었는데 미션맨이 3으로 바꾸고 도둑이 훔쳐서 2로 바뀜. 철수는 집 못들어가겠다.

 

 

📌 포인터로 배열 다루기

#include <stdio.h>

int main(void){
	int arr[3] = {5,10,15};
	for (int i = 0; i < 3; i++) {
		printf("배열 arr[%d]값 : %d\\n", i, arr[i]);
		//배열 arr[0]값 : 5
		//배열 arr[1]값 : 10
		//배열 arr[2]값 : 15
	}
	int* ptr = arr;
	for (int i = 0; i < 3; i++) {
		printf("포인터 변수 ptr[%d]의 값: %d\\n", i, ptr[i]);
		//포인터 변수 ptr[0]의 값 : 5
		//포인터 변수 ptr[1]의 값 : 10
		//포인터 변수 ptr[2]의 값 : 15
	}
	ptr[0] = 100;
	ptr[1] = 200;
	ptr[2] = 300;
	for (int i = 0; i < 3; i++) {
		printf("배열 arr[%d]값 : %d\\n", i, arr[i]);
		//배열 arr[0]값 : 100
		//배열 arr[1]값 : 200
		//배열 arr[2]값 : 300
	}
	for (int i = 0; i < 3; i++) {
		printf("포인터 변수 ptr[%d]의 값: %d\\n", i, ptr[i]);
		//포인터 변수 ptr[0]의 값 : 100
		//포인터 변수 ptr[1]의 값 : 200
		//포인터 변수 ptr[2]의 값 : 300
	}

	return 0;
}
  • 포인터 변수의 값을 바꾸기 전에는 배열의 초깃값 그대로 5, 10, 15가 출력이 됨.
  • 값을 새로 넣으면 포인터 변수가 직접 배열의 각 요소에 접근해서 값을 바꿈.

 

 

📌 포인터로 값 교환하기

#include <stdio.h>

void swap(int a, int b);

int main(void) {
	int a = 10;
	int b = 20;
	printf("swap() 함수 호출 전 => a: %d, b : %d\\n", a, b);
	swap(a, b);
	printf("swap() 함수 호출 후 => a: %d, b : %d\\n", a, b);
	return 0;
}

void swap(int a, int b) {
	int temp = a;
	a = b;
	b = temp;
	printf("swap() 함수 안 => a: %d, b: %d\\n", a, b);
}
  • 이렇게 하면 a와 b의 값이 바뀌어서 나올 것 같지만 출력값은
swap() 함수 호출 전 => a: 10, b : 20
swap() 함수 안 => a: 20, b: 10
swap() 함수 호출 후 => a: 10, b : 20
  • 함수에서는 a와 b가 값이 바꼈는데 호출 후의 값에는 그대로임. 왜 그럴까???
  • 실제로는 두 변수 자체가 아닌 두 변수의 값만 전달해서 그럼. 무슨 소리냐면

 

int main(void) {
	int a = 10;
	int b = 20;
	printf("a의 주소: %p\\n", &a);
	printf("b의 주소: %p\\n", &b);
	printf("swap() 함수 호출 전 => a: %d, b : %d\\n", a, b);
	swap(a, b);
	printf("swap() 함수 호출 후 => a: %d, b : %d\\n", a, b);
	return 0;
}

void swap(int a, int b) {
	printf("swap() 함수 안에서 a의 주소: %p\\n", &a);
	printf("swap() 함수 안에서 b의 주소: %p\\n", &b);
	int temp = a;
	a = b;
	b = temp;
	printf("swap() 함수 안 => a: %d, b: %d\\n", a, b);
}

//a의 주소 : 0000000F1910F6C4
//b의 주소 : 0000000F1910F6E4
//swap() 함수 호출 전 = > a: 10, b : 20
//swap() 함수 안에서 a의 주소 : 0000000F1910F6A0
//swap() 함수 안에서 b의 주소 : 0000000F1910F6A8
//swap() 함수 안 = > a: 20, b : 10
//swap() 함수 호출 후 = > a: 10, b : 20
  • 변수 a, b의 주소가 서로 다름. 이로서 main()함수에 a와 swqp()의 a는 다른 변수인 것을 알 수 있음.
  • 전달값으로 변수를 넘기면 호출한 함수 안에서는 변수 자체가 아닌 전달받은 변수의 값만 복사해서 사용 >> 값에 의한 호출 이라고 부름.

 

#include <stdio.h>

void swap_addr(int * a, int * b);

int main(void) {
	int a = 10;
	int b = 20;
	printf("swap_addr() 함수 호출 전 => a: %d, b : %d\\n", a, b);
	swap_addr(&a, &b);
	printf("swap_addr() 함수 호출 후 => a: %d, b : %d\\n", a, b);
	return 0;
}

void swap_addr(int* a, int* b) {
	int temp = *a;
	*a = *b;
	*b = temp;
	printf("swap_addr() 함수 안 => a: %d, b: %d\\n", *a, *b);
}

//swap_addr() 함수 호출 전 => a: 10, b : 20
//swap_addr() 함수 안 => a: 20, b: 10
//swap_addr() 함수 호출 후 => a: 20, b : 10
  • 함수를 호출하면서 전달값으로 변수의 주소를 넘기면 호출한 함수 안에서 변수의 주소를 참조해 값을 사용하거나 수정할 수 있음 >> 참조에 의한 호출이라고 부름.