programing

C에서는 어레이가 포인터입니까, 포인터로 사용됩니까?

prostudy 2022. 6. 7. 21:29
반응형

C에서는 어레이가 포인터입니까, 포인터로 사용됩니까?

어레이는 단순히 일련의 값에 대한 지속적인 포인터일 뿐이며, C에서 어레이를 선언할 때는 포인터를 선언하고 포인터가 가리키는 시퀀스에 공간을 할당하는 것으로 알고 있습니다.

그런데 헷갈리네요.다음 코드:

char y[20];
char *z = y;

printf("y size is %lu\n", sizeof(y));
printf("y is %p\n", y);
printf("z size is %lu\n", sizeof(z));
printf("z is %p\n", z);

Apple GCC를 사용하여 컴파일하면 다음과 같은 결과가 나타납니다.

y size is 20
y is 0x7fff5fbff930
z size is 8
z is 0x7fff5fbff930

(머신은 64비트, 포인터는 8바이트입니다).

'y'가 상수 포인터인 경우, 가리키는 값의 순서와 같이 크기가 20인 이유는 무엇입니까?컴파일 중에 변수 이름 'y'가 적절한 경우 메모리 주소로 대체됩니까?그러면 배열은 C에 있는 구문설탕 같은 것으로 컴파일할 때 포인터 물질로 변환되는 것일까요?

C 표준(n1256)의 정확한 언어는 다음과 같습니다.

6.3.2.1 Lvalue, 열 6 6 6 6 6 6 。
...
3 피연산자의 피연산자일 경우 제외한다. sizeof연산자 또는 단항자 &operator 또는 배열 초기화에 사용되는 문자열 리터럴로, 배열의 유형 "array"를 가진 식입니다.type'은 type이 "type"인 식에 변환됩니다.type'은 배열 객체의 초기 요소를 가리키며 l값이 아닙니다.어레이 개체에 레지스터 스토리지 클래스가 있으면 동작이 정의되지 않습니다.

여기서 기억해야 할 중요한 것은 오브젝트(C 용어로 메모리를 차지하는 것을 의미)와 그 오브젝트를 참조하는 데 사용되는 표현 사이에 차이가 있다는 것입니다.

다음과 같은 배열을 선언하는 경우

int a[10];

표현에 의해 지정된 대상 a의 메모리 으로 10개의 메모리 블록, 10개의 메모리 블록, 10개의 메모리 를 저장할 수 .intvalues) 및 표현식 a의 유형은 "10-segrates 배열"입니다.int ",int [10]. 만약 표현된 경우 a는 오퍼랜드 됩니다.sizeof ★★★★★★★★★★★★★★★★★」&합니다.int *을 사용하다

sizeof 「」(operand 「operand」)의.T [N] 오브젝트에 .「 」 、 「 」 。N * sizeof T

&연산자, 값은 배열의 주소입니다.이것은 배열의 첫 번째 요소의 주소와 동일하지만 식 타입이 다릅니다.선언이 지정됩니다.T a[N]; 「」입니다.&aT (*)[N]또는 T의 N-element 배열에 대한 포인터입니다.값은 다음과 같습니다.a ★★★★★★★★★★★★★★★★★」&a[0](어레이의 주소는 어레이의 첫 번째 요소의 주소와 동일하지만 유형의 차이는 중요합니다).를 들어, 코드 「」가 되면, 「」가 됩니다.

int a[10];
int *p = a;
int (*ap)[10] = &a;

printf("p = %p, ap = %p\n", (void *) p, (void *) ap);
p++;
ap++;
printf("p = %p, ap = %p\n", (void *) p, (void *) ap);

의 순서로 출력이 표시됩니다.

p = 0xbff11e58, ap = 0xbff11e58
p = 0xbff11e5c, ap = 0xbff11e80

, IOW, ★★psizeof int (4)는 원래 값으로 됩니다.ap10 * sizeof int (40)

