Search

포인터

포인터/주소값

iNum이라는 변수의 주호가 0x1000, int의 size = 4byte라고 가정
int iNum=10;
코드 실행시 컴퓨터 내부에서는 iNum이라는 변수값을 저장하기 위해 변수의 type을 확인 → int
int는 4byte이기 때문에 그 크기만큼의 공간을 메모리상에 할당

메모리

메모리는 각 바이트마다 주소를 가짐
메모리 주소는 1바이트씩 증가한다
10이라는 data를 찾기 위해서는 10x1000주소로 가야함
주소값으로 데이터에 접근할 수 있게 하는 수단 ⇒ 포인터
포인터 변수 자체에는 주소값이 저장됨

포인터연산자 * , 주소 연산자 &

포인터변수 : 주소값 저장
포인터 표시 *, 주소값 표시 &
주소연산자 &는 scanf("%d", &iNum); 과 같이 사용
⇒ iNum의 주소에 접근헤 입력한 데이터를 넣는다
예시)
int* pNum; int iNum; pNum=&iNum;
C
복사
다양한활용
포인터는 주소값을 저장한다는 특성이 있기 때문에 단독으로는 잘 사용되지 않는다.
printf("%x", &iNum); // 변수의 주소값 16진수 표기 int *pNum1, *pNum2, *pNum3; // 3개의 포인터 int* pNum1, pNum2, pNum3;// pNum1만 포인터, 뒤의 두개는 int형 int* pArr[3]; // 포인터배열 - 포인터가 원소인 배열 int iArr[3]={}; int* p=iArrl // 배열 포인터 = 배열을 가리키는 포인터
C
복사
주의! int* pNum=&iNum; // 포인터 pNum에 iNum의 주소값 저장 pNum=100; // 주소값을 임의로 주소값 100으로 바꿔버리면 error 발생 *pNum=100; //주소 값이 가리키는 데이터의 값을 100으로 설정 포인터 연산자는 선언과 동시에 초기화가 필수 ⇒NULL연산자 이용 ⇒ int *p = NULL; 왜? 초기화 없이 함부로 사용하다보면 접근하면 안되는 메모리 영역에 접근하게 될 수 있기 때문이다.
<예시>
#include <stdio.h> int main() { int *p; // 포인터 변수 선언 int a; // int형 변수 선언 p = &a; // 포인터변수 p 는 a의 주소값을 저장 a = 10; printf("%d\n", a); printf("%d\n", &a); printf("%d\n", p); printf("%d\n", *p); return 0; }
C
복사
#include <stdio.h> int main() { int *pNum1; // 포인터 변수 선언 pNum1 = NULL; // 포인터값 초기화 용도 printf("%u\n", pNum1);// 0이 출력된다 return 0; }
C
복사

포인터의 유연성

포인터는 변수의 주소값을 저장하기 때문에 포인터 하나로 여러 변수를 관리할 수 있다.
int a, b, c; int *p; p = &a; p = &b; p = &c; // 포인팅을 삭제하거나 그런 과정 없이 다른 주소를 포인팅하도록 변경이 가능
C
복사
#include <stdio.h> int main() { int* p; // 포인터 변수 선언 int iNum1 = 10; int iNum2 = 20; int iNum3 = 30; p = &iNum1; printf("%d\n", *p); p = &iNum2; printf("%d\n", *p); p = &iNum3; printf("%d\n", *p); return 0; }
C
복사

이중포인터

말그대로 포인터를 이중으로 사용한 것
즉, 이중포인터는 포인터의 주소값을 가지는 변수가 된다
numPtr2는 이중포인터
이중포인터 선언 int **p;
이중포인터 역시 단독으로 사용되는 경우는 없다
동적할당에서 많이 사용된다.
2차원 배열의 동적할당 예
#include <stdio.h> int main() { int** p; // 이중포인터 변수 선언 int* tp; // 포인터 변수 선언 int v = 10; p = &tp; tp = &v; printf("%d\n", **p); printf("%d\n", *tp); printf("%d\n", v); return 0; }
C
복사
모두 10이라는 결과가 나왔음
왜? **p는 *tp와 같아지기 때문에 v값을 출력하게된다
#include <stdio.h> int main() { int** p; int* tp; int v = 10; p = &tp; tp = &v; // v의 주소값이자 tp의 데이터*p printf("v: %d\n", &v); printf("tp: %d\n", tp); printf("*p: %d\n", *p); printf("&tp: %d\n", &tp); printf("p: %d\n", p); return 0; }
C
복사
v의 주소값을 tp가 가지고 있고 *p는 tp가 가리키는 곳의 주소를 갖게되어 v의 주소값을 갖음
p는 tp의 주소값이므로 p와 &tp의 값은 같음

