2012-11-15 6 views
2

이 주제는 이미 여러 번 논의되었으며 기본적으로 배열과 포인터의 차이점을 알고 있다고 생각하지만 배열이 mem에 정확히 저장되는 방법에 관심이 있습니다. 예를 들어const char ** name VS char * name []

:

const char *name[] = {"a","b","c"}; 
printf("Char: %c\n", name[0][0]); // Works well 

모든 것이 잘 밖으로 작동 :

const char **name = {{'a',0},{'b',0},{'c',0},0}; 
printf("Char: %c\n", name[0][0]); // This does not work 

하지만 이런 식으로 선언하면

.

+0

는 "이 작동하지 않습니다"무엇을 의미합니까? 첫 번째 예제를 컴파일하고 실행할 때 어떤 일이 발생합니까? –

+0

내 시스템에 이것은 seg 결함으로 이어질 것입니다. –

+3

흠, 심지어 첫 번째 샘플을 컴파일 할 수 없습니다 – billz

답변

2

문자열 리터럴은 암시 적으로 char const*으로 변환됩니다.

중괄호 이니셜 라이저는 그렇지 않습니다.

예제와 관련이 없지만 C++ 03까지 포함하여 문자열 리터럴도 이전 C와의 호환성을 위해 char* (const)으로 암시 적으로 변환 될 수 있지만 행복하게는 C++ 11 안전하지 않은 전환이 마지막으로 제거되었습니다.

+0

C++ 11에서 삭제했습니다. 할렐루야! – chris

1

첫 번째 스 니펫이 작동하지 않는 이유는 컴파일러가 문자 시퀀스를 포인터 값으로 다시 해석 한 다음 나머지 이니셜 라이저를 무시하기 때문입니다. 스 니펫을 작업하기 위해, 다음과 같이 자신을 당신은 당신이 배열을 선언하는 컴파일러에게 필요하고, 그 배열의 요소는 배열 것을 : 장소에서이 수정으로

const char *name[] = {(char[]){'a',0},(char[]){'b',0},(char[]){'c',0},0}; 

, 프로그램을 원하는 출력 (link to ideone)을 생성합니다.

1

첫 번째 예는 char에 대한 포인터에 대한 포인터를 선언합니다. 두 번째는 char에 대한 포인터 배열을 선언합니다. 차이점은 첫 번째 계층에는 간접 지정 계층이 하나 더 있다는 것입니다. 그림이 없으면 묘사하기가 약간 어렵습니다. 두 번째는,

 char *name[] = {"a","b","c"}; 

는 T1에 대해 동일한 코드를 생성 할 수있는 반면,

t1: .byte 'a', 0 
    .align somewhere; possibly somewhere convenient 
t2: .byte 'b', 0 
    .align 
t3: .byte 'c', 0 
    .align 
t4: .dword t1, t2, t3, 0 
name: .dword t4 

: 가짜 조립 스타일에서

,

char **name = {{'a',0},{'b',0},{'c',0},0}; 

같은 뭔가 번역 할 것 t2, t3을 제외하고는 다음과 같이 수행합니다.

name: .dword t1, t2, t3 

의미가 있습니까?

1

배열은 인접한 개체 시퀀스로 메모리에 저장됩니다. 여기서 개체 유형은 배열의 기본 형식입니다. 따라서, 어레이의 경우 :

const char *name[] = {"a","b","c"}; 

어레이의 기본 형태는 const char *하고 (검색 initialiser 세 요소를 가지고 있기 때문에) 배열의 크기는 3이다.

| const char * | const char * | const char * | 

배열의 요소는 포인터이며 실제 문자열은 배열에 저장되지 않습니다. 각 문자열은 char의 배열 인 문자열 리터럴입니다.

| 'a' | 0 | 
| 'b' | 0 | 
| 'c' | 0 | 

initialiser이 name 배열의 세 가지 요소를 설정하는 이들의 초기 요소를 가리 키도록이 경우, 그들은 당신이 세 가지 이름이 배열이 때문에 다른 곳에서 메모리에 두 char의 모든 배열이야 3 개의 이름없는 배열. name[0]'a'을 가리키고, name[1]'b'을 가리키고 name[2]'c'을 가리 킵니다. 당신이 변수가

char const* str = "abc"; 
char const** name = &str; 