보다 표준적인 언어:

6.5.2.1

★★

1 표현 중 하나는 타입 "객체에 대한 포인트"를 가져야 한다.type'', 다른 식에는 정수형이 있어야 하며 결과는 type '입니다.를 입력합니다.



2 postfix 식 2 、 「 」[]는 배열 오브젝트 요소의 첨자 표기입니다.첨자 연산자의 정의 []것이이E1[E2]★★★★★★★★★★★★★★★★★★▼(*((E1)+(E2)))바이너리에 적용되는 변환 규칙 때문에 +if if자 if. E1는 어레이 오브젝트(즉, 어레이 오브젝트의 초기 요소에 대한 포인터)이며, E2정수입니다. E1[E2]를 지정합니다. E2의 -번째 요소 E1(제로에서 제외).

따라서 배열 식에 첨자를 붙이면 후드 아래에서 배열의 첫 번째 요소 주소에서 오프셋이 계산되고 결과가 참조 해제됩니다.표현

a[i] = 10;

와 동등하다

*((a)+(i)) = 10;

와 동등하다.

*((i)+(a)) = 10;

와 동등하다.

 i[a] = 10;

네, 어레이의 서브스크립션은 교환형입니다.실가동코드에서는절대사용하지않습니다.

배열 첨자는 포인터 조작의 관점에서 정의되므로, 다음과 같이 포인터 유형의 식과 배열 유형의 식에 첨자 연산자를 적용할 수 있습니다.

int *p = malloc(sizeof *p * 10);
int i;
for (i = 0; i < 10; i++)
  p[i] = some_initial_value(); 

다음 표는 다음 개념을 기억하기 위한 편리한 표입니다.

선언:Ta[N];
식 유형이 값으로 변환됨----------    ----    ------------    -----a T [N] T * a의 첫 번째 요소의 주소쓰기 &a[0]와 동일&a T(*)[N] 어레이의 주소, 값이 동일합니다.위와 같으나 종류가 다르다size of a size_t 배열에 포함된 바이트 수오브젝트(N * T 사이즈)*a [0]에서의 T값a[i] T 값 a[i]에서의 값&a[i] T * a[i] 주소
선언:Ta[N][M];
식 유형이 값으로 변환됨----------     ----        ------------    -----a T [ N ] [ M ] T ( * ) [ M ]첫 번째 서브 어레이의 주소(&a[0])&a T(*)[N][M] 어레이의 주소(와 같은 값)위, 단, 다른 타입)size of a size_t 에 포함되는 바이트 수어레이 객체(N * M * T 크기)*a T [M] T * a [ 0 ]의 값(주소)첫 번째 서브어레이의 첫 번째 요소의(&a[0][0]와 동일)a[i] T [M] T * a[i]의 값(주소)i번째 서브어레이의 첫 번째 요소의&a[i] T(*)[M] i번째 서브 어레이의 주소, 다음과 같은 값위, 그러나 다른 유형size of a [i] size_t i번째 서브어레이에 포함된 바이트 수오브젝트(M * T 사이즈)*a[i] T i'th 첫 번째 요소의 값서브어레이(a[i][0])a[i][j] T 값 a[i][j]&a[i][j] T * a[i][j] 주소
선언:[N][M][O];

식 유형이 변환됨----------        ----             -----------a [N][M][O] T (*)[M][O]&a T(*)[N][M][O]*a [M] [O] T (*) [O]a[i] T [M] [O] T (*) [O]&a[i] T(*)[M][O]*a[i] T[O] T *a[i][j] T[O] T *&a[i][j] T(*)[O]*a[i][j] Ta[i][j][k] T

여기서부터 고차원 배열의 패턴이 명확해야 합니다.

즉, 어레이는 포인터가 아닙니다.대부분의 컨텍스트에서 배열 식은 포인터 유형으로 변환됩니다.

