왜 x [0]! = x [0] [0]! = x [0] [0] [0]입니까?


149

나는 약간의 C ++을 공부하고 있으며 포인터와 싸우고 있습니다. 다음과 같이 선언하면 3 단계의 포인터를 가질 수 있음을 이해합니다.

int *(*x)[5];

그래서 이것은 *x포인터 인 5 개 요소의 배열에 대한 포인터 int입니다. 또한 내가 알고 x[0] = *(x+0);, x[1] = *(x+1)등등 및 ....

위의 선언에서 왜 그렇 x[0] != x[0][0] != x[0][0][0]습니까?


58
x[0], x[0][0]x[0][0][0]다른 유형이있다. 비교할 수 없습니다. 무슨 소리 야 !=?
bolov

4
@celticminstrel 그들은 동일하지 않습니다 : int **x[5]5 요소의 배열입니다. 요소는 int`를 가리키는 포인터입니다.
bolov

5
@celticminstrel int** x[5]은 int를 가리키는 포인터를 가리키는 다섯 개의 포인터 배열입니다. int *(*x)[5]int를 가리키는 5 개의 포인터 배열에 대한 포인터입니다.
emlai

5
@celticminstrel 오른쪽 왼쪽 규칙 , 나선 규칙 , C 횡설수설 ↔ 영어 및 당신의 '는 3 성급 프로그래머 가되기 위해가는 길에 :)
bolov

5
@ Leo91 : 첫째, 세 가지가 아닌 두 가지 수준의 포인터가 있습니다. 둘째, 무엇을 x[0] != x[0][0] != x[0][0][0]의미합니까? 이것은 C ++에서 유효한 비교가 아닙니다. 하더라도 당신은에 그것을 분할 x[0] != x[0][0]하고 x[0][0] != x[0][0][0]여전히 유효하지 않습니다. 그래서, 당신의 질문은 무엇을 의미합니까?
AnT

답변:


261

x에 대한 5 개의 포인터 배열에 대한 포인터 int입니다.
x[0]에 대한 5 개의 포인터 배열 입니다 int.
x[0][0]에 대한 포인터 int입니다.
x[0][0][0]입니다 int.

                       x[0]
   Pointer to array  +------+                                 x[0][0][0]         
x -----------------> |      |         Pointer to int           +-------+
               0x500 | 0x100| x[0][0]---------------->   0x100 |  10   |
x is a pointer to    |      |                                  +-------+
an array of 5        +------+                        
pointers to int      |      |         Pointer to int                             
               0x504 | 0x222| x[0][1]---------------->   0x222                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x508 | 0x001| x[0][2]---------------->   0x001                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x50C | 0x123| x[0][3]---------------->   0x123                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x510 | 0x000| x[0][4]---------------->   0x000                    
                     |      |                                             
                     +------+                                             

당신은 그것을 볼 수 있습니다

  • x[0]는 배열이며 표현식에서 사용될 때 첫 번째 요소에 대한 포인터로 변환됩니다 (일부 예외 제외). 따라서 x[0]첫 번째 요소의 주소 x[0][0]0x500입니다.
  • x[0][0]의 주소가 포함되어 int있는이 0x100.
  • x[0][0][0]int값을 포함합니다 10.

따라서 x[0]동일하다 &x[0][0]그러므로 및, &x[0][0] != x[0][0].
따라서 x[0] != x[0][0] != x[0][0][0].


이 다이어그램은 약간 혼란 스럽습니다 : 0x100상자 왼쪽에 나타나는 10것과 같은 방식으로 상자가 왼쪽에 즉시 나타나야합니다 0x500. 왼쪽과 아래쪽으로 멀어지는 대신.
MM

@MattMcNabb; 혼란스럽지 않다고 생각하지만 더 명확하게하기 위해 귀하의 제안에 따라 변경됩니다.
haccks

4
@haccks-나의 기쁨 :) 그 다이어그램이 훌륭한 이유는 당신이 그에 따른 설명을 필요로하지 않기 때문입니다. 이 다이어그램 자체는 이미 설명되어 있으므로 이미 질문에 대답했습니다. 다음 텍스트는 단순히 보너스입니다.
rayryeng

1
다이어그램 소프트웨어 인 yed를 사용할 수도 있습니다. 그것은 내 생각을 정리하는데 많은 도움이됩니다
rpax

의견에 대한 @GrijeshChauhan I 사용 asciiflow : 프리젠 테이션 YED 적힌 코드
rpax

133
x[0] != x[0][0] != x[0][0][0]

자신의 게시물에 따르면

*(x+0) != *(*(x+0)+0) != *(*(*(x+0)+0)+0)`  

