프로그래밍/C

[C언어] 10. 포인터 (포인터의 개념, 포인터와 배열, 포인터와 함수(Call by Reference))

록스타★ 2024. 10. 23. 11:03
반응형

1. 포인터의 개념 및 정의

- 포인터(pointer)는 변수의 메모리 주소를 저장하는 변수

- C언어에서 메모리와의 직접적인 상호작용을 가능하게 해주는 중요한 기능

- 일반적인 변수는 값을 저장하지만, 포인터는 그 변수의 위치(주소)를 저장하는 변수

 

포인터의 필요성

- 함수 호출 시, 대용량 데이터를 복사하지 않고 메모리 주소를 통해 효율적으로 처리

- 동적 메모리 할당 가능

- 배열과 문자열을 효율적으로 처리

- 포인터를 통해 더 복잡한 데이터 구조(ex: 링크드 리스트, 트리) 가능

 

포인터 선언 방법

- 여기서 int *ptr;는 ptr이 정수형(int) 데이터를 가리키는 포인터

- * 기호는 해당 변수가 포인터임을 나타냄

int *ptr;

 

포인터 변수 기본 예제

int a = 10;
int *p = &a;  // a의 메모리 주소를 포인터 p에 저장

printf("a의 값: %d\n", a);
printf("p가 가리키는 값: %d\n", *p);
printf("a의 주소: %p\n", p);

 

출력


a의 : 10
p가 가리키는 값: 10
a의 주소: 0x7ffeeb7c8abc (주소는 실행할 때마다 다름)

 

 

 

2. 포인터와 배열

배열과 포인터의 관계

- 배열의 이름 자체가 첫 번째 메모리 주소를 가리키는 포인터와 동일한 역할

- 이 코드에서 ptr은 배열의 첫 번째 요소인 arr[0]의 주소를 가리킴

int arr[3] = {1, 2, 3};
int *ptr = arr;

 

배열의 요소 접근

- 여기서 ptr + 1은 배열의 두 번째 요소를 가리킴

printf("%d\n", *(ptr + 1));  // arr[1]에 해당하는 값 출력

 

 

배열과 포인터 차이

- 배열은 크기가 고정되어 있지만, 포인터는 메모리 주소를 변경 가능

- 배열 변수 자체는 상수 포인터와 유사하여 다른 주소를 가리킬 수 없지만, 포인터 변수는 주소를 자유롭게 변경

 

2차원 배열과 포인터

- 여기서 ptr + 1은 두 번째 행을 가리키고 +2는 두 번째 행의 세 번째 요소를 가리킴

int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
int (*ptr)[3] = arr;  // 각 행을 가리키는 포인터

printf("%d\n", *(*(ptr + 1) + 2));  // arr[1][2]에 해당하는 값 출력

 

 

 

3. 포인터와 함수(Call by Reference)

Call by Value와 Call by Reference

- 기본적으로 C언어의 함수는 인수를 복사하여 전달하는 "Call by Value" 사용

- 포인터를 사용하면 "Call by Reference"방식으로 인수의 메모리 주소 전달

 

Call by Reference의 장점

- 함수를 통해 원본 변수의 값을 직접 수정

- 큰 구조체나 배열을 복사하지 않고 효율적으로 다를 수 있음

 

Call by Reference 예제 

- swap 함수는 포인터를 통해 a와 b의 값을 교환

- 포인터를 사용하지 않으면 Call by Value로인해 함수 내부에서만 값이 바뀌고, 원본 값은 수정되지 않음 

#include <stdio.h>

void swap(int *x, int *y) {
    int temp = *x;
    *x = *y;
    *y = temp;
}

int main() {
    int a = 5, b = 10;
    swap(&a, &b);  // a와 b의 주소를 전달

    printf("a: %d, b: %d\n", a, b);
    return 0;
}

 

출력

a: 10, b: 5

 

 

동적 메모리 할당과 포인터

- C언어에서 malloc, calloc, realloc, free 함수들을 사용하여 동적으로 메모리 할당 가능

- 배열의 동적 할당, 값 입력 및 출력, 메모리 해제까지 모두 동작

#include <stdio.h>
#include <stdlib.h>

int main() {
    // 정수형 5개 크기의 배열 동적 할당
    int *arr = malloc(5 * sizeof(int));

    // 메모리 할당 확인
    if (arr == NULL) {
        printf("메모리 할당 실패\n");
        return 1;
    }

    // 배열 초기화
    for (int i = 0; i < 5; i++) {
        arr[i] = i + 1;  // 배열에 값 대입
    }

    // 배열 출력
    printf("동적 할당된 배열의 값: ");
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    // 할당한 메모리 해제
    free(arr);

    return 0;
}

 

출력

동적 할당된 배열의 값: 1 2 3 4 5

 

 

 

결론

포인터는 C 언어에서 엄청 유용한데, 메모리 관리의 주의가 필요!!!

반응형