사이먼's 코딩노트
[C언어] 포인터 문제풀이 본문
- 이번엔 포인터와 관련된 문제들을 풀어봅시다.
- 각 문제에는 문제와 조건이 있으니 해당 조건에 맞춰서 문제를 해결해봅시다.
[문제 1]
- 변수 i의 값을 해킹해주세요.
- 조건 1 : i의 값을 직접 바꾸는 것은 안됩니다.
- 조건 2 : `i = 50;` 은 안됩니다.
#include <stdio.h>
// 8바이트
int main(void) {
int i = 30;
int i2 = 30;
int* p = &i;
printf("p의 주소값 : %ld\n", (long)p);
printf("포인터 p의 값 : %d\n", *p);
*p = 50;
printf("i : %d\n", i);
// 출력 => i : 50
return 0;
}
- 변수 i를 직접적인 수정말고 포인터를 이용해서 값을 바꿔야한다.
- 포인터 변수 p를 생성하여 i의 주소값을 넣어준다.
- *p의 의미는 포인터 변수 p의 주소로 이동한다라는 의미이고 주소로 이동해서 50을 넣어준다.
- 50으로 숫자가 바뀌었는지 확인하기 위해선 출력문을 통해 i 또는 *p를 출력해보면 50이 출력된다.
[문제 2]
- 포인터 변수 p를 이용해서 변수 2개의 값을 변경해주세요.
- 조건 : 변수 a, b에 값을 직접 할당하지 마세요.
#include <stdio.h>
int main(void) {
int a = 10;
int b = 20;
int* p;
p = &a;
*p = 100;
p = &b;
*p = 200;
printf("a : %d\n", a);
// 출력 => a : 100
printf("b : %d\n", b);
// 출력 => b : 200
return 0;
}
- 포인터 변수 p는 주소를 저장하는 공간이다.
- p = &a를 통해 포인터 변수 p에 변수 a의 값인 10이 아닌 주소값을 넣어준다.
- *p를 통해 현재 들어있는 a의 주소로 이동하여 해당 값을 10이 아닌 100으로 바꿔 넣어준다.
- 마찬가지로 다시 한번 포인터 변수 p에 b의 주소를 넣고 *p를 통해 b의 주소로 이동하여 20이 아닌 200으로 값을 바꿔 넣어준다.
- 각 변수 a, b를 출력해보면 포인터를 통해 새로 들어간 값 100과 200이 출력된다.
[문제 3]
- char 변수 b를 이용하지 않고 b의 값을 훼손시켜보세요.
- 조건 1 : 포인터 변수를 사용해서 값을 변경해야 한다.
- 조건 2 : 수정가능 지역에서 b라는 변수를 언급하면 안됩니다.
#include <stdio.h>
int main(void) {
char a = 1;
char b = 5;
printf("== 변수의 주소 ==\n");
printf("&a : %ld\n", (long)&a);
printf("&b : %ld\n", (long)&b);
char* p;
p = &a;
*p = 2;
p = &a - 1;
*p = 10;
printf("== 변수의 값 ==\n");
printf("a : %d\n", a);
// 출력 => a : 2
printf("b : %d\n", b);
// 출력 => b : 10
return 0;
}
- 지역변수인 a와 b는 메모리에 저장되게 된다.
- 변수인 a, b의 타입은 char이고, p는 포인터 변수이며 해당 변수의 타입은 char이다.
- *p가 가르키는 변수의 크기는 char 타입이므로 1바이트를 가진다.
- 모든 포인터의 크기는 8바이트이지만, 변수와 포인터변수의 크기 타입은 반드시 맞춰줘야한다.
- 만약 변수 a, b의 타입이 int라면 p도 똑같이 int로 맞춰 선언해줘야한다.
- 포인터 변수 p에는 a의 주소값을 넣어 해당 주소로 이동하고 기존에 들어있는 1이 아닌 2를 넣어준다.
- 조건에서 지역변수 b를 언급하지 않고 b의 값을 바꿔줘야한다고 명시되어 있기 때문에 이번에는 포인터 변수 p에 b의 주소값을 넣지 않는다.
- 포인터 변수 p에 a의 주소값에서 -1을 해준다.
- 변수들은 메모리의 스택이라는 곳에서 밑에서 위로 하나씩 차곡차곡 쌓이기 때문에 변수가 생성된 순서대로 주소값이 부여된다.
- 가장 먼저 선언된 변수의 주소값이 가장 무겁다.(숫자가 크다)
- 따라서 a가 b보다 변수 선언이 먼저 되었고 실제로 두 변수의 주소값을 &a, &b로 출력해보면 주소값의 차이가 1이난다.
- 여기서 주소값의 차이가 1이 나는 것은 해당 변수의 타입이 char 이기 때문이다.
- char의 크기가 1바이트이기 때문에 주소값도 1이 차이 나는 것이다. 이런식으로 short는 2, int는 4 만큼 주소값이 차이가 난다.
- 그렇게 때문에 a의 주소값에서 -1을 하게되면 b의 주소로 이동하는 것이다.
- 만약 변수 a, b가 char가 아닌 int로 선언되었다면 지금 같은 상황에서 -4를 해서 b의 값을 바꿔 출력해보면 해당 주소는 비어서 원하는 값이 출력되지 않을 것이다.
- 그 이유는 해당 변수의 크기가 4바이트인거지 스택에 쌓일때는 차곡쌓이기 때문에 똑같이 -1을 해줘야한다.
[문제 4]
- 다음 p1과 p2의 값을 출력했을 때 결과를 예상해보세요.
#include <stdio.h>
int main(void) {
int* p1 = 4;
char* p2 = 4;
printf("p1 + 1 : %ld\n", (long)(p1+1));
printf("p2 + 1 : %ld\n", (long)(p2+1));
return 0;
}
- 결과적으로 위 코드를 실행시켰을 때 출력되는 값은 8과 5이다.
- 포인터 변수 p1의 타입은 int이고, p2의 타입은 char 이다.
- 포인터 변수는 주소값을 담고 있고 p1, p2의 주소값을 모두 4로 정의했다.
- 출력문에서는 현재 주소값으로 이동해서 해당 주소가 가지고 있는 값이 아닌 순수 주소값을 출력하게 되어있다.
- p1의 주소값은 4였지만 변수 타입이 4바이트인 int이기 때문에 주소값에 +1를 더하게되면 주소값 하나 차이가 나는 4가 더해진다.
- p2의 주소값은 4였지만 변수 타입이 1바이트인 char이기 때문에 주소값에 +1를 더하게되면 주소값 하나 차이가 나는 1이 더해진다.
[문제 5]
- 원본 값 x를 훼손하는 change 함수를 만들어주세요.
#include <stdio.h>
void change(int* num) {
*num = 50;
}
int main(void) {
int x = 20;
printf("change 함수 호출하기 전의 x : %d\n", x);
change(&x);
printf("change 함수 호출한 후의 x : %d\n", x);
// 출력 => change 함수 호출한 후의 x : 50
return 0;
}
- 직접적인 정의를 하지 않고 변수 x의 값을 바꾸기 위해서 포인터를 사용한다.
- change라는 함수는 인자로 x의 값이 아닌 x의 주소값을 받는다.
- change() 함수의 매개변수는 주소값을 받기 때문에 int num이 아닌 int* num으로 포인터 변수를 받아와야한다.
- num이라는 포인터 변수를 change() 함수를 통해 받아오면 num에는 현재 x의 주소값이 들어있다.
- *num을 통해 x의 주소값으로 이동하고 해당 주소에 있는 20이라는 값을 50으로 바꿔 넣어준다.
반응형
'C언어' 카테고리의 다른 글
[C언어] 배열 (2) | 2024.02.08 |
---|---|
[C언어] 다중 포인터 (0) | 2024.02.06 |
[C언어] 포인터 (0) | 2024.02.02 |
[C언어] 함수 문제풀이(2) / 서식지정자와 자료형 (0) | 2024.01.29 |
[C언어] 함수 문제풀이(1) (0) | 2024.01.24 |