1. 포인터
💡 자료형 *변수명
리마인드
- * : 주소로 가서 값을 가져와라
- & : 주소가 뭔지 불러와라
- *& : 서로 상쇄 (아무것도 없는 거라고 생각)
포인터의 특징
- 기본 설명
void main() { int* p = NULL; int num = 15; p = # printf("포인터 p의 값 : %d \\n", p); // 93929524 printf("int 변수 num의 주소 : %d \\n", &num); // 93929524 printf("%d\\n", num); // 15 printf("%d\\n", *p); // 15 : *p = num의 주소 }
- 변수/클래스/스트럭쳐의 주소값을 저장하는 변수
- 그대로 불러오면 용량이 크므로 링크 따는 것, 포인터로 원본을 변경할 수 있음 (연산 가능)
- 포인터 변수의 크기는 모두 동일하지만, 자료형을 선언하는 이유는 가리킬 주소가 어떤 자료형을 갖는지 알려주기 위함 (가리키는 변수에 맞춰 포인터 변수도 자료형을 맞추면 됨)
- 포인터는 무조건 NULL(0)으로 초기화, 아니면 바로 주소값 넣기
- 연산자의 우선순위 : 참조 연산자(*)가 증감연산자(++, --)보다 순위가 높음
-
void main() { int *p = NULL; int num = 15; p = # printf("포인터 p가 가리키는 값 : %d\\n", *p); // 15 printf("num의 값 : %d\\n\\n", num); // 15 *p += 5; printf("포인터 p가 가리키는 값 : %d\\n", *p); // 20 : *p(num) + 5 printf("num 값 : %d\\n\\n", num); // 20 : 위 값이 num에 들어감 (*p)++; printf("포인터 p가 가리키는 값 : %d\\n", *p); // 21 : *p(num) + 1 printf("num 값 : %d\\n\\n", num); // 21 : 위 값이 num에 들어감 *p++; printf("포인터 p가 가리키는 값 : %d\\n", *p); // -13545343 : 주소를 찾아가지 않고 주소값이 들어있는 변수 p를 증가, 쓰레기값 출력 printf("num 값 : %d\\n", num); // 21 }
-
- 함수에서는 인자를 전달할 때 복사해서 사용하므로 전달해주는 원래 변수는 함수에서 수정 불가(call by value 어쩌구 개념 등장), 이때 포인터로 메모리의 주소를 넘겨주면 변수 값을 바로 수정 가능
-
void pointerPlus(int *num) { *num += 5; } void numPlus(int num) { num += 5; } void main() { int num = 15; printf("num 값 : %d\\n", num); numPlus(num); printf("numPlus 사용 후 : %d\\n", num); // 15 pointerPlus(&num); printf("pointerPlus 사용 후 : %d\\n", num); // 20 }
-
상수 포인터
- 포인터가 가리키는 변수를 상수화 (포인터를 통해 값 변경 불가)
-
void main() { int num = 10; const int* ptr = # }
-
- 포인터를 상수화 (주소값 변경 불가)
-
void main() { int num = 10; int *const ptr = # }
-
- 둘 다 상수화
-
void main() { int num = 10; const int *const ptr = # }
-
2. 포인터와 함수
Call by Value
- C언어에서 지원하는 방식
- 함수에서 값을 복사해서 전달하는 방식, 인자로 전달되는 변수를 함수의 매개변수에 복사 (인자로 전달한 변수와는 별개의 변수가 되기 때문에 원본 값이 바뀌지 않음, Swap 코드 참고)
- Swap 코드 예시
-
void swap(int a, int b) { int temp; temp = a; a = b; b = temp; } void main() { int a, b; a = 10; b = 20; printf("swap 전 : %d %d\\n", a, b); // 10 20 swap(a, b); printf("swap 후 : %d %d\\n", a, b); // 10 20 }
-
Call by Reference
- C언어에서는 공식적으로 지원하지 않으므로, Call by Address(주소값을 복사해서 넘겨주기)를 이용해야 함
- 함수에서 값을 전달하는 대신 주소값을 전달하는 방식
- Swap 코드 예시
-
void swap(**int *a, int *b**) { int temp; **temp = *a; *a = *b; *b = temp;** } void main() { int a, b; a = 10; b = 20; printf("swap 전 : %d %d\\n", a, b); // 10 20 **swap(&a, &b)**; printf("swap 후 : %d %d\\n", a, b); // 20 10 }
-
3. 포인터와 배열
- 다시 한번 리마인드
- * : 주소로 가서 값을 가져와라
- & : 주소가 뭔지 불러와라
- *& : 서로 상쇄 (아무것도 없는 거라고 생각)
특징
- 배열의 이름은 주소값 (포인터 변수의 값)
- 포인터 주소에 증가 연산을 하는 경우, 자료형의 크기 x N만큼 증가함
- *(arr+i) == arr[i]
- type형 포인터를 대상으로 n 크기만큼 값을 변경시키면 n x sizeof(type) 크기만큼 값이 증가/감소한다. (int 형일 경우 4씩, double 형일 경우 8...) 그래서 위와 같이 배열일 경우 *(arr+i) == arr[i] 가 성립
- 특징 총정리
void main()
{
int arr[5] = { 10, 20, 30, 40, 50 }; // 배열 (이름, 주소) : arr (10, 00000024)
int* arrPt = arr; // 포인터 : 00000024
// 배열의 [이름]은 [배열의 첫번째 값]과 동일
printf("%d\\n", *arrPt); // 10
printf("%d\\n", arr[0]); // 10
// 배열[i] = 포인터[i]
printf("%d\\n", arrPt[0]); // 10
printf("%d\\n", arrPt[1]); // 20
// 포인터(배열주소)에 숫자를 더하면 : (자료형의 크기 x n)
printf("%d\\n", arrPt); // 00000024
printf("%d\\n", arrPt + 1); // 00000028
// 배열에 숫자를 더하면 : 배열 주소에 숫자를 더한 것과 동일
printf("%d\\n", arr); // 00000024
printf("%d\\n", arr + 1); // 00000028
// 포인터(배열주소)에 숫자 더한 후 값을 가져오기
printf("%d\\n", *(arr + 1)); // 20 = arr[1]
printf("%d\\n", *(arr + 2)); // 30 = arr[2]
// 배열 각 인덱스의 주소값
printf("%d\\n", &(arr[0])); // 00000024
printf("%d\\n", &(arr[1])); // 00000028
// 따라서 : ***(arr+i) == arr[i]**
}
- 함수 인자로 배열 전달할 때 배열의 크기를 sizeof로 전달
-
**void 함수(int *arr, int len)** { for (int i=0; i < len; i++) printf("%d\\n", arr[i]); } void main() { int arr[10] = {1, 2, 3, 4, 5}; **함수(arr, sizeof(arr) / sizeof(int));** }
-
- 연습문제 : 포인터로 버블 정렬 함수 만들기
-
#include <stdio.h> void bubbleSort(int* arr, int len) { int temp; for (int i = 0; i < len-1; i++) { for (int j = 0; j < len-1; j++) { if (*(arr + j) > *(arr + j + 1)) { temp = *(arr + j); *(arr + j) = *(arr + j + 1); *(arr + j + 1) = temp; } } } } int main() { int arr[10]; for (int i = 0; i < 10; i++) { scanf("%d", &arr[i]); } bubbleSort(arr, sizeof(arr) / sizeof(int)); for (int i = 0; i < 10; i++) { printf("%d ", arr[i]); } return 0; } // 10 5 8 2 9 1 4 6 11 15
-
4. 이중 포인터(더블 포인터)
💡 포인터 변수를 가리키는 또다른 포인터 변수
- 또 다시 한번 리마인드
- * : 주소로 가서 값을 가져와라
- & : 주소가 뭔지 불러와라
- *& : 서로 상쇄 (아무것도 없는 거라고 생각)
이중 포인터 선언과 사용
#include <stdio.h>
void main()
{
int num = 10;
int* ptr = #
int** dptr = &ptr;
printf("%d\\n", *dptr); // ptr의 주소
printf("%d\\n", *(*dptr)); // ptr이 가리키는 값 (num), = **dptr
}
#include <stdio.h>
int main()
{
int num = 10;
int* ptr = #
int** dptr = &ptr;
int* ptr2;
printf("%d %d\\n", num, &num); // 10, 10000024
printf("%d %d\\n", ptr, *ptr); // 10000024, 10 : num의 주소값, ptr(num)의 값
printf("%d %d %d\\n", dptr, *dptr, **dptr); // 10000012 10000024 10 : dptr의 주소값, prt의 주소값, ptr(num)의 값
ptr2 = *dptr; // ptr2에 ptr에 저장된 값을 넣음 (num의 주소)
*ptr = 20; // ptr(num)에 20을 넣음
printf("%d %d\\n", ptr2, *ptr2); // 10000024 20 : ptr의 주소값, ptr2(num)의 값
printf("%d %d\\n", num, **dptr); // 20 20 : num의 값, ptr(num)의 값
return 0;
}
포인터 변수 대상의 Call by Reference
- 함수를 이용해서 싱글 포인터 변수 값을 변경하는 경우, 같은 싱글 포인터 변수를 사용하면 값 변경하지 못함
- (ptr1, ptr2 자체의 주소가 넘어가는 게 아니라, 저장된 값(num의 주소)과 같은 주소값을 가진 변수 p1, p2가 새로 생겨나기 때문)
#include <stdio.h> void swapPtr(int* p1, int* p2) { int* tmp = p1; p1 = p2; p2 = tmp; } void main() { int num1 = 10, num2 = 20; int* ptr1, * ptr2; ptr1 = &num1, ptr2 = &num2; printf("*ptr1, *ptr2 : %d %d\\n", *ptr1, *ptr2); // 10 20 swapPtr(ptr1, ptr2); printf("*ptr1, *ptr2 : %d %d\\n", *ptr1, *ptr2); // 10 20 }
- 호출되는 함수의 매개변수를 더블 포인터 변수로 바꾸고, 인자로 싱글 포인터 자체의 주소값을 넘겨야 값이 제대로 변환됨
-
#include <stdio.h> void swapPtr(int**p1, int**p2) // 더블 포인터 변수 선언 { int* tmp = *p1; *p1 = *p2; *p2 = tmp; } void main() { int num1 = 10, num2 = 20; int* ptr1, * ptr2; ptr1 = &num1, ptr2 = &num2; printf("*ptr1, *ptr2 : %d %d\\n", *ptr1, *ptr2); // 10 20 swapPtr(&ptr1, &ptr2); // 싱글 포인트 변수의 주소값을 함수의 인자로 사용 printf("*ptr1, *ptr2 : %d %d\\n", *ptr1, *ptr2); // 20 10 }
-
'스터디 노트 > C언어 기초' 카테고리의 다른 글
C언어 기초 > 10장 동적 메모리 할당 (0) | 2021.12.07 |
---|---|
C언어 기초 > 09장 구조체 (0) | 2021.12.06 |
C언어 기초 > 07장 배열과 문자열 (0) | 2021.12.04 |
C언어 기초 > 06장 함수 (0) | 2021.12.03 |
C언어 기초 > 05장 조건문 (0) | 2021.12.02 |