2010-01-24 6 views
3
#include <stdio.h> 

int main(void){ 
    unsigned a[3][4] = { 
    {2,23,6,7}, 
    {8,5,1,4}, 
    {12,15,3,9} 
}; 
printf("%u",*((int*)(((char*)a)+4))); 
return 0; 
} 

내 컴퓨터에서 출력은 a[0][1]23 .Could 누군가의 값이이 작업 방법을 설명입니까? 이전 yucky 코드에 롤백, 정확히 무엇을 나에게 제시했다 : 편집이 포인터 연산은 어떻게 작동합니까?

P

+0

예, 오타되었습니다 : | –

+0

GMan의 게시물을 읽은 후 스 니펫을 편집했습니다. –

+0

감사합니다. :) 그것은 사람들을 혼란스럽게하고 우리가 준 응답을 무효로 만듭니다. 어떻게 모든 것이 합리적인지 계속해서 그래서 지나가는 사람은 질문에서 완전한 가치를 얻을 수 있었는지 질문을하십시오. 편집 : 훨씬 더. :) – GManNickG

답변

13

그래서 당신은 너무 메모리에 배열을 가지고 :

이가 배열을 캐스팅 무엇
2, 23, 6, 7, 8... 

2, 23, 6, 7, 8... 
^ 

그런 다음, 4 바이트를 추가합니다 (다음 값으로 더 많은 그것을 통해 이동 : 개별 바이트에 접근하고, 여기에서 지적 할 수있는 char*, 나중에).

2, 23, 6, 7, 8... 
^

은 그럼이 코드를 잘못 세 가지 기술적 있습니다 (23)


값을 받고, int*로 바뀌고을 역 참조.

는 그것이 unsigned 크기가 4 바이트 인 것으로 가정한다는 것이다. (따라서 + 4). 그러나 이것이 반드시 사실 일 필요는 없습니다! unsigned이 어떤 크기이든 상관없이 정확함을 보장하면 + sizeof(unsigned)이 좋을 것입니다.

두 번째 문제는 int으로 캐스팅되었습니다. 원래 배열은 unsigned이지만, 값은 int으로 캐스팅됩니다. 배열의 값 중 하나가 int (값이 INT_MAX보다 큼)을 나타낼 수없는 경우 int이 표시 할 수없는 unsigned 범위의 값이 있습니다 (범위의 반이 음수이므로 int이 음수이므로) , 당신은 틀린 가치를 얻을 것입니다. 올바른 유형을 유지하려면 unsigned*으로 변환하는 것이 더 낫습니다.

마지막 것은 형식 지정자입니다. 정수의 지정은 %d이지만, 코드는 부호없는 정수에 대한 인 %u를 사용합니다. 실제로, int* 다시 캐스팅에도 불구 것은 printf 그것은 무결성의 복원, unsigned*로 다시 값을 캐스팅 것입니다 잘못이었다. 문제 2를 수정하면 문제 3이 수정됩니다.

숨겨진 네 번째 문제가 있습니다 : 코드는 안됐다. 이것은 학습 목적 일 수도 있지만 yuck입니다.

+0

알았습니다! 감사합니다 :) –

+0

@nthgreek : 포인터 산술 : http://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BitOp/pointer.html –

+0

@GMan :'숨겨진 네 번째 문제가 있습니다. 코드가 싫습니다. . 이것은 학습 목적 일 수 있지만, 멍청이.'- 동의 : P –

2

는 먼저 암시 시작 부분에 대한 포인터로 배열 A를 변환한다. 그런 다음 포인터를 char *로 캐스팅하고 값을 4 씩 증가시킵니다. 값 4는 시스템에서 sizeof (부호없는)와 동일하므로 실제로는 시작 부분에서 한 요소를 앞으로 이동 시켰습니다. 그런 다음 주소를 int *로 변환하고 그 주소 (연산자 *)를 읽습니다. 이 결과 값은 int와 unsigned가 같은 크기이기 때문에 작동하는 부호없는 정수로 인쇄됩니다.

메모리에서 정적 2D 배열의 레이아웃은 모든 요소가 실제로 1 차원 배열로 순서대로 저장되도록합니다.

1

부호 INT 사이즈, 즉 제를 sizeof (부호 없음) ==의 4

가 바이트이고 각각의 4 개 문자, 수납 할 수있는 [C로하지 자바/C의 번호 등].

배열은 연속적으로 메모리에 할당됩니다. 서명되지 않은 배열을 char *로 처리 할 때는 배열에서 다음 무 부호 값에 도달하기 위해 포인터를 4 단계 이동해야합니다.

+0

'sizeof (unsigned) == 4' *이 경우에는 *, 반드시 모든 곳일 필요는 없습니다. 그것이 당신이 말하고자하는 의도 일 수 있습니다. – GManNickG

1

먼저 크기가 3x4 인 2 차원 배열을 만듭니다.

((char*)a) 이후에는이 문자 배열로 작업 할 수 있습니다. b로 지정합시다.

((char*)a)+4 그것은 문자 배열의 5 번째 요소 (는 C에서 0이 aarays 기반 것을 기억)을 가리키는, b[4] 동일하다. 또는 단지 5 번째 바이트.

배열을 다시 int로 변환하면 i-th int 배열의 요소는 sizeof(int) = 4 인 경우 i*4 바이트에서 시작합니다. 그래서, 5 번째 바이트에서 int 배열의 두 번째 요소가 포인터가 가리키는 곳에서 시작됩니다. 컴파일러는 4 번째 위치부터 4 바이트를 가져오고 int라고 말합니다. 그건 정확히 [0] [1]입니다.

9

배열 :

0x8000 0 0 0 2 
0x8004 0 0 0 23 
0x8008 0 0 0 6 
0x800C 0 0 0 7 
0x8010 0 0 0 8 
0x8014 0 0 0 5 
0x8018 0 0 0 14 
0x801C 0 0 0 12 
0x8020 0 0 0 15 
0x8024 0 0 0 3 
0x8028 0 0 0 9 
:

unsigned a[3][4] = { 
    {2,23,6,7}, 
    {8,5,1,4}, 
    {12,15,3,9} 
}; 

는 (자체가 메모리 위치 0x8000 특정 엔디안에있다 a 가정하고 4 바이트 int 용)로서 메모리에 뻗어

표현 깨기 :

*((int*)(((char*)a)+4)) 
  • ((char*)a)char 포인터를 제공합니다.
  • (int*)int 포인터에 그 결과를 다시 턴 4 바이트 (4 * sizeof(char))에 의해 포인터
  • +4 진보.
  • *int의 포인터를 역 참조합니다.

는 이것은 본질적으로 비 - 휴대용 이후 (AN int 예를 들면, 두 개 또는 8 바이트 환경)을 수행하는 매우 바보 같은 방법이다.

+1

+1 배열 메모리 레이아웃이 내 것보다 굉장한 것 같아서. – GManNickG

+0

좋은 설명 +1! :) –

+0

@ GMAN : 맞습니다. paxdiablo의'배열 메모리 레이아웃은 굉장합니다.'하지만이 행을 읽은 후에 해답을 얻었습니다.'배열이 char *로 캐스팅되어 개별 바이트에 액세스 할 수 있습니다 .') –

관련 문제