티스토리 뷰

카테고리 없음

[C언어] 포인터

쳉링통망통 2024. 4. 30. 16:30

이번 포스트에서는 C언어의 핵심 기능 중 하나인 포인터에 대해 완전 구체적으로 알아보는 시간을 가지려 합니다. 포인터를 정확히 이해하고 사용하는 것은 C언어에서 효율적이고 강력한 프로그래밍을 가능하게 합니다.

포인터의 정의

포인터는 다른 변수의 메모리 주소를 저장하는 변수입니다. 즉, 데이터가 아닌 데이터가 저장된 위치를 가리키는 변수입니다. 이를 통해 메모리의 특정 위치에 직접 접근하고, 그 위치에 저장된 데이터를 읽고 쓸 수 있습니다.

포인터가 필요한 이유

1. 함수를 통한 값의 효율적 변경

프로그래밍을 할 때, 때때로 여러 함수에 걸쳐 변수를 수정해야 할 필요가 있습니다. 포인터를 사용하지 않고 일반 변수를 함수에 전달하면, 함수는 그 변수의 복사본을 받아 작업하기 때문에 원본 데이터는 변경되지 않습니다. 그러나 포인터를 사용하면 원본 변수의 메모리 주소를 직접 전달하므로 함수 내에서 변수의 값을 직접 변경할 수 있습니다.

#include <stdio.h>

void addTen(int *num) {
    *num += 10;  // num 포인터가 가리키는 값에 10을 더함
}

int main() {
    int value = 5;
    addTen(&value);  // value의 주소를 전달
    printf("value: %d\n", value);  // 출력: value: 15
    return 0;
}

 

이 예시에서 addTen 함수는 int 포인터를 매개변수로 받아, 포인터가 가리키는 값에 10을 더합니다. 메인 함수에서는 value 변수의 주소를 함수에 전달하므로, 함수에서 value의 원본 값이 변경됩니다.

2. 대용량 데이터 처리

데이터가 매우 클 때, 예를 들어 대규모 배열이나 구조체 등을 다룰 때, 이를 값으로 전달하면 매번 전체 데이터가 복사되어 메모리 사용량이 매우 높아지고 성능이 저하될 수 있습니다. 포인터를 사용하면 데이터의 주소만을 전달하므로 메모리 사용량과 처리 시간을 크게 절약할 수 있습니다.

#include <stdio.h>

typedef struct {
    char name[100];
    int age;
    float salary;
} Employee;

void printEmployee(const Employee *emp) {
    printf("Name: %s, Age: %d, Salary: %.2f\n", emp->name, emp->age, emp->salary);
}

int main() {
    Employee emp = {"John Doe", 30, 50000.0};
    printEmployee(&emp);
    return 0;
}

 

여기서 Employee 구조체의 인스턴스는 크기가 큰 편이므로, 함수에 직접 값을 전달하기보다는 포인터를 사용하여 주소만 전달합니다. 이로 인해 함수 호출의 효율성이 높아집니다.

 

3. 동적 메모리 관리

C언어에서 동적 메모리 할당은 포인터 없이는 불가능합니다. malloc, calloc 등의 함수를 사용해 메모리를 할당받고, 이를 통해 실행 중에 메모리 크기를 조정할 수 있습니다. 이는 배열 크기가 런타임에 결정되어야 할 때 매우 유용합니다.

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

int main() {
    int n, i;
    int *array;
    
    printf("Enter the number of elements: ");
    scanf("%d", &n);
    
    array = (int*)malloc(n * sizeof(int));  // n개의 int 크기만큼 메모리 할당
    
    for (i = 0; i < n; i++) {
        array[i] = i;
    }
    
    for (i = 0; i < n; i++) {
        printf("%d ", array[i]);
    }
    
    free(array);  // 동적 할당된 메모리 해제
    return 0;
}

 

이 예시에서는 사용자가 입력한 개수에 따라 배열의 크기를 동적으로 할당합니다. 프로그램 실행 중 데이터의 크기가 변할 때 이러한 동적 메모리 할당이 필수적입니다.

 

이처럼 포인터는 C언어에서 데이터의 효율적 관리, 성능 최적화, 그리고 유연성 제공을 위해 필수적인 요소입니다. 포인터를 통해 메모리를 보다 직접적으로 제어하며, 이는 C언어의 강력한 특성 중 하나입니다.


포인터의 선언

포인터를 선언하는 방법은 일반 변수를 선언하는 방법과 유사합니다. 단, 변수 타입 앞에 * (별표)를 붙여 해당 변수가 포인터임을 나타냅니다. 예를 들어, int 타입의 데이터를 가리키는 포인터를 선언하고 싶다면 다음과 같이 선언합니다:

int *pointer;

이 예에서 pointer는 int 타입의 데이터를 가리키는 포인터 변수입니다.

포인터의 초기화

포인터를 초기화하는 방법에는 여러 가지가 있습니다. 가장 간단한 방법은 다른 변수의 주소를 포인터에 할당하는 것입니다. 주소 할당은 & (주소 연산자)를 사용하여 이루어집니다.

int var = 5;
int *pointer = &var;

여기서 pointer는 var의 주소를 저장하게 됩니다. 즉, pointer를 통해 var에 저장된 5라는 값을 읽거나 변경할 수 있습니다.

 

포인터를 통한 값의 접근

포인터가 가리키는 주소의 값을 접근하려면 역참조 연산자 *를 사용합니다. 예를 들어, 위에서 선언한 pointer를 통해 var의 값을 변경하려면 다음과 같이 작성합니다:

*pointer = 10;

이 코드를 실행하면 var의 값은 10으로 변경됩니다. 포인터 pointer를 통해 var의 실제 메모리 위치에 접근하여 값을 10으로 수정한 것입니다.

포인터와 배열

배열 이름 자체가 배열의 첫 번째 요소의 주소를 가리키는 포인터로 사용될 수 있습니다. 예를 들어, int arr[3] = {10, 20, 30}; 배열이 있다면, arr을 포인터처럼 사용할 수 있습니다.

int *ptr = arr;
printf("%d\n", *(ptr + 1)); // 20 출력

ptr + 1은 배열의 두 번째 요소를 가리키며, *(ptr + 1)는 두 번째 요소의 값을 읽습니다.

 

포인터의 주의사항

포인터를 사용할 때는 항상 유효한 메모리 주소를 가리키고 있는지 확인해야 합니다. 초기화되지 않은 포인터나 잘못된 메모리 주소를 참조하는 포인터는 프로그램의 안정성을 크게 해칠 수 있습니다.

int *bad_ptr;
*bad_ptr = 10; // 정의되지 않은 행동 발생

 

이 코드에서 bad_ptr은 초기화되지 않았기 때문에 정의되지 않은 행동을 일으킬 수 있습니다.

 

 

참고하면 좋을 포스팅

https://www.inflearn.com/pages/dc-pointer-202310

 

왜 C언어 포인터는 이해하기 어려울까? - 인프런 | 스토리

교수님! 진도가 너무 빠릅니다 😭 C언어 입문의 최종보스, 들어는 봤나 포인터! C언어 배워보신 분 손! 프로그래밍에 관심이 있다면 한 번쯤은 ‘C언어에서 포인터가 그렇게 어렵다더라’ 하는

www.inflearn.com

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함