programing

C 다차원 배열의 포인터 주소

lastcode 2023. 10. 4. 21:58
반응형

C 다차원 배열의 포인터 주소

저는 다차원 배열과 포인터를 만지작거리고 있습니다.저는 간단한 배열의 내용과 주소를 출력하는 프로그램을 보고 있었습니다.제 어레이 선언문은 다음과 같습니다.

int zippo[4][2] = { {2,4},
            {6,8},
            {1,3},
            {5,7}   };

이해하는 로는,zippo는 포인터이며 다른 포인터 몇 개의 주소를 저장할 수 있습니다.으로,zippo합니다의 합니다.zippo[0]의 주소인 도 할 수 있습니다.zippo[1],zippo[2],그리고.zippo[3].

자, 다음과 같은 말을 들어보겠습니다.

printf("zippo[0] = %p\n", zippo[0]);
printf("  *zippo = %p\n", *zippo);
printf("   zippo = %p\n", zippo);

내 컴퓨터에서 다음과 같은 출력이 나옵니다.

zippo[0] = 0x7fff170e2230
  *zippo = 0x7fff170e2230
   zippo = 0x7fff170e2230

합니다의 이유를 합니다.zippo[0]그리고.*zippo같은 가치를 가지다 2 둘 다 포인터이며 기본값 2 의 주소( 저장합니다) 둘 다 정수합니다.zippo[0][0]왜 그래요? 요?zippo또한 같은 메모리 주소를 공유하고 있습니까? 돼요zippo다의 .zippo[0] 뭐라고요?

배열 표현식이 대부분의 컨텍스트에서 나타날 때, 그 유형은 "T의 N-element array"에서 "T로의 포인터"로 암묵적으로 변환되고, 그 값은 배열의 첫 번째 요소를 가리키도록 설정됩니다.의 피연산자인 입니다.sizeof&연산자 또는 배열이 선언에서 이니셜라이저로 사용되는 문자열 리터럴인 경우.

zippoint [4][2] 어레이) ~ (열의 열 에서int (*)[2](인트의 2-element 배열에 포인터).마찬가지로, 다음과 같은 유형의zippo[0]이다.int [2] 암묵적으로 됩니다.int *.

,int zippo[4][2] 및 즉, 는 zippo .

식 유형이 해당 식으로 암묵적으로 변환됨----------    ----            -----------------------  ---------------------지퍼[4][2] int(*)[2]&zipoint(*)[4][2]*지포[2] int * 지포[0]zippo[i] int [2] int *&zipo[i] int(*)[2]*zippo[i] intzippo[i][0]지포[i][j]int&zippo[i][j] int **zippo[i][j] 유효하지 않음

:zippo,&zippo,*zippo,zippo[0],&zippo[0],그리고.&zippo[0][0]모두 동일한 값을 갖습니다. 모두 배열의 맨 아래 부분을 가리킵니다(배열의 주소는 배열의 첫 번째 요소의 주소와 동일합니다).하지만 다양한 표현의 종류는 모두 다릅니다.

다차원 배열을 선언하면 컴파일러는 이 배열을 단일 차원 배열로 취급합니다.다차원 배열은 우리의 삶을 더 쉽게 만들기 위한 추상적인 것에 불과합니다.오해하고 있습니다.이것은 4개의 어레이를 가리키는 하나의 어레이가 아니라, 항상 하나의 연속적인 메모리 블록일 뿐입니다.

당신의 경우 다음을 수행합니다.

int zippo[4][2]

하는 것과 정말 같습니다.

int zippo[8]

컴파일러가 2D 어드레싱에 필요한 연산을 처리합니다.

자세한 내용은 C++의 배열에 대한자습서를 참조하십시오.

이는 다음과 크게 다릅니다.

int** zippo

아니면

int* zippo[4]

이 경우에는 다른 배열에 할당할 수 있는 4개의 포인터의 배열을 만드는 것입니다.

zippo는 포인터가 아닙니다.배열 값의 배열입니다.zippo,그리고.zippo[i]위해서i값에서) 수 있습니다. 04에서는 특정한 경우(특히 값 컨텍스트에서) 포인터로 "decay"할 수 있습니다.ysizeof zippo를 들어,를 예로 zippo비가치적인 맥락에서이 경우에는.sizeof는 포인터의 크기가 아닌 배열의 크기를 보고합니다.

