[C언어] 2차원배열의 각 셀 접근방식과 관련된 2차원 포인터..
C에서
type data[row최대값 A ][column 최대값 B] 과 같은
배열이 존재할때
data[2][3] 인경우엔
셀 접근 방식이
data첫주소 + (2*column 최대값 B + 3)*sizeof(type)
으로 된다는 사실을 확인해보고 싶었습니다.
#include <stdio.h> int main(){ char data[2][5] = {1,2,3,4,5,6,7,8,9,0}; char *p = data; char (*p2)[5] = data; char (*p3)[10] = data; char **p4 = data; printf("%d\n",data); printf("%d\n",*(p+5)); printf("%d\n",*(p2+1)); printf("%d\n",*(p3+1)); printf("%d\n",*(p4+1)); return 0; } 결과 1245044 <- data배열의 첫주소입니다. 6 <- 6번째 값입니다. 1245049 <- 첫주소 + 5 입니다. 1245054 <- 첫주소 + 10입니다. 134678021 <- 첫주소 + ? 입니다.
위 소스는 vc6.0 에서
--------------Configuration: 2 - Win32 Debug-----------------
Compiling...
2.c
C:\Documents and Settings\Home\바탕 화면\2.c(6) : warning C4047: 'initializing' : 'char *' differs in levels of indirection from 'char (*)[5]'
C:\Documents and Settings\Home\바탕 화면\2.c(8) : warning C4048: different array subscripts : 'char (*)[10]' and 'char (*)[5]'
C:\Documents and Settings\Home\바탕 화면\2.c(9) : warning C4047: 'initializing' : 'char ** ' differs in levels of indirection from 'char (*)[5]'
Linking...
2.exe - 0 error(s), 3 warning(s)
[/code]
당연히 경고가 뜹니다. C++에선 에러인데요
C에서는 에러로 취급되지는 않아서 위 소스를 가지고 테스트를
해봤습니다.
첫번째 찍히는값은 배열의 첫 주소입니다.
배열은 메모리상에서 linear하게 존재 하므로
아무리 2차원 배열의 주소라고 할지라도 포인터를 한번만
참조하게 되면 값에 도달 하는것이 가능할 것 같았습니다.
두번째 찍어본 값에 의해서 그 사실을 확일할 수 있었습니다.
세번째 내용에서는 포인터의 column 사이즈가 5로 지정이 되어있어서 원래의 data배열 첫주소에 5*sizeof(char)이 된것을 볼 수있었습니다.
네번째 내용에서는 포인터의 column 사이즈가 10으로 되어있으므로 (물론 column사이즈가 다르므로 data배열을 할당하는것은
잘못된것입니다.)
data배열 첫주소에 10*sizeof(char) 이 된것을 볼 수 있었습니다.
그런데 다섯번재 출력내용을 보면..
배열의 주소 참조 과정에서
data배열의 첫주소(data) + (1*?) * sizeof(char)
물음표에 해당하는 어떤 값이 곱해졌는지 궁금합니다.
답변부탁드립니다.
ps : vc6.0은 1989년에 발표된 ANSI C 표준을 따르는거 맞나요?
그렇다면 gcc도 마찬가지 인가요?
2차원 배열과 포인터의 포인터는 다릅니다.p4+1 라고 하면 p4
2차원 배열과 포인터의 포인터는 다릅니다.
p4+1 라고 하면 p4가 가리키는 주소(1245044겠죠?)에 포인터 크기인 char * 크기만큼을 더한 값(4라고 가정하죠)인 1245048이 되죠? 이 번지에 저장된 값을 주소로 해서 char *크기만큼을 읽은 값이 *(p4+1)이 됩니다.
134678021을 16진수로 적으면 0x08070605가 됩니다. 즉 위 배열에서 원래 data[4]에서 data[7]까지의 값을 little endian으로 읽은 셈이죠.
이런 코딩은 굳이 익히지 않으셔도 됩니다. -_-;;
답변감사합니다.
int 로 바꿔서 테스트 하고 나서야 그 이유를 알았습니다.
말씀하신대로
char (*p1)[10]; 형태의 배열에 관한 포인터의 주소처리는
배열의 주소 처리와 같지만
char **p2; 단일 2중포인터의 주소처리는 다르네요
결정적으로
*p1은 해당위치 메모리의 주소를 갖지만
*p2는 해당 위치에서부터 4바이트의 값을 갖는다는것을
알았습니다.
포인터 사이즈가 integer 랑 같으니 2가 출력되는것도 이상하지 않군요..
좋은 답변 감사합니다.
Re: [C언어] 2차원배열의 각 셀 접근방식과 관련된 2차원 포인터
printf로 주소값을 출력할 때는 반드시 "%p"를 사용하고 void* 형의 인자를 주어야 합니다. 위에서처럼 "%d"로 주소값을 출력하려고 하면 그 결과는 정의되지 않습니다.
VC 6.0의 C 컴파일러 부분은 1990년의 ISO C 표준을 따르는 것이 맞을 겁니다. (1989년의 ANSI C 표준과 1990년의 ISO C 표준은 내용상으로는 같습니다만, ANSI는 미국의 정부 기관일 뿐이고 ISO는 국제 표준 기구이므로 우리 입장에서는 "ANSI C"보다는 "ISO C"라는 표현을 사용하는 것이 더 바람직하다고 생각합니다. :) )
GCC는 1999년에 나온 ISO C 표준도 지원합니다. -std=c99 또는 -std=iso9899:1999 옵션을 주시면 C99 모드로 동작합니다. C99 지원이 완벽하지는 않은데, 지원 상황은 http://gcc.gnu.org/gcc-3.4/c99status.html에 나와 있습니다.
Re: [C언어] 2차원배열의 각 셀 접근방식과 관련된 2차원 포인터
포인터용 %p 가 있었군요..
그리고 담부턴 ISO C90으로 알아두겠습니다.
답변감사합니다.
댓글 달기