[c] 배열 이름이 포인터입니까?

배열의 이름이 C의 포인터입니까? 그렇지 않은 경우 배열의 이름과 포인터 변수의 차이점은 무엇입니까?



답변

배열은 배열이고 포인터는 포인터이지만 대부분의 경우 배열 이름은 포인터 로 변환 됩니다. 자주 사용되는 용어는 포인터로 쇠퇴 한다는 것 입니다.

배열은 다음과 같습니다.

int a[7];

a 7 개의 정수를위한 공간을 포함하며, 다음과 같이 대입으로 값 중 하나에 값을 넣을 수 있습니다.

a[3] = 9;

다음은 포인터입니다.

int *p;

p정수를위한 공백을 포함하지 않지만 정수를위한 공백을 가리킬 수 있습니다. 예를 들어, 배열 a에서 첫 번째 장소 와 같은 장소 중 하나를 가리 키도록 설정할 수 있습니다 .

p = &a[0];

혼란스러운 점은 다음과 같이 쓸 수도 있다는 것입니다.

p = a;

이것은 배열의 내용을 포인터에 복사 하지 않습니다 (의미 한 것은 무엇이든). 대신 배열 이름 이 첫 번째 요소에 대한 포인터로 변환됩니다. 할당은 이전과 동일합니다.apa

이제 p배열과 비슷한 방식으로 사용할 수 있습니다 .

p[3] = 17;

이것이 작동하는 이유는 C의 배열 역 참조 연산자 [ ]가 포인터로 정의되기 때문입니다. x[y]수단 : 포인터로 시작 x, 단계 y에 어떤 포인터 포인트 후 앞으로 요소를, 다음이 무엇이든 걸릴. 포인터 산술 구문을 사용하여로 x[y]도 쓸 수 있습니다 *(x+y).

이것이 우리와 같은 일반 배열과 함께 작동 하려면 먼저 in a의 이름 aa[3]포인터로 변환해야합니다 (의 첫 번째 요소로 a). 그런 다음 3 단계 요소를 앞으로 진행하고 모든 요소를 ​​가져옵니다. 다시 말해, 배열에서 3 번째 위치에있는 요소를 가져옵니다. (첫 번째 요소의 번호는 0이므로 배열의 네 번째 요소는 어느 것입니까?)

따라서 요약하면 C 프로그램의 배열 이름은 (대부분의 경우) 포인터로 변환됩니다. 예외는 sizeof배열 에서 연산자를 사용할 때 입니다. a이 문맥에서 포인터로 변환 된 경우 sizeof a실제 배열이 아닌 포인터의 크기를 지정하면 쓸모가 없으므로 a배열 자체를 의미합니다.


답변

배열을 값으로 사용하면 해당 이름은 첫 번째 요소의 주소를 나타냅니다.
배열을 값으로 사용하지 않으면 이름이 전체 배열을 나타냅니다.

int arr[7];

/* arr used as value */
foo(arr);
int x = *(arr + 1); /* same as arr[1] */

/* arr not used as value */
size_t bytes = sizeof arr;
void *q = &arr; /* void pointers are compatible with pointers to any object */


답변

배열 유형의 표현식 (예 : 배열 이름)이 더 큰 표현식에 나타나고 &또는 의 피연산자가 아닌 경우sizeof 그 배열 식의 종류가 “T의 N 소자 어레이”로 변환된다 연산자 “pointer to T”이고 표현식의 값은 배열에서 첫 번째 요소의 주소입니다.

간단히 말해서 배열 이름은 포인터가 아니지만 대부분의 상황에서 마치 .

편집하다

의견의 질문에 대답 :

sizeof를 사용하면 배열 요소의 크기 만 계산합니까? 그런 다음 배열 “head”는 길이와 포인터에 대한 정보로 공간을 차지합니다 (그리고 이것은 일반적인 포인터보다 공간이 더 많이 필요하다는 것을 의미합니까?).

배열을 만들 때 할당 된 유일한 공간은 요소 자체를위한 공간입니다. 별도의 포인터 또는 메타 데이터를 위해 스토리지가 구체화되지 않습니다. 주어진

char a[10];

기억에 남는 것은

   +---+
a: |   | a[0]
   +---+
   |   | a[1]
   +---+
   |   | a[2]
   +---+
    ...
   +---+
   |   | a[9]
   +---+

표현은 a 전체 어레이를 지칭하지만 없다 객체 a 배열 요소 자체는 별개. 따라서 sizeof a전체 배열의 크기 (바이트)를 제공합니다. 이 표현식 &a은 배열 의 주소를 제공하며 이는 첫 번째 요소의 주소와 동일합니다 . 차이 &a&a[0]그 결과의 유형 1char (*)[10]첫번째 경우와 char *두번째로.

상황이 이상하게 여기는 위치는 개별 요소에 액세스하려는 경우입니다. 표현식 a[i]*(a + i)주소 값 의 결과로 정의되며 해당 주소 a에서 오프셋 i요소 ( 바이트가 아님)를 정의하고 결과를 역 참조합니다.