처럼 이런 식으로 뭔가 보이는 정의 할 때

4

: 양식을 사용하여 변수를 정의 할 때

+---+  +---+ +---+---+---+---+ 
| *-+---->| *-+--->| a | b | c | 0 | 
+---+  +---+ +---+---+---+---+ 

char const* name[] = { "a", "b", "c" }; 

당신의 배열을 가지고 포인터. 이것은 그 같은 :

  +---+  +---+---+ 
      | *-+---->| a | 0 | 
      +---+  +---+---+ 
      | *-+---->| b | 0 | 
      +---+  +---+---+ 
      | *-+---->| c | 0 | 
      +---+  +---+---+ 

무엇 혼동 될 수있다 당신이 어딘가에이 배열을 통과 할 때, 그것은 포인터로 붕괴 것입니다 당신이있어 :이다

+---+  +---+  +---+---+ 
| *-+---->| *-+---->| a | 0 | 
+---+  +---+  +---+---+ 
      | *-+---->| b | 0 | 
      +---+  +---+---+ 
      | *-+---->| c | 0 | 
      +---+  +---+---+ 

, 당신이 얻을를 배열의 첫 번째 요소에 대한 포인터. 이 포인터를 증가 시키면 배열의 다음 요소로 이동합니다.

+0

매우 흥미 롭습니다. 그게 어떻게되는거야? 포인터가 다음 요소로 이동합니까? 그 배열과 배열에 대한 포인터가 동일한 행동을 의미합니다 –

+0

@QuicknDirty : 그것은 포인터가 정의되는 방법입니다 - 그것은 이전에 가리키고 있던 객체 다음의 다음 연속 객체를 가리 킵니다. 그러한 대상. 배열을 증가시킬 수는 없습니다. 배열에 대해 수행 할 수있는 유일한 작업은 초기화하고, 주소를'&'로 취하고, 크기를'sizeof'로 가져 와서 첫 번째 요소에 대한 포인터로 평가하는 것입니다. 배열을 사용하여 수행하는 모든 작업은 이러한 포인터를 통해 수행됩니다. – caf

+0

포인터와 배열에 동일한 방법으로 * 액세스 * 할 수 있지만 배열은 요소를 통해 * 반복 할 수 없습니다. 배열을 통해 이동하려면 포인터로 변환해야합니다. –

1

변수를 선언 할 때 어떤 일이 일어나는지, 그리고 변수에 대한 데이터를 저장할 메모리가 어디에 있는지 살펴야합니다.

첫째, 단순히 쓰는 것은 무엇을 의미 하는가 :

char x = 42; 

당신은 스택에 문자를 저장하기에 충분히 바이트를 얻고, 그 바이트, 42

둘째 값으로 설정하는 것을

char x[] = "hello"; 

당신이 스택에 6 바이트를 얻고, 그들이 문자 H, E, L, L, O, 값 0으로 설정됩니다 : 당신이 배열을 선언 할 때 발생합니다. 당신이 문자 포인터를 선언하는 경우

지금 무슨 일이 :

const char* x = "hello"; 

"안녕하세요"정적 메모리 어딘가에 저장하고, 충분한 바이트가 스택에 포인터를 얻을, 그 값에 대해 사용하는 바이트 문자열의 값을 보유하고있는 정적 메모리의 첫 번째 바이트 주소로 설정됩니다.

이제 두 번째 예와 같이 선언하면 어떻게됩니까? 정적 메모리, "a", "b"및 "c"에 저장된 세 개의 분리 된 문자열을 얻습니다.스택에서 세 포인터의 배열을 얻습니다. 각 포인터는 세 문자열의 메모리 위치로 설정됩니다.

첫 번째 예는 무엇입니까? 포인터의 배열에 대한 포인터를 원하는 것처럼 보입니다. 그러나 포인터의 배열은 어디로 갈 것입니까? 위의 포인터 예와 같습니다. 정적 메모리에 무언가를 할당해야합니다. 그러나 정적 메모리에서 2 차원 배열을 이와 같이 중괄호 초기화를 사용하여 선언 할 수없는 경우가 발생합니다. 함수 내에서 다음

const char* name_pointers[] = {"a", "b", "c"}; 

: 그래서 당신은 함수의 변수 외부로 배열을 선언하여 당신이 원하는 것을 할 수

const char** name = name_pointers;