주소를 가지고 있는 변수
일반 변수앞에다 & 를 붙이면 주소가 리턴됨 (reference operator)
int* pointerA = &varB; // 포인터 변수 A에 변수 B의 주소를 할당하고 싶다면
// 변수 B의 주소값을 주기 위해 & 를 붙일것
int varA = *pointerB; // 포인터 변수 B가 가리키는 변수에 저장된 값을 리턴
예시
malloc() 으로 동적으로 할당한 4바이트 짜리 정수형 메모리 주소를 포인터에 할당함
서식문자 %p : 포인터의 주소값 출력
cf) malloc() 의 값들은 초기화가 안되서, 우리가 별도의 값을 할당하지 않는 이상 쓰레기값이 저장되어있다.
힙 메모리 공간을 제한없이 사용 가능하다
동적으로 할당한 메모리 공간에 대해 언제든지 사이즈를 재조정(resize) 가능하다!
함수 호출시 파라미터로 포인터를 넘겨주면, 같은 메모리 공간을 공유할 수 있다 ( => 함수끼리 동일한 메모리 공간을 공유하는 방법은 포인터를 사용해야 한다!)
(함수안의 일반 로컬변수는 함수가 리턴(종료) 되면 stack 에 쌓였던 변수가 사라지지만, 포인터 활용시 malloc() 으로 동적인 메모리 공간을 생성하고 heap 에 존재하게 된 메모리의 값을 변경가능하다!. heap 에 있는 메모리 공간은 stack 에 있는 메모리 공간과 달리 함수 호출이 종료되어도 사라지지도 않음)
int arr[4];
int *pointer = &arr[1];
int *pointer = (int *)malloc(sizeof(int) * 2);
pointer[0] = 1;
pointer[1] = 2;
printf("%d \n", pointer[1]);
int *pointer = (int *)malloc(sizeof(int) *3);
pointer[0] = 0;
pointer[1] = 1;
pointer[2] = 2;
pointer = pointer + 2; // 현재 포인터가 가리키는 동적 메모리공간의 시작주소에서
// (int형 4바이트) * 2 = 8바이트만큼 이동해서 그 주소를 포인터가 새롭게 가기키게 함
printf("%d \n", *pointer);
int (*atpr)[4] : 포인터 배열 => 크기가 4인 int형 배열의 각 원소를 atpr의 각각 가리킴
ptr : 배열 포인터
aptr = &array : 배열 포인터(aptr)에다 배열의 주소(&array) 를 줘도 에러가 발생하지 않는다.
ptr = array : 그냥 포인터(ptr)에다 배열의 시작주소(array) 를 할당
cf) 만일 aptr = array 와 같은 연산이 일어나면 에러가 발생함
=> 배열 포인터(atpr)가 배열 타입의 메모리 공간을 가리켜야 하는데 배열의 시작주소, 즉 int형 타입의 메모리 공간을 가리키게 되니까 타입 에러가 발생!
예제1
예제2
int **dptr = (int **)malloc(sizeof(int *) * 2); // int형 포인터 2개가 생성(dptr[0], dptr[1])
dptr[0][0] = 0; // 2차원 배열 처럼 사용하는 중!
dptr[0][1] = 1;
dptr[0][2] = 2;
dptr[0][3] = 3;
함수의 주소를 저장하는 포인터
함수의 이름의 곧 해당 함수의 주소값이다.
예제
scanf() 에 할당되어야 하는 인자가 주소값이여함. 그래야 해당 주소에 값을 넣어줄 수 있다.
scanf 함수는 인자값이 포인터인지 변수인지 신경쓰지 않고 주소라고 여긴다.
int var = 3;
scanf("%d", var); // var에 저장된 숫자 3을 주소라고 인식하고 동작 하려고 한다. 그럼 당연히 에러발생!
// => scanf("%d", &var); 이게 옳은 표현!
아래처럼 malloc() 에 초기화 과정을 별도로 안해줬는지 값을 참조하려고 하면 각 메모리 공간에 완전 이상한 값이 할당된다!
예시
=> 만일 크키가 64인 char형 배열에 64개 이상의 문자들을 gets() 로 할당시킬 경우, 스택 오버플로우가 발생! (invalid 한 메모리 공간까지 사용하려 하므로)
이중 포인터 A의 각 원소(int형 포인터)들은 타입이 int 가 아닌, int형 포인터이다!
그런데 A의 각 원소들이 가리키고 있는 malloc() 메모리 공간을 보면 sizeof(int) 를 보듯이 타입이 int형 타입이다!
=> 그래서 래는 int형 포인터 <-> int형 간에 타입이 알맞지 않아서 에러가 발생해야 정상인데, 운좋게도 int형 포인터도 4바이트이고 int형도 4바이트이다. 따라서 다행히도 코드가 실행되는데 문제없이는 돌아간다.
but, 일부 시스템(i7 코어)에서는 int형 포인터가 8바이트라서, 에러가 발생한다!
case1) size 포인터가 가리키는 메모리 공간에 저장된 값이 1감소
ex. int val = 3; int* size = &val; 인 경우 변수의 val의 값이 3에서 2가 되는 경우
case2) size 포인터 주소값이 4바이트만큼 감소
ex. size 포인터 변수의 주소값이 10000 이였다면, 9996이 되는 경우
=> 연산자 "--" 가 "*" 보다 우선순위가 높아서, case2 가 실행될 것이다.
이렇게 애매모호한 상황을 방지하기 위해, 괄호 "( )" 를 꼭 활용해서 연산의 우선순위를 잘 조정해주자!
ex) p += 2; // p가 int형 포인터이라면, 주소값이 8바이트만큼 늘어남
위와 같이 함수에서 지역변수 val 을 선언하고 그 주소값을 리턴하면 문제가 발생한다.
함수가 종료시에 스택에 쌍였던 변수 val 이 소멸되는데, 이 소멸되는 변수의 주소값을 리턴하는 행위는 잘못된 행위이다.
=> 해결법 : int val; // val = (int )malloc(sizeof(int) * 1);
이렇게 해놓고 return &val; 을 하면 문제발생x
val가 가리키는 메모리 공간은 스택이 아니라 힙에 저장되어 있어서 소멸되지 않는다!
위와 같이 메모리 공간 할당해놓고 사용하지도 않으면 쓸떄없는 메모리 공간 낭비가 된다.
cf) 최신 컴파일러는 똑똑해서 낭비되는 저런 메모리 공간을 자동으로 삭제시킴