본문 바로가기
C/C 문법

혼자 공부하는 C언어 (15~16강)

by Sein_ 2025. 9. 7.
728x90
1. 이중 포인터와 2차원 배열 포인터
2. 함수 포인터와 void 포인터
3. 동적 할당 함수

 

이중 포인터와 2차원 배열 포인터

  • 이중 포인터
    • 가리키는 자료형 **포인터
    • 이중 포인터는 포인터 변수를 가리키는 포인터
double a = 3.5;
double *pi = &a;

double **ppi = pi;

 

  • 포인터 활용 1
    • 포인터 값을 바꾸는 함수의 매개변수
int main(void)
{
    char *pa = "success";
    char *pb = "failure";
    
    swap_ptr(&pa, &pb);
}

void swap_ptr(char **ppa, char **ppb)
{
    char *pt;
    pt = *ppa;
    
    *ppa = *ppb;
    *ppb = pt;
}

 

 

  • 포인터 활용 2
    • 포인터 배열을 매개변수로 받는 함수
      • 포인터를 인자로 넘겨주어 매개변수에서 포인터의 주소값을 저장
void print_str(char **pps, int cnt);

int main(void)
{
    char *ptr_ary[] = {"apple", "banana"};
    
    int count = sizeof(ptr_ary) / sizeof(ptr_ary[0]);
    
    print_str(ptr_ary, count);	//print_str은 포인터 배열의 이름이므로 포인터의 주소이다.
}

void print_str(char **pps, int cnt)
{
    int i;
    
    for (i=0; i<cnt; i++)
    {
        printf("%s", pps[i]);
    }
}

 

  • 2차원 배열과 배열 포인터
    • 2차원 배열의 이름은 1차원 배열의 주소이다. (ex. int ary[3][4] 의 첫번째 배열 요소 => ary[0])
    • 2차원 배열의 이름을 저장할 배열 포인터의 선언
      • 배열의 자료형 (*포인터)[배열의 갯수] (ex. int (*pa)[4];)
      • 포인터를 괄호로 묶고 -> 양옆에 가리키는 배열의 형태를 나누어 적는다.

 

함수 포인터와 void 포인터

  • 함수 포인터
    • 반환형 (*포인터이름)(매개변수 목록);
    • 함수를 가리키는 포인터
    • 함수의 주소를 저장하고, 포인터를 통해 함수를 호출할 수 있음.
int add(int a, int b) {
    return a + b;
}

int (*funcPtr)(int, int);  // 함수 포인터 선언
funcPtr = add;             // 함수 주소 저장
int result = funcPtr(3, 4); // 포인터를 통한 함수 호출
  • void 포인터
    • void* 포인터;
    • 어떤 타입의 주소든 저장 가능한 포인터
    • void* 타입이기 때문에, 역참조하려면 형변환 필요
    • 간접 참조 연산과 주소에 대한 정수 연산이 불가
int a = 10;
void* ptr = &a;     // int형 변수의 주소 저장
printf("%d\n", *(int*)ptr); // 형변환 후 역참조

 

동적 할당 함수

  • 동적 할당
    • 프로그램 실행 중에 메모리를 할당하는 것
    • 크기를 미리 정하지 않고, 필요할 때 원하는 만큼 할당 가능
  • malloc, free 함수
    • malloc(size)
    • free(ptr)
    • stdlib.h 헤더 파일에 정의된 함수를 사용하여 동적 할당을 함
    • 프로그램 실행 중에 메모리를 동적으로 할당할 때는 malloc 함수를 사용
    • 프로그램 실행 중에 함수를 반환할 때는 free 함수 사용
#include <stdio.h>
#include <stdlib.h>

int main() {
    int* p = (int*)malloc(sizeof(int));  // 정수형 1개 공간 동적 할당

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

    *p = 100;
    printf("값: %d\n", *p);

    free(p);  // 메모리 해제
    return 0;
}
  • calloc, realloc 함수
    • calloc(n, size)
    • realloc(ptr, new_size)
    • colloc 함수는 동적 할당한 저장 공간을 0으로 초기화
    • realloc 함수는 크기를 바꿔 재할당
int* arr = (int*)calloc(5, sizeof(int));  // 0으로 초기화된 배열

arr = (int*)realloc(arr, 10 * sizeof(int));  // 배열 크기 늘리기

 

  • 동적 할당 함수 활용
    • 문자열 입력 처리
      • 정적인 배열로 문자열을 저장하면 사용자가 입력할 문자열의 길이를 예측할 수 없음
      • 입력하는 문자열의 길이에 맞는 가변 메모리 공간을 확보 가능
      • malloc() 또는 realloc()으로 메모리를 할당하여 해결
#include <stdio.h>
#include <stdlib.h>

int main() {
    char* str = (char*)malloc(100 * sizeof(char)); // 최대 99글자까지 허용

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

    printf("문자열 입력: ");
    fgets(str, 100, stdin);  // 공백 포함 문자열 입력 가능

    printf("입력한 문자열: %s", str);

    free(str);
    return 0;
}
  • 명령행 인수 처리
    • 프로그램 실행 시, 명령줄에서 함께 전달되는 문자열 인수들
    • 운영체제가 명령행 인수를 프로그램의 main 함수로 넘기는 방법
#include <stdio.h>

int main(int argc, char **argv) {
    printf("인수 개수: %d\n", argc);

    for (int i = 0; i < argc; i++) {
        printf("argv[%d]: %s\n", i, argv[i]);
    }

    return 0;
}