값 컨텍스트에서 배열의 이름은 첫 번째 요소의 포인터로 표시됩니다.그래서, 가치적 맥락에서,zippo.&zippo[0] 의 " " [2] 에 포인터" .int";*zippo는 , 와 .&zippo[0][0] "에 대한 , , "에 포인터.int는 같지만." 그들은 가치는 같지만 종류는 다릅니다.

두 번째 질문에 답하려면 배열 포인터를 읽는 것이 좋습니다.포인터의 "값"은 같지만 공간의 양은 다릅니다.인쇄 시도zippo+1그리고.*zippo+1그것을 더 명확하게 볼 수 있습니다.

#include <stdio.h>

int main(void)
{
    int zippo[4][2] = { {2,4}, {6,8}, {1,3}, {5,7} };
    printf("%lu\n", (unsigned long) (sizeof zippo));
    printf("%p\n", (void *)(zippo+1));
    printf("%p\n", (void *)(*zippo+1));
    return 0;
}

내가 도망칠 때는 다음과 같이 출력합니다.

32
0xbffede7c
0xbffede78

을 해주니깐.sizeof(int)내 기계에서 4이고 두번째와 세번째 포인터의 값이 같지 않습니다(예상대로).

."%p"svoid *인에*printf() 당신은 당신의 들,다에 .void *n에printf()printf()는 가변 함수이므로 컴파일러가 자동 변환을 수행할 수 없습니다.

편집: 배열이 포인터에 "흔들어진다"고 말하면 값 컨텍스트에서 배열의 이름이 포인터와 동일하다는 의미입니다.따라서, 만약 내가T pt[100]; 타입의 T에 이름, ㅇpt입니다.T *가치적인 맥락에서 말입니다.sizeofd&자,자pt포인터로 축소되지 않습니다.하지만 당신은 할 수 있습니다.T *p = pt;는 이러한 , 합니다이기 pt입니다.T *.

이 "쇠락"은 한 번만 일어난다는 것에 유의하세요.자, 예를 들면 다음과 같습니다.

int zippo[4][2] = { {2,4}, {6,8}, {1,3}, {5,7} };

그리고나서,zippo in value context의 는 유형의 포인터로 붕괴합니다.열[2]합니다.int 코드명:

int (*p1)[2] = zippo;

유효한 반면에

int **p2 = zippo;

incomp 호환 포인터 할당" 경고를 트리거합니다.

와 함께zippo되며,

int (*p0)[4][2] = &zippo;
int (*p1)[2] = zippo;
int *p2 = zippo[0];

모두 유효합니다.다를 할 때 .printf("%p\n", (void *)name); 포인터들은 정수를 에서 다릅니다 , .

은 그 입니다.int zippy[4][2]다와(와) 다른 입니다.int **zippo.

처럼.int zippi[5],zippy메모리 블록의 주소입니다.그러나 컴파일러는 당신이 8개의 메모리 위치를 다루기를 원한다는 것을 알고 있습니다.zippy으로 .나 5다.zippi일차원적인 구문으로

zippo완전히 다른 것입니다. 개의 포인터를 포함할 수 있을 정도로 충분히 큰 메모리 블록의 주소를 보유하고 있으며 정수의 일부 배열을 가리키게 할 경우 2차원 배열 액세스 구문을 사용하여 참조를 해제할 수 있습니다.

잘해 주었는데, , 할 때 좀 더 .zippo아니면zippo[0]아니면zippo[0][0]한 기본 주소인 를 .zippo는 여러 어레이가 항상 연속된 메모리 블록이고 다차원 어레이가 연속적으로 배치되는 이유는 여러 단일 차원 어레이입니다.

할에는 포인터 int *p = &zippo[0][0], ㅇp++포인터가 행 단위로 증가합니다.에서 id는 4 X 2이고,4 X 2 배열입니다.p++의 두 번째 재 4다를 있습니다

언급URL : https://stackoverflow.com/questions/2003745/pointer-address-in-a-c-multidimensional-array

반응형