이것은 단순화

*x != **x != ***x

왜 평등해야합니까?
첫 번째는 포인터의 주소입니다.
두 번째는 다른 포인터의 주소입니다.
그리고 세 번째는 int가치입니다.


이해할 수 없습니다 ... x [0], x [0] [0], x [0] [0] [0]이 * (x + 0), * (x + 0 + 0)에 해당하는 경우 , * (x + 0 + 0 + 0), 왜 서로 다른 주소를 가져야합니까?
Leo91

41
@ Leo91가 x[0][0]있다 (x[0])[0], 즉 *((*(x+0))+0), 없습니다 *(x+0+0). 역 참조는 두 번째 전에 발생합니다 [0].
emlai

4
x[0][0] != *(x+0+0)그냥 @ Leo91 x[2][3] != x[3][2].
özg

@ Leo91 "지금 가져 왔습니다"라는 두 번째 주석이 제거되었습니다. 당신은 무언가를 이해하지 못합니까 (답변에서 더 잘 설명 될 수 있습니까), 그렇지 않습니까? (일부 사람들은 유익한 정보없이 댓글을 삭제하는 것을 좋아합니다)
deviantfan

@deviantfan 죄송합니다, 당신이 무슨 뜻인지 이해할 수 없습니다. 나는 그 개념을 명확히하는 데 도움이 된 많은 의견들과 그 해답들을 이해한다.
Leo91

50

다음은 포인터의 메모리 레이아웃입니다.

   +------------------+
x: | address of array |
   +------------------+
            |
            V
            +-----------+-----------+-----------+-----------+-----------+
            | pointer 0 | pointer 1 | pointer 2 | pointer 3 | pointer 4 |
            +-----------+-----------+-----------+-----------+-----------+
                  |
                  V
                  +--------------+
                  | some integer |
                  +--------------+

x[0]"어드레스 주소",
x[0][0]"포인터 0",
x[0][0][0]"일부 정수"를 나타냅니다.

나는 지금 분명해야한다고 생각한다. 왜 그들은 모두 다르다.


위의 내용은 기본적인 이해를 위해 충분히 가깝기 때문에 내가 쓴 방식으로 썼습니다. 그러나 헥스가 올바르게 지적했듯이 첫 번째 줄은 100 % 정확하지 않습니다. 자세한 내용은 다음과 같습니다.

C 언어의 정의에서 값 x[0]은 정수 포인터의 전체 배열입니다. 그러나 배열은 C에서 실제로 할 수없는 일입니다. 항상 주소 전체 또는 요소를 조작하고 전체 배열을 전체적으로 사용하지 마십시오.

  1. 운영자 x[0]에게 전달할 수 있습니다 sizeof. 그러나 그것은 실제로 값을 사용하는 것이 아니며 결과는 유형에만 달려 있습니다.

  2. 주소를 가져 와서 xtype의 "address of array" 값을 얻을 수 있습니다 int*(*)[5]. 다시 말해:&x[0] <=> &*(x + 0) <=> (x + 0) <=> x

  3. 에서는 모든 다른 콘텍스트 의 값은 x[0]상기 어레이의 첫번째 엘리먼트에 대한 포인터로 붕괴된다. 즉, "address of array"값과 유형이있는 포인터입니다 int**. 효과는 x유형의 포인터로 캐스팅 한 것과 같습니다 int**.

경우 3의 배열 포인터 붕괴로 인해, x[0]궁극적으로 모든 사용은 포인터 배열의 시작을 가리키는 포인터를 생성합니다. 이 호출 printf("%p", x[0])은 "어드레스 주소"라고 표시된 메모리 셀의 내용을 인쇄합니다.


