&, * : 포인터 연산자
변수의 주소 값을 반환하는 & 연산자
& : 피연산자의 주소 값을 반환하는 연산자
#include <stdio.h>
int main(void)
{
int num = 7;
int* pnum = # // num의 주소 값을 반환해서 포인터 변수 pnum을 초기화
}
& 연산자의 피연산자는 변수(상수 X)
변수의 자료형에 맞지 않는 포인터 변수의 선언은 문제가 될 수 있다.
#include <stdio.h>
int main(void)
{
int num1 = 7;
double* pnum1 = &num1; // 일치하지 않음
double num2 = 5;
int* pnum2 = &num2; // 일치하지 않음
}
컴파일 에러는 발생하지 않지만 포인터 관련 * 연산 시 문제가 발생한다.
포인터가 가리키는 메모리를 참조하는 * 연산자
* 연산자는 포인터가 가리키는 메모리 공간에 접근할 때 사용하는 연산자
#include <stdio.h>
int main(void)
{
int num1 = 7;
int* pnum1 = &num1; // 포인터 변수 pnum1이 변수 num을 가리키게 하는 문장
printf("%d\n", *pnum1);
*pnum1 = 20; // pnum1이 가리키는 변수에 20을 저장하라
printf("%d\n", *pnum1); // pnum1이 가리키는 변수를 부호 있는 정수로 출력
}
포인터 변수 pnum1은 변수 num을 가리키고 있다.
따라서 *pnum1이 의미하는 바는 다음과 같다.
"포인터 변수 pnum1이 가리키는 메모리 공간인 변수 num에 접근을 해서..."
다음
*pnum1 = 20; => "포인터 변수 pnum1이 가리키는 메모리 공간인 변수 num에 정수 20을 저장"
*printf("%d\n", *pnum); => "포인터 변수 pnum1이 가리키는 메모리 공간인 변수 num에 저장된 값을 출력"
예제
#include <stdio.h>
int main(void)
{
int num1 = 13;
int num2 = 150;
int* pnum;
pnum = &num1;
(*pnum) += 100; // num1+=30과 동일
pnum = &num2;
(*pnum) -= 200; // num2-=30과 동일
printf("num1 : %d, num2 : %d\n", num1, num2);
return 0;
}
포인터 변수 pnum이 가리키는 대상이 num1에서 num2로 한차례 변경
다양한 '포인터 형'이 존재하는 이유
- 포인터의 형은 메모리 공간을 참조하는 기준이 됨(int형 포인터 -> 4바이트, double형 포인터 -> 8바이트)
- 포인터 형을 정의한 이유 : * 연산자를 통한 메모리 공간의 접근 기준을 마련하기 위함
아래 예시로 무엇이 문제인지 살펴봄
#include <stdio.h>
int main(void)
{
double num = 3.14;
int* pnum = # // 형의 불일치
printf("%d\n", *pnum); // 예측 불가능한 의미 없는 출력
return 0;
}
- 경고 메세지는 출력되지만, 컴파일 에러가 발생하지 않는다.
- C언어가 메모리 접근에 대한 유연성을 최대한 보장하기 때문에 -> 메모리 접근에 신중을 기해야 함
- int형 포인터 변수 pnum은 double형 변수 num을 가리키게 됨
- 메모리 공간에 저장된 값을 얻기 위해서 *하면 -> "4바이트로 읽어 들여서 이를 정수로 해석"
- 의미 없는 일임
정리
포인터의 형이 존재하는 이유는 포인터 기반의 메모리 접근기준을 마련하기 위함.
포인터의 형이 존재하지 않는다면 * 연산을 통한 메모리 접근을 불가능하다.
잘못된 포인터의 사용과 널 포인터
포인터 변수 : 메모리 주소 값 저장
포인터 변수로 메모리 공간에 접근도 가능하기 때문에 포인터와 관련해서는 상당히 주의를 해야 함
1.
#include <stdio.h>
int main(void)
{
int* ptr;
*ptr = 200;
}
포인터 변수를 선언만 하고 초기화하지 않으면, 포인터 변수는 쓰레기 값으로 초기화 → 어디를 가르킬지 모름
이러한 상태에서 * 연산을 통해 값을 저장하는 것은 치명적인 결과로 이어짐
만약 ptr이 가리키는 메모리 공간이 매우 중요한 위치면, 시스템 전체에 심각한 문제를 일으킬 수도 있다.
2020-12-07 이와 관련해서 visual studio 2019에서 확인 결과 에러를 통해 문제를 방지해줌
2.
#include <stdio.h>
int main(void)
{
int* ptr = 30;
*ptr = 200;
}
30번지가 어딘 줄 알고 포인터 변수로 초기화 하는가? → 쓰레기 값으로 포인터 변수를 초기화한 것과 다르지 않다.
"그렇다면 포인터 변수는 어떤 값으로 초기화?"
포인터 변수를 우선 선언만 해놓고, 이후에 유효한 주소 값을 채워 넣을 생각이면 다음과 같이 초기화
#include <stdio.h>
int main(void)
{
int* ptr1 = 0;
int* ptr2 = NULL; // NULL은 사실상 0을 의미함
}
ptr1을 초기화하는 값 0을 가리켜 '널 포인터'
0번지를 의미하는 것이 아님.
"아무데도 가리키지 않는다!"는 것을 의미
참고 : [윤성우 열혈 C 프로그래밍] - 대부분의 내용 및 코드는 이 책에서 개인 공부 정리 목적으로 참고하였습니다.
'Language&Framework&Etc > C' 카테고리의 다른 글
포인터와 배열! 함께 이해하기(13-2) 포인터 연산 (0) | 2020.12.08 |
---|---|
포인터와 배열! 함께 이해하기(13-1) 포인터와 배열의 관계 (0) | 2020.12.07 |
포인터의 이해(12-1) 포인터란 무엇인가? (0) | 2020.12.07 |
6일차 - 기본제어문 (0) | 2017.05.29 |
5일차 (0) | 2017.05.20 |