배열과 포인터의 관계

배열과 포인터는 깊은 관계를 갖는다
배열의 메모리 공간 할당 방식때문에 포인터를 이용해 접근이 가능하다

1차원 배열과 포인터

왼쪽처럼 변수가 독립적으로 메모리를 할당받은 경우
포인터변수p에 num1변수에 대한 주소 값이 저장된다면, num2, num3에 접근할 방법이 없다
오른쪽처럼 연속적으로 메모리를 할당받으면, 첫번째 주소만 안다면 다음 데이터에도 쉽게 접근이 가능하다
(예)
int iScore[10] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
첫번째 원소의 주소값은 &iScore[0]으로 표기
배열 iScore에서 변수이름 iScore자체가 첫 번째 원소 주소값
주소 값 이용해 저장된 데이터에 접근할 때 *(포인터) 사용
iScore == *(iScore+0) == iScore[0]
*(iScore+i) == iScore[i]
#include <stdio.h> int main() { int iArr[3] = { 0,1,2 }; printf("%d\n", *iArr);// 0 printf("%d\n", iArr[0]);// 0 printf("%d\n", *(iArr+1));// 1 printf("%d\n", iArr[2]);// 2 return 0; }
C
복사
#include <stdio.h> int main() { int iArr[3] = { 0,1,2 }; printf("%d\n", iArr); printf("%d\n", &iArr[0]); printf("%d\n", (iArr+1)); printf("%d\n", &iArr[2]); return 0; }
C
복사
int형이라서 4byte씩 차이가 남
iArr+1이라는 의미가 정말 숫자 1을 더한다는 의미가 아니다(주소값이 한 바이트 증가한다는 의미가 아니다)
데이터 크기만큼(자료형크기만큼)증가한다는 의미이다.
#include <stdio.h> int main() { int iArr[3] = { 0,1,2 }; int* p; p = iArr; for (int i = 0; i < 3; i++) { printf("%d\n", p[i]); } return 0; }
C
복사
Q. p는 포인터 변수이므로 p=iArr은 iArr첫번째원소의 주소값을 p에 넣는것인데, 왜 *p[i]가 아닌 p[i]가 배열의 원소값을 출력하게 되는지 궁금합니다 (교안21p)

2차원 배열과 포인터

2차원 배열 역시 실제 메모리 공간에서는 결국 연속적인 메모리 공간으로 할당된다
배열을 참조하기 위한 배열포인터
int (*p)[2]; int iArr[2][2] = { {5,8}, {11,20} }; p = iArr;
C
복사
이렇게 하면
p[0][0] == *(*iArr+0) == *(p[0]+0) == iArr[0][0]
<예시>
#include <stdio.h> int main() { int(*p)[2];// 배열포인터 int iArr[2][2] = { {5,8},{11,20} }; p = iArr; printf("%d\n", *(*(p + 1) + 1));// 안쪽 괄호는 행, 바깥쪽 괄호는 열을 선택. 결국 iArr[1][1] printf("%d\n", *(p[0] + 1));// p[0]행의 1번째 원소 printf("%d\n", p[0][1]); // 일반적인 배열처럼 사용 가능 return 0; }
C
복사
#include <stdio.h> int main() { int arr2d[2][3] = { {1,2,3},{4,5,6} }; for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { printf("%2d", arr2d[i][j]); } printf("\n"); } **arr2d += 10; // arr2d[0][0]+10 *(*(arr2d)+1) *= 2; // arr2d[0][1]*2 *(*(arr2d + 1)) *= 3; // arr2d[0][1]*3 for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { printf("%2d", arr2d[i][j]); } printf("\n"); } return 0; }
C
복사