프로그래밍C 개발자

배열에 대한 포인터(pointer to array)와 포인터 배열(array of pointers) 작업의 세부적인 특징을 설명하십시오. C 언어에서 이들을 올바르게 선언하고 사용하는 방법 및 서로 구별하는 방법은 무엇입니까?

Hintsage AI 어시스턴트로 면접 통과

답변.

역사적으로 포인터는 C 언어에서 메모리 작업의 기초가 되었으며, 배열 요소 및 동적 구조체에 대한 효율적인 접근을 위한 유연한 메커니즘을 제공합니다. 그러나 배열에 대한 포인터와 포인터 배열의 문법과 의미는 종종 혼란을 일으킵니다.

문제: 초보 프로그래머는 종종 배열에 대한 포인터 (pointer to array)와 포인터 배열 (array of pointers)를 혼동하여 잘못된 메모리 사용, 파라미터 전달 오류 및 해석하기 어려운 문법 오류를 초래합니다.

해결책:

  • Pointer to array: 전체 배열의 주소를 저장하는 변수입니다(메모리의 한 블록).
  • Array of pointers: 각 요소가 포인터인 배열입니다(예: 문자열 배열).

선언 및 사용 예:

// 10개의 int 배열에 대한 포인터: int (*p)[10]; int arr[10]; p = &arr; // 10개의 int에 대한 포인터 배열 int *ap[10]; for (int i = 0; i < 10; ++i) { ap[i] = &arr[i]; } // 배열에 대한 포인터로 요소에 접근하기: (*p)[2] = 5; // arr의 세 번째 요소 // 포인터 배열을 사용하여 값 얻기: *ap[2] = 8; // ap를 통해 arr의 세 번째 요소

주요 특징:

  • 타입 int (*p)[N]은 N개의 요소로 구성된 배열에 대한 포인터를 의미합니다(여기서 p는 하나의 메모리만 가집니다).
  • 타입 int *a[N]은 N개의 포인터로 구성된 배열을 의미하며, 각 포인터는 어디론가 가리킵니다(예: 문자열).
  • 문법 및 괄호의 우선 순위: int (*p)[N], 아닌 int *p[N]!

함정 질문.

**int p[10]와 int (p)[10]은 동일합니까?

아니요. int *p[10]은 int에 대한 10개의 포인터로 구성된 배열입니다. int (*p)[10]은 10개의 int로 구성된 배열에 대한 포인터입니다. 괄호 없이 혼란이 생깁니다!

코드 예:

int arr[10]; int *p[10]; // 포인터 배열 int (*q)[10] = &arr; // 배열에 대한 포인터

*일반 int 포인터를 int (p)[10]형 변수에 자유롭게 할당할 수 있습니까?

아니요. 일반 int *는 하나의 요소를 가리키고, int (*p)[10]은 10개의 정수 배열을 가리키기 때문에 타입이 호환되지 않습니다.

2차원 배열을 함수에 올바르게 전달하는 방법은 무엇입니까?

두 번째 차원의 크기를 명시적으로 지정해야 합니다:

void foo(int a[][4], int n); // n개의 4요소 행 배열

또는 배열에 대한 포인터를 사용할 수 있습니다:

void bar(int (*a)[4], int n);

일반적인 오류 및 안티 패턴

  • 괄호 없이 잘못 선언하기.
  • 포인터 배열과 배열에 대한 포인터 간의 타입 혼동.
  • 함수에 2차원 배열 전달 시 오류.

실생활 사례

부정적인 사례

엔지니어가 변수를 int *p[10]으로 선언하고, &arr을 할당하려고 시도하며, arr이 int arr[10]인 경우 배열처럼 접근하려고 하면 컴파일 오류나 잘못된 동작이 발생합니다.

장점:

  • 가장 간단한 표기법.

단점:

  • 명확하지 않은 런타임 오류, 잘못된 메모리 작업.

긍정적인 사례

개발자가 괄호를 주의 깊게 사용하고 int (*p)[10]을 사용하여 차이를 명확히 이해하며, 배열을 함수에 올바르게 전달하고 typedef를 사용하여 선언을 간소화합니다.

장점:

  • 안전하고 명확한 코드, 타입 오류 없음.

단점:

  • 과도한 문법, 세부 사항에 대한 주의가 필요합니다.