문제는 a포인터 또는 주소가 아니라 전체 배열 객체라는 것입니다. 따라서 C의 규칙은 컴파일러가 배열 유형의 표현식 (예 : a유형이있는 char [10])을 보고 해당 표현식이 sizeof단항 &연산자 의 피연산자가 아니 거나 해당 표현식의 유형이 변환 되는 규칙 ( “감쇠”)입니다. 포인터 유형 ( char *)에 대한 표현식의 값은 배열의 첫 번째 요소의 주소입니다. 따라서 표현식 a표현식 과 유형 및 값이 동일 &a[0]하며 확장에 따라 표현식 *a은 유형 및 값과 동일합니다 a[0].

C는 B라는 이전 언어에서 파생되었으며 B 에서는 배열 요소 와 별도의 포인터 객체 a 였습니다 .a[0]a[1] 등 리치는 B의 배열의 의미를 유지하고 싶어하지만, 그는 별도의 포인터 객체를 저장 엉망 싶지 않았다. 그래서 그는 그것을 제거했다. 대신, 컴파일러는 필요에 따라 변환 중에 배열 표현식을 포인터 표현식으로 변환합니다.

배열은 크기에 대한 메타 데이터를 저장하지 않는다는 것을 기억하십시오. 배열 표현식이 포인터로 “부패”하자마자 단일 요소에 대한 포인터입니다. 해당 요소는 일련의 요소 중 첫 번째 요소이거나 단일 객체 일 수 있습니다. 포인터 자체를 기반으로 알 방법이 없습니다.

배열 표현식을 함수에 전달할 때받는 모든 함수는 첫 번째 요소에 대한 포인터입니다. 배열이 얼마나 큰지 알 수 없습니다 (이것이 gets함수가 그러한 위협이었고 결국 라이브러리에서 제거 된 이유입니다 ). 함수가 배열의 요소 수를 알기 위해서는 센티넬 값 (예 : C 문자열의 0 종결 자)을 사용하거나 요소 수를 별도의 매개 변수로 전달해야합니다.


  1. 주소 값 해석 방법에 어떤 영향을 미칠 수 있는지는 기계에 따라 다릅니다.


답변

이와 같이 선언 된 배열

int a[10];

10 int초 동안 메모리를 할당합니다 . 당신은 수정할 수 a없지만 포인터 산술을 할 수 있습니다a .

이와 같은 포인터는 포인터에 대해서만 메모리를 할당합니다 p.

int *p;

ints를 할당하지 않습니다 . 수정할 수 있습니다 :

p = a;

다음과 같이 배열 첨자를 사용하십시오.

p[2] = 5;
a[2] = 5;    // same
*(p+2) = 5;  // same effect
*(a+2) = 5;  // same effect


답변

배열 이름 자체는 메모리 위치를 생성하므로 배열 이름을 포인터처럼 취급 할 수 있습니다.

int a[7];

a[0] = 1976;
a[1] = 1984;

printf("memory location of a: %p", a);

printf("value at memory location %p is %d", a, *a);

그리고 포인터에 대해 할 수있는 다른 멋진 것들 (예 : 오프셋 추가 / 빼기)은 배열에 할 수도 있습니다.

printf("value at memory location %p is %d", a + 1, *(a + 1));

C가 배열 을 “포인터”의 일종 으로 노출시키지 않은 경우 언어 적으로 메모리 위치입니다. 메모리 위치 일뿐입니다. 메모리의 임의 위치를 ​​가리킬 수 없으며 프로그래머가 제어 할 수도 없습니다. 우리는 항상 이것을 코딩해야합니다 :

printf("value at memory location %p is %d", &a[1], a[1]);


답변

이 예제는이 문제에 대해 약간의 지적을합니다.

#include <stdio.h>
int main()
{
        int a[3] = {9, 10, 11};
        int **b = &a;

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

gcc 4.9.2에서 잘 컴파일되고 (경고 2 개) 다음을 인쇄합니다.

a == &a: 1

죄송합니다 🙂

따라서 결론은 아니오입니다. 배열은 포인터가 아니며 &처럼 연산자를 사용하여 주소를 얻을 수 있기 때문에 메모리처럼 (읽기 전용이 아닌) 포인터로 저장되지 않습니다. . 그러나-죄송합니다-그 연산자는 작동하지 않습니다 :-)), 당신은 어느 쪽이든 경고를 받았습니다 :

p.c: In function main’:
pp.c:6:12: warning: initialization from incompatible pointer type
  int **b = &a;
            ^
p.c:8:28: warning: comparison of distinct pointer types lacks a cast
  printf("a == &a: %d\n", a == b);

C ++은 컴파일 타임에 오류가있는 그러한 시도를 거부합니다.

편집하다:

이것이 내가 설명하려는 것입니다.

#include <stdio.h>
int main()
{
    int a[3] = {9, 10, 11};
    void *c = a;

    void *b = &a;
    void *d = &c;

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

비록 ca같은 메모리에 “포인트”, 당신의 주소를 얻을 수 있습니다 c포인터를, 그러나 당신은의 주소를 얻을 수 없습니다 a포인터를.


답변

배열 이름은 포인터처럼 동작하며 배열의 첫 번째 요소를 가리 킵니다. 예:

int a[]={1,2,3};
printf("%p\n",a);     //result is similar to 0x7fff6fe40bc0
printf("%p\n",&a[0]); //result is similar to 0x7fff6fe40bc0

두 인쇄 문 모두 기계에 대해 정확히 동일한 출력을 제공합니다. 내 시스템에서 그것은 주었다 :

0x7fff6fe40bc0