1
x[0]배열의 주소가 아닙니다.
haccks

1
@haccks 예, 표준의 문자를 따르는 x[0]것은 배열의 주소가 아니라 배열 자체입니다. 이에 대한 자세한 설명을 추가 한 이유 x[0]는 "어드레스 주소"입니다. 나는 그것을 좋아하면 좋겠.
cmaster-복원 monica

완벽하게 잘 설명하는 멋진 그래프!
MK

"하지만 배열은 C에서 실제로 할 수없는 일입니다." -> 카운터 예 : printf("%zu\n", sizeof x[0]);포인터의 크기가 아니라 배열의 크기를보고합니다.
chux-

@ chux-ReinstateMonica 그리고 계속해서 "너는 항상 주소 나 요소를 다룰 수 있고, 전체 배열을 전체로 절대 다루지 않는다"고 말한 다음 열거의 영향을받는 열거의 포인트 1을 따라 갔다 sizeof x[0].
cmaster-

18
  • x[0]가장 바깥 쪽 포인터 ( int에 대한 포인터의 크기 5의 배열에 대한 포인터) 를 역 참조하고 포인터 의 크기 5의 배열을 만듭니다 int.
  • x[0][0]최 포인터 역 참조 포인터로 결과 인덱스 어레이 int;
  • x[0][0][0] 모든 것을 역 참조하여 구체적인 가치를 창출합니다.

그건 그렇고, 이러한 종류의 선언이 의미하는 것에 혼란 스러우면 cdecl을 사용하십시오 .


11

단계 식으로 단계를 고려하자 x[0], x[0][0]하고 x[0][0][0].

x다음과 같이 정의됩니다

int *(*x)[5];

expression x[0]은 유형의 배열입니다 int *[5]. expression x[0]은 expression 과 동일 하다는 점을 고려하십시오 *x. 즉, 배열에 대한 포인터를 참조하여 배열 자체를 얻습니다. 선언처럼 y와 같이 표시하자

int * y[5];

표현식은와 x[0][0]동일하며 y[0]유형이 int *있습니다. 우리가 선언을했다 z와 같이 표시하자

int *z;

expression x[0][0][0]y[0][0]expression z[0]과 동등하며 expression 과 동등하며 type을 갖습니다 int.

그래서 우리는

x[0] 유형이있다 int *[5]

x[0][0] 유형이있다 int *

x[0][0][0] 유형이있다 int

따라서 그것들은 다른 유형의 객체와 다른 크기의 객체입니다.

예를 들어 실행

std::cout << sizeof( x[0] ) << std::endl;
std::cout << sizeof( x[0][0] ) << std::endl;
std::cout << sizeof( x[0][0][0] ) << std::endl;

10

가장 먼저 말해야 할 것은

x [0] = * (x + 0) = * x;

x [0] [0] = * (* (x + 0) +0) = ** x;

x [0] [0] [0] = * (* (* (x + 0) +0)) = *** x;

따라서 * x ≠ * * x ≠ * * * x

다음 그림에서 모든 것이 명확합니다.

  x[0][0][0]= 2000

  x[0][0]   = 1001

  x[0]      = 10

여기에 이미지 설명을 입력하십시오

x [0] [0] [0] = 10 인 경우의 예일뿐입니다.

그리고 어드레스 X [0] [0] [0] 이다 1,001

해당 주소는 x [0] [0] = 1001에 저장됩니다.

x [0] [0]의 주소 는 2000입니다

그 주소는 x [0] = 2000에 저장됩니다

따라서 x [0] [0] [0] x [0] [0] x [0]

.

편집

프로그램 1 :

{
int ***x;
x=(int***)malloc(sizeof(int***));
*x=(int**)malloc(sizeof(int**));
**x=(int*)malloc(sizeof(int*));
***x=10;
printf("%d   %d   %d   %d\n",x,*x,**x,***x);
printf("%d   %d   %d   %d   %d",x[0][0][0],x[0][0],x[0],x,&x);
}

산출

142041096 142041112 142041128 10
10 142041128 142041112 142041096 -1076392836

프로그램 2 :

