1. 포인터
포인터는 메모리의 주소를 저장하는 변수이다. 즉, 다른 변수가 메모리 상에 위치한 곳을 가리키는 것이다.
1.1 포인터 선언 ( * )
포인터는 포인터가 가리킬 변수의 자료형을 명시하고 이름 앞에 * 기호를 붙여서 포인터임을 나타낸다.
자료형 *포인터변수명;
// 예시
int* pi; // int형 포인터 pi가 선언됨
1.2 주소 연산자 ( & )
변수 앞에 & 기호를 붙이면 해당 변수의 메모리 주소를 얻을 수 있고, 메모리 주소는 포인터 변수에 저장된다.
int i = 10;
int *pi= &i; // i의 메모리 주소를 pi에 저장
1.3 간접 참조 연산자 ( * )
포인터 앞에 * 기호를 붙이면 포인터가 가리키는 메모리 주소의 값을 접근할 수 있다.
int i = 10;
int* pi = &i;
printf("%d",*pi); // 10이 출력
2. 포인터 타입
포인터가 가리키는 변수의 타입에 의해서 결정된다.
1.4.1 정수형 포인터 (int *)
정수형 변수의 주소를 저장한다.
1.4.2 실수형 포인터 (float *, double *)
float 또는 double 타입의 변수 주소를 저장한다.
1.4.3 문자 포인터 (char *)
문자형 변수 또는 문자열의 첫 번째 문자의 주소를 저장한다.
3. NULL 포인터
NULL 포인터는 어떠한 것도 가리키지 않고 있다는 것을 알려준다.
NULL 포인터를 쓰면 유효한 주소로 할당 전까지 포인터가 임의의 주소를 가리키는 것을 방지할 수 있다.
int *ptr = NULL;
4. 포인터 산술 연산
포인터 산술 연산은 포인터의 주소 값을 기준으로 수행된다.
포인터 산술 연산에는 네 가지 종류가 존재한다. (덧셈, 뺄셈, 증가, 감소)
4.1 포인터와 정수의 덧셈 , 뺄셈
포인터에 정수를 더하면, 포인터가 가리키는 타입의 크기를 고려하여 주소 값이 조정된다.
ex) int형 포인터에 1을 더하면 int형 크기인 4바이트 만큼 덧셈이 된다.
#include <stdio.h>
int main()
{
int i = 10;
int *pi = &i;
printf("%p\\n", pi); // 000000000061FE14
printf("%p\\n", pi+1); // 000000000061FE18 <-- 4 바이트 증가
printf("%p\\n", pi-2); // 000000000061FE0C <-- 8 바이트 감소
return 0;
}
4.2 포인터와 포인터의 뺄셈
같은 타입의 두 포인터 간의 뺄셈을 수행하면, 그 결과는 두 포인터 사이에 있는 요소 수가 된다.
int *p1 = &arr[4];
int *p2 = &arr[1];
int n = p1 - p2; // n은 3이 됨
4.3 증가, 감소 연산자
증가 연산자(++)와 감소 연산자(—)를 사용하여 포인터 연산을 수행할 수 있다.
#include <stdio.h>
int main()
{
int i = 10;
int *pi = &i;
printf("%p\\n", pi); // 000000000061FE14
printf("%p\\n", ++pi); // 000000000061FE18
printf("%p\\n", --pi); // 000000000061FE14
return 0;
}
5. 포인터와 배열
5.1 배열의 이름과 포인터
배열의 이름은 배열의 첫 번째 원소의 주소이다.
즉, 배열 이름 자체가 포인터처럼 작동하여 배열의 첫 번째 원소를 가리킨다.
int arr[5] = {10, 20, 30, 40, 50};
int *p = arr; // arr은 arr[0]의 주소를 나타냄
5.2 배열 요소 접근
포인터 산술 연산을 사용해서 포인터 배열의 요소에 접근할 수 있다.
printf("%d\\n", *(p + 2)); // 30 출력
printf("%d\\n", p[2]); // 위와 동일하게 30 출력
5.3 포인터를 사용하여 배열의 함수 전달
함수에 배열을 전달할 때는 배열의 이름만 전달하면 됩니다.
즉, 배열의 첫 번째 원소를 가리키는 포인터를 전달
void printArray(int *arr, int size) {
for(int i = 0; i < size; i++) {
printf("%d ", arr[i]); // 혹은 printf("%d ", *(arr + i));
}
printf("\\n");
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
printArray(arr, 5); // 배열의 이름을 포인터로 전달
return 0;
}
6. 포인터와 함수
6.1 함수 인자로서의 포인터
함수에 변수의 주소를 전달하여 함수 내에서 원본 데이터를 수정할 수 있다. ( Call by Reference 사용 )
void updateValue(int *value) {
*value = 10; // 포인터를 통해 전달된 변수의 값을 변경
}
int main() {
int a = 5;
updateValue(&a); // 'a'의 주소를 전달
printf("%d", a); // 출력: 10
return 0;
}
6.2 포인터를 반환하는 함수
함수에서 포인터를 반환하는 것은 동적으로 할당된 메모리 주소를 반환하거나 함수 내부에서 정의된 정적 변수의 주소를 반환하는데 사용한다.
int* createArray(int size) {
int* arr = (int*)malloc(size * sizeof(int)); // 동적 메모리 할당
// 배열 초기화 또는 다른 작업
return arr; // 할당된 메모리의 주소 반환
}
int main() {
int* myArray = createArray(5); // 함수에서 반환된 포인터를 받음
// 배열 사용
free(myArray); // 동적으로 할당된 메모리 해제
return 0;
}
6.3 포인터를 반환하는 함수
함수에서 포인터를 반환하는 것은 동적 메모리 할당을 활용하거나, 배열과 같은 데이터 구조에 접근할 때 유용
int* createArray(int size) {
int* arr = (int*)malloc(size * sizeof(int)); // 동적 메모리 할당
// 배열 초기화 또는 다른 작업
return arr; // 할당된 메모리의 주소 반환
}
int main() {
int* myArray = createArray(5); // 함수에서 반환된 포인터를 받음
// 배열 사용
free(myArray); // 동적으로 할당된 메모리 해제
return 0;
}
7. 포인터와 문자열
7.1 문자열과 포인터
문자열 상수 “Hello”를 str에 저장하면 문자열 상수는 변경할 수 없는 메모리 영역에 저장(텍스트 세그먼트)되기 때문에 문자열 수정이 불가능하다.
단, 다른 문자열 상수를 가리키게 하는 것은 가능하다.
char *str = "Hello"; // str 포인터에 H의 메모리 주소를저장