배열은 포인터가 아니지만 대부분의 식에서 배열 이름은 배열의 첫 번째 요소에 대한 포인터로 평가됩니다.따라서 어레이 이름을 포인터로 사용하는 것은 매우 간단합니다.이를 설명하기 위해 사용되는 용어 'decay'는 "array decrupt to pointer"에서 자주 볼 수 있습니다.

한 가지 예외는 오퍼랜드로서sizeofoperator. 여기서 결과는 배열 크기(요소가 아닌 바이트 단위)입니다.

이와 관련된 몇 가지 추가 문제:

함수에 대한 배열 파라미터는 픽션입니다.컴파일러는 플레인 포인터를 실제로 전달합니다(이것은 C++의 배열 참조 파라미터에는 적용되지 않습니다).따라서 함수에 전달되는 배열의 실제 크기를 결정할 수 없습니다.다른 방법으로 (명시적인 추가 파라미터를 사용하거나 sentinel 요소를 사용하여) 정보를 전달해야 합니다.C 스트링처럼)

또한 배열 내의 요소 수를 얻기 위한 일반적인 관용구는 다음과 같은 매크로를 사용하는 것입니다.

#define ARRAY_SIZE(arr) ((sizeof(arr))/sizeof(arr[0]))

이는 컴파일러의 경고 없이 동작하는 어레이 이름과 포인터 중 하나를 받아들이는 문제가 있습니다.매크로의 안전한 버전(특히 C++의 경우)이 존재하기 때문에 어레이 대신 포인터와 함께 사용하면 경고나 오류가 발생합니다.다음 SO 항목을 참조하십시오.


주의: C99 VLA(가변 길이 어레이)는 이러한 규칙 중 일부를 따르지 않을 수 있습니다(특히, 호출된 함수에 의해 인식되는 어레이 크기를 가진 파라미터로 전달할 수 있습니다).저는 VLA에 대한 경험이 거의 없고 널리 사용되지 않는 것으로 알고 있습니다.단, 위의 설명은 VLA에 따라 다를 수 있습니다.

sizeof컴파일 시 평가되며 오퍼랜드가 배열인지 포인터인지 컴파일러가 알 수 있습니다.어레이의 경우 어레이가 점유하는 바이트 수를 나타냅니다.어레이는char[](그리고sizeof(char)1) 입니다.sizeof원소의 수를 알 수 있습니다.일반적인 경우의 요소 수를 얻기 위해 일반적인 관용구는 다음과 같습니다.int):

int y[20];
printf("number of elements in y is %lu\n", sizeof(y) / sizeof(int));

포인터sizeofraw 포인터 타입이 점유하는 바이트 수를 나타냅니다.

char hello[] = "hello there"
int i;

그리고.

char* hello = "hello there";
int i;

첫 번째 인스턴스(디스카운트 얼라인먼트)에서는 12바이트가 hello용으로 저장되며, 두 번째 hello에서는 다른 곳(스태틱스페이스일 가능성이 있음)에 저장되어 있습니다.hello는 지정된 문자열을 가리키도록 초기화됩니다.

hello[2]게다가*(hello + 2)단, 두 경우 모두 'e'가 반환됩니다.

다른 사람의 의견과 더불어 이 기사는 도움이 될 수 있습니다.http://en.wikipedia.org/wiki/C_%28programming_language%29#Array-pointer_interchangeability

'y'가 상수 포인터인 경우, 가리키는 값의 순서와 같이 크기가 20인 이유는 무엇입니까?

왜냐면z는 변수의 주소이며, 항상 머신에 대해8 을 반환합니다.변수의 내용을 가져오려면 참조 해제 포인터(&)를 사용해야 합니다.

편집: http://www.cs.cf.ac.uk/Dave/C/node10.html과 http://www.cs.cf.ac.uk/Dave/C/node10.html의 좋은 차이점

언급URL : https://stackoverflow.com/questions/4607128/in-c-are-arrays-pointers-or-used-as-pointers

반응형