{
int x[1][1][1]={10};
printf("%d   %d   %d   %d \n ",x[0][0][0],x[0][0],x[0],&x);
}

산출

10   -1074058436   -1074058436   -1074058436 

3
당신의 대답은 오도의 소지가 있습니다. x[0]개미 주소가 포함되어 있지 않습니다. 배열입니다. 첫 번째 요소를 가리 키기 위해 부패합니다.
haccks

음 ... 무엇을 의미합니까? 당신의 편집은 잘못된 답변에 케이크에 체리와 같습니다. 말이 안
돼요

@haccks 포인터 만 사용한다면이 대답이 옳습니다. Array 사용시 주소 섹션에 약간의 변화가있을 것입니다
apm

7

실제 관점에서 배열을 볼 경우 다음과 같이 나타납니다.

x[0]상자로 가득한화물 컨테이너입니다.
x[0][0]화물 컨테이너 안에 신발 상자로 가득 찬 단일 상자입니다.
x[0][0][0]상자 안에,화물 컨테이너 안에있는 단일 신발 상자입니다.

화물 컨테이너의 유일한 상자에있는 유일한 신발 상자 였음에도 불구하고 여전히화물 컨테이너가 아닌 신발 상자입니다


1
하지 않을 x[0][0]그들에 쓰여진 신발 상자의 위치가 종이 조각이 가득 하나의 상자가 될?
wchargin

4

C ++에는 다음과 같은 원칙이 있습니다. 변수 선언은 변수를 사용하는 방법을 정확하게 나타냅니다. 선언을 고려하십시오.

int *(*x)[5];

(더 명확하게) 다음과 같이 다시 작성할 수 있습니다.

int *((*x)[5]);

원칙으로 인해 다음과 같은 이점이 있습니다.

*((*x)[i]) is treated as an int value (i = 0..4)
 (*x)[i] is treated as an int* pointer (i = 0..4)
 *x is treated as an int** pointer
 x is treated as an int*** pointer

따라서:

x[0] is an int** pointer
 x[0][0] = (x[0]) [0] is an int* pointer
 x[0][0][0] = (x[0][0]) [0] is an int value

차이를 알아낼 수 있습니다.


1
x[0]포인터가 아닌 5 int의 배열입니다. (대부분의 상황에서 포인터로 쇠퇴 할 수 있지만 여기서 구별이 중요합니다).
MM

x [0]은 5 개의 포인터 int *의 배열입니다
Nghia Bui

@MattMcNabb 당 올바른 유도을 제공하려면 : *(*x)[5]입니다 int그래서, (*x)[5]입니다 int *때문에, *x입니다 (int *)[5]때문에, x입니다 *((int *)[5]). 즉, x에 대한 포인터의 5 개 배열에 대한 포인터 int입니다.
wchargin

2

다른 유형을 값으로 비교하려고합니다.

주소를 가져 가면 예상보다 더 많은 것을 얻을 수 있습니다

선언에 차이가 있음을 명심하십시오.

 int y [5][5][5];

이후, 원하는 비교를 허용 것 y, y[0], y[0][0], y[0][0][0]서로 다른 값 및 유형하지만 같은 주소를 가질 것

int **x[5];

인접한 공간을 차지하지 않습니다.

xx [0]같은 주소를 가지고 있지만, x[0][0]x[0][0][0]다른 주소에서 각각


2
int *(*x)[5]와 다른int **x[5]
MM

2

p포인터 : 당신이 역 참조를 적재하고 p[0][0]에 해당하는 *((*(p+0))+0).

C 참조 (&) 및 역 참조 (*) 표기법에서 :

p == &p[0] == &(&p[0])[0] == &(&(&p[0])[0])[0])

다음과 같습니다.

p == &*(p+0) == &*(&*(p+0))+0 == &*(&*(&*(p+0))+0)+0

& *를 리팩토링하고 제거하면됩니다.

p == p+0 == p+0+0 == p+0+0+0 == (((((p+0)+0)+0)+0)+0)

첫 번째 문장 이후에 모든 것을 보여 주려고 무엇입니까? 에 대한 많은 변형이 있습니다 p == p . &(&p[0])[0]와 다른p[0][0]
MM

