## 포인터 Pointer
: "메모리 주소"를 값으로 저장하는 변수 (cf. 일반변수 - 실제 데이터값을 저장)
- 용도: 메모리 직접 접근/조작 , 동적 메모리 할당 , 함수로 변수 값 변경 , 배열/문자열 효율적 처리
- 핵심 연산자: & (앰퍼샌드) - 주소 연산자 / * - 간접참조 연산자(가리키는 주소의 실제데이터값 접근)
- 크기: 1워드의 크기 (8 / 16 / 32 / 64 bit)
## 포인터 선언
int *p1; # 정수 가리키는 포인터
char *p2; # 문자열 가리키는 포인터
double *p3; # 실수 가리키는 포인터
## 포인터 사용 주의사항 (3)
1- 포인터는 초기화하고 사용하는 게 안전.
(어떤 변수 가리킬 지 알 수 없으면 NULL로 초기화)
int *q; #쓰레기값
*q = 10; #실행 에러 발생
>>>
int *q = NULL; ## 권장
2- 포인터의 데이터형 & 가리키는 변수의 데이터형 같아야함.

3- 포인터 안전하게 사용하려면, 사용할 때 null포인터인지 검사하기
if (q != NULL)
*q = 100;
##=====
if (q)
*q = 100;
## 포인터 연산
- 포인터 + N --> 결과값 : ( 포인터가 가리키는 자료형의 크기 x N ) 만큼 증가

## 상수 포인터

## 이중 포인터 (**)
: 주소의 주소 담고있는 포인터 (포인터를 가리키는 포인터)
int n = 10; # n <- 10(상수값)
int* n_p = &n; # n_p <- n의주소
int** n_pp = &n_p; # n_pp <- n_p의주소
printf("%d", n); # 10
printf("%d", *n_p); # 10 (n의 값) : n_p가 가리키는 값
printf("%d", *n_pp); # 0x... (n의 주소) : n_p에 든 값
printf("%d", **n_pp); # 10 (n의 값) :n_pp가 가리키는 주소가 가리키는 값

- 주 용도:
> 1) 포인터를 함수 인자로 전달해서 "원본 포인터" 수정할 때 (Call-by-Reference) **
void allocMemory(int **ptr) {
*ptr = (int *)malloc(sizeof(int));
**ptr = 10;
}
int main(){
int *p = NULL;
allocMemory(&p);
printf("%d\n", *p); # 10
free(p);
}
> 2) 동적 2차원 배열 구현할 때 (가변크기 배열)
int main(){
int rows = 3, cols = 4;
int **arr = (int **)malloc(rows * sizeof(int *)); #행 포인터 배열
for (int i = 0; i < rows; i++){
arr[i] = (int *)malloc(cols * sizeof(int)); #각 행의 열 메모리
}
arr[1][2] = 7;
printf("%d\n", arr[1][2]); #7
for (int i = 0; i < rows; i++)
free(arr[i]);
free(arr);
}
## ======== 메모리 순서대로 할당하는법
int(*arr)[width] = (int(*)[width])malloc(height * width * sizeof(int));
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int data;
scanf("%d", &data);
arr[i][j] = data;
}
}
> (3) 문자열 배열 다룰 때
## 문자열 배열 (char argv)
int main(int argc, char **argv)
**Call-by-Reference
* 일반적으로 함수에 변수 전달 시 복사본 전달됨. >>포인터 전달해야 원래 변수 값 변경 가능.
> 변경대상: 일반변수 값 --> 변수 주소(=단일 포인터) 전달
포인터의 주소 --> 포인터의 주소(=이중 포인터) 전달
** 포인터의 주소 바꾸기 = 해당 포인터의 화살표 방향(목적지) 바꾸기
## 일반변수 변경할 때 :pointer ========
int a = 10;
void change(int* ptr) {
*ptr = 20;
}
change(&a);
## 포인터변수 변경할 때 :double-pointer ========
int* p = &a;
## malloc()
: 프로그램 실행 중(runtime)에 메모리를 직접 빌려오는 함수 (**어원: memory allocation 메모리 할당)
- 용도: 컴파일할 때 크기를 모르는 데이터를 나중에 동적으로 만들 때
#정수 1개 할당 ========
int *p = (int *)malloc(sizeof(int));
#정수 n개 할당 ========
int *arr = malloc(n * sizeof(int));
#2차배열(m*n) _각 행에 malloc 반복 ========
int **mat = malloc(m * sizeof(int*));
#포인터 수정 함수 ========
void alloc(int **p){
*p = malloc(...);
}

## 포인터 문제 풀이
https://www.geeksforgeeks.org/quizzes/pointers-gq/
C Pointer Basics
C Pointer Basics Quiz will help you to test and validate your C Quiz knowledge. It covers a variety of questions, from basic to advanced. The quiz contains 43 questions. You just have to assess all the given options and click on the correct answer.
www.geeksforgeeks.org
(g2g_'C Pointer Basics' #1~5)

'*'의 쓰임 2가지 잘 구분하기
1- 포인터 변수 선언할 때
2- 역참조 할 때
**c = &b;
>> 이중포인터 c = b의주소

mystery() 분석
- 인자: 포인터변수 ptra, ptrb
- 전달받은 주소값: &a, &b
- 함수 내용: ptra = &a, ptrb = &b ----> ptra = &b, ptrb = &a
>> 어차피 ptra, ptrb는 이 함수 내에서만 존재하는 포인터라 걔네 값 바꿔도 원본에 영향 없음
## 만약 함수에서 원본값 바꾸고싶다면 (특정 주소의 값 변경),
: " 이중포인터 " 사용
void swap(int **pp_a, int **pp_b){
int *tmp = *pp_a;
*pp_a = *pp_b;
*pp_b = *tmp;
}
int main(){
int x = 10, y = 20;
int *a = &x;
int *b = &y;
swap(&a, &b);
printf("%d %d\n", *a, *b); #20, 10



** 배열 이름- 그 배열의 첫번째 요소의 주소 포인터 역할
int arr[5] = {10,20,30,40,50}
## arr = &arr[0]
** 2차원배열에서의 포인터
int a[2][3] = { {1,2,3}, {4,5,6} };
## a <- 배열의 첫번째요소 주소값
print("%p\n", a); # &a[0][0]
print("%p\n", a+1); # &a[1][0]
print("%p\n", *(a+1)); # &a[1][0]
print("%p\n", *(*(a+1) + 2)); # a[1][2]
## 왜 a+1와 *(a+1) 값이 같을까? ============
a: int 3개까지 배열을 가리키는 포인터
> int (*)[3]
>> a[0] (int[3]) -> [1][2][3]
>> a[1] (int[3]) -> [4][5][6]
a+1 : &a[1]
*(a+1) : a[1] #포장지 하나만 깐 상태
>> 둘다 두번째 행 전체를 뜻함(그 안의 값은 아직 아님)
>> 본문에서 둘다 %p로 출력하므로, 둘다 그 행의 첫번째 요소 주소가 찍히는 것


** 대부분의 CPU는 리틀엔디안 방식 사용함 (x86, ARM 등)
> 정수 a=300이 메모리에 저장될 때는 낮은 바이트부터 거꾸로 저장됨
[10진수] 300 = [16진수] 0x0000012c
## >> 리틀엔디안으로 메모리 저장 시,
0x100 0x2C
0x101 0x01
0x102 0x00
0x103 0x00
>> 이렇게 4Byte로 저장됨
** char *b = (char *)&a; 의 의미
> a의 주소에 담긴 값을 1바이트 단위로 접근하겠다 (char=1Byte)
int main()
{
int a = 300;
## ex. 메모리 - 0x0000012c 리틀엔디안으로 저장하면(300->16진수값)
## >> [ 2c 01 00 00 ]
char *b = (char *)&a; # b는 a의 '값'을 1바이트씩 접근
*++b = 2;
## >> [ 2c 02 00 00 ] --> (22c->10진수로 바꾸면 556됨)
printf("%d ",a);
return 0;
}

** y = *ptr --> *ptr=x값=0 들어감
'Programming' 카테고리의 다른 글
| [C] 함수 포인터 (개념간단정리) (0) | 2025.10.10 |
|---|---|
| [C] C언어 특성 정리 (4) - 배열,가변인자,전처리명령어 (0) | 2025.10.09 |
| [C] C언어 특성 정리 (1) - 선언,정의,static,extern,enum,union,빌드과정 (0) | 2025.10.08 |