x가 포인터 일 때 남자는 왜 'x [0]! = x [0] [0]! = x [0] [0] [0]'을 물었습니다. 나는 그가 [0]을 쌓을 때 C의 역 참조 표기법 (*)에 갇힐 수 있음을 보여 주려고 노력했다. 따라서 x가 x [0]이되도록 올바른 표기법을 보여 주려고 시도하고 x와 다시 x [0]을 다시 참조하는 식입니다.
Luciano

1

다른 대답은 정확하지만 그중 어느 것도 세 가지 모두가 같은 가치를 포함 할 수 없다는 생각을 강조하지 않으므로 어떤 방식 으로든 불완전합니다.

이것이 다른 답변에서 이해할 수없는 이유는 대부분의 상황에서 도움이되고 확실히 합리적이지만 모든 그림이 포인터 x자체를 가리키는 상황을 다루지 않기 때문 입니다.

이것은 구성하기가 쉽지만 이해하기가 다소 어렵습니다. 아래 프로그램에서 세 값을 모두 동일하게 만드는 방법을 살펴 보겠습니다.

참고 : 이 프로그램의 동작은 정의되지 않습니다,하지만 난 포인터가 무언가 흥미로운 데모로 순수 여기를 게시하도록하겠습니다 없지만, .

#include <stdio.h>

int main () {
  int *(*x)[5];

  x = (int *(*)[5]) &x;

  printf("%p\n", x[0]);
  printf("%p\n", x[0][0]);
  printf("%p\n", x[0][0][0]);
}

C89 및 C99에서 경고없이 컴파일되며 출력은 다음과 같습니다.

$ ./ptrs
0xbfd9198c
0xbfd9198c
0xbfd9198c

흥미롭게도 세 값은 모두 동일합니다. 그러나 이것은 놀라운 일이 아닙니다! 먼저 프로그램을 분석해 봅시다.

x각 요소가 int에 대한 포인터 유형 인 5 개의 요소 배열에 대한 포인터로 선언 합니다. 이 선언은 런타임 스택에 4 바이트를 할당하거나 구현에 따라 4 바이트를 할당하므로 내 컴퓨터 포인터는 4 바이트이므로 x실제 메모리 위치를 나타냅니다. C 언어 군에서, 그 내용 x은 단지 쓰레기 일 뿐이며, 이전에 사용했던 장소에서 남은 것이므로, 그 x자체는 어느 곳도 가리 키지 않습니다. 분명히 할당 된 공간이 아닙니다.

따라서 자연스럽게 변수의 주소를 x가져다가 어딘가에 놓을 수 있습니다. 이것이 바로 우리가하는 일입니다. 그러나 계속해서 x 자체에 넣겠습니다. &x와 유형이 다르기 때문에 x캐스트를해야 경고가 표시되지 않습니다.

메모리 모델은 다음과 같습니다.

0xbfd9198c
+------------+
| 0xbfd9198c |
+------------+

따라서 주소의 4 바이트 메모리 블록 0xbfd9198c에는 16 진수 값에 해당하는 비트 패턴이 포함 0xbfd9198c됩니다. 충분히 간단합니다.

다음으로 세 가지 값을 인쇄합니다. 다른 답변은 각 표현이 무엇을 의미하는지 설명하므로 관계가 명확해야합니다.

값이 동일하지만 매우 낮은 수준에서만 비트 패턴이 동일하지만 각 식과 관련된 형식 데이터는 해석 된 값이 다르다는 것을 알 수 있습니다. 예를 들어, x[0][0][0]format string을 사용하여 인쇄 %d하면 큰 음수를 얻게되므로 실제로 "값"은 달라 지지만 비트 패턴은 동일합니다.

다이어그램에서 화살표는 다른 메모리 주소가 아닌 동일한 메모리 주소를 가리 킵니다. 그러나 정의되지 않은 동작으로 인해 예상되는 결과를 도출 할 수 있었지만 정의되지 않은 것입니다. 이것은 프로덕션 코드가 아니라 완벽을 기하기위한 데모입니다.

합리적인 상황에서 malloc5 int 포인터의 배열을 만들고 해당 배열에서 가리키는 int를 다시 만드는 데 사용합니다. malloc항상 고유 한 주소를 반환합니다 (메모리가 없으면 NULL 또는 0을 반환하지 않는 한). 이와 같은 자기 참조 포인터에 대해 걱정할 필요가 없습니다.

바라건대 그것은 당신이 찾고있는 완전한 대답입니다. 당신은 기대하지 말아야 x[0], x[0][0]그리고 x[0][0][0]동일하게하지만, 강제로 한 경우에는이 될 수 있습니다. 머릿속에 무언가가 있으면 알려주세요.


내가 본 것 중 또 다른 이상한 포인터 사용이라고 말하고 싶습니다.
haccks

@haccks 그래, 꽤 이상하지만, 분해 할 때 다른 예제와 마찬가지로 기본입니다. 비트 패턴이 모두 동일한 경우에 발생합니다.
Purag

코드에서 정의되지 않은 동작이 발생합니다. x[0]실제로 올바른 유형의 유효한 객체를 나타내지 않음
MM

@MattMcNabb 그것은 정의되지 않았으며 실제로 그것에 대해 매우 분명합니다. 유형에 대해 동의하지 않습니다. x는 배열에 대한 포인터이므로 []연산자를 사용하여 해당 포인터에서 오프셋을 지정하고 역 참조 할 수 있습니다. 뭐가 이상해? 결과 x[0]는 배열이며 C를 사용하여 인쇄하면 C가 불만을 제기하지 않으므로 %p어쨌든 아래에서 구현됩니다.
Purag

그리고 이것을 -pedantic플래그로 컴파일하면 경고가 생성되지 않으므로 C는 다음과 같은 유형에 적합합니다.
Purag

0

의 유형 int *(*x)[5]int* (*)[5]즉 int에 대한 5 개의 포인터 배열에 대한 포인터입니다.

  • xint에 대한 5 개의 포인터로 구성된 첫 번째 배열의 주소입니다 (유형이있는 주소 int* (*)[5]).
  • x[0]int에 대한 5 개 포인터의 첫 번째 배열 주소 (유형이 동일한 주소 int* [5]) (offset address x, 0*sizeof(int* [5])즉 index * size-of-type-being-pointed-to-dereference)
  • x[0][0]배열의 int에 대한 첫 번째 포인터입니다 (유형이 동일한 주소 int*) (주소 x by 0*sizeof(int* [5])및 역 참조, 그리고 by 0*sizeof(int*)및 역 참조의 오프셋 주소 ).
  • x[0][0][0]int에 대한 포인터가 가리키는 첫 번째 int입니다 (주소 x에 의해 오프셋 주소 x 0*sizeof(int* [5])및 역 참조 및 해당 주소로 0*sizeof(int*)dereference 및 오프셋 및 해당 주소로 dereference 및 오프셋 0*sizeof(int))

의 유형 int *(*y)[5][5][5]int* (*)[5][5][5]즉 int에 대한 5x5x5 포인터의 3d 배열에 대한 포인터입니다.

  • x 유형이 int 인 5x5x5 포인터의 첫 번째 3d 배열 주소입니다. int*(*)[5][5][5]
  • x[0]int에 대한 5x5x5 포인터의 첫 번째 3d 배열 주소 (offset address x by 0*sizeof(int* [5][5][5])및 dereference)
  • x[0][0]int에 대한 5x5 포인터의 첫 번째 2D 배열의 주소입니다 (주소 x 0*sizeof(int* [5][5][5])를 오프셋하고 참조를 해제하여 주소를 오프셋 0*sizeof(int* [5][5]))
  • x[0][0][0]int에 대한 5 개의 포인터로 구성된 첫 번째 배열의 주소입니다 (주소 x로 0*sizeof(int* [5][5][5])오프셋 및 주소를 역 참조 및 오프셋으로 주소로 0*sizeof(int* [5][5])오프셋 0*sizeof(int* [5])).
  • x[0][0][0][0]배열의 int에 대한 첫 번째 포인터입니다 (주소 x 기준 오프셋 0*sizeof(int* [5][5][5])및 역 참조 및 해당 주소 기준 0*sizeof(int* [5][5])오프셋 및 해당 주소 기준 0*sizeof(int* [5])및 오프셋 기준 오프셋 0*sizeof(int*))
  • x[0][0][0][0][0]int에 대한 포인터가 가리키는 첫 번째 int입니다 (오프셋 주소 x 기준 0*sizeof(int* [5][5][5])및 역 참조 및 해당 주소 기준으로 0*sizeof(int* [5][5])오프셋 및 해당 주소 기준으로 0*sizeof(int* [5])오프셋 및 해당 주소 기준으로 0*sizeof(int*)오프셋 및 해당 주소 기준 및 오프셋 기준으로 오프셋 0*sizeof(int))

배열 붕괴에 관해서 :

void function (int* x[5][5][5]){
  printf("%p",&x[0][0][0][0]); //get the address of the first int pointed to by the 3d array
}

이는 전달과 동일 int* x[][5][5]하거나 int* (*x)[5][5]그들에게 후자의 모든 부패를 즉. 이것이 x[6][0][0]함수에서 사용하기 위해 컴파일러 경고를 얻지 않지만 x[0][6][0]그 크기 정보가 보존되기 때문에 그렇게 할 것입니다

void function (int* (*x)[5][5][5]){
  printf("%p",&x[0][0][0][0][0]); //get the address of the first int pointed to by the 3d array
}
  • x[0] int에 대한 5x5x5 포인터의 첫 번째 3d 배열 주소입니다.
  • x[0][0] int에 대한 5x5 포인터의 첫 번째 2d 배열 주소입니다.
  • x[0][0][0] int에 대한 5 개의 포인터로 구성된 첫 번째 배열의 주소입니다.
  • x[0][0][0][0] 배열의 int에 대한 첫 번째 포인터입니다.
  • x[0][0][0][0][0] int에 대한 포인터가 가리키는 첫 번째 int입니다.

마지막 예에서, *(*x)[0][0][0]대신에 의미 적으로 사용하는 것이 훨씬 더 명확 x[0][0][0][0][0]합니다. 첫 번째와 마지막 [0]은 유형 때문에 다차원 배열에 대한 인덱스가 아닌 포인터 역 참조로 해석되기 때문입니다. 그러나 (*x) == x[0]의미에 관계없이 동일 합니다. *****x포인터를 5 번 역 참조하는 것처럼 보일 수도 있지만 실제로는 정확히 유형으로 인해 오프셋, 역 참조, 역 참조, 배열에 대한 2 오프셋 및 역 참조와 동일하게 해석됩니다. 작업을 적용하고 있습니다.

본질적으로 귀하 [0]또는 *a *가 아닌 배열 유형에 대해서는 우선 순위가 우선하기 때문에 오프셋 및 역 참조입니다 *(a + 0).

당신 때 [0]또는 배열 유형은 다음가 다음 나무 등의 역 참조를의 오프셋 (- 그것은 나무 등 동작의 역 참조는 같은 주소를 산출하기 위해 컴파일러에 의해 해결됩니다).**

당신 [0]이나 *1 차원 배열 유형을 가진 유형은 오프셋이며 역 참조입니다

당신 [0]이나 **2 차원 배열 유형 인 경우 오프셋 만, 즉 오프셋과 dem 등원 역 참조입니다.

귀하 [0][0][0]또는 ***3d 배열 유형 인 경우 오프셋 + dem 등원 역 참조, 오프셋 + dem 등원 역 참조, 오프셋 + dem 등원 역 참조, 역 참조입니다. 진정한 역 참조는 어레이 유형이 완전히 제거 된 경우에만 발생합니다.

int* (*x)[1][2][3]형식 의 예는 순서대로 래핑되지 않습니다.

  • x 유형이 있습니다 int* (*)[1][2][3]
  • *x유형이 있음 int* [1][2][3](오프셋 0 + dem 등원 역 참조)
  • **x유형이 있음 int* [2][3](오프셋 0 + dem 등원 역 참조)
  • ***x유형이 있음 int* [3](오프셋 0 + dem 등원 역 참조)
  • ****x유형이 있음 int*(오프셋 0 + 역 참조)
  • *****x유형이 있음 int(오프셋 0 + 역 참조)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.