2011-02-14 2 views
9

를 역 참조 나는 char **문자 ** 포인터

내 혼란을 종료 하시겠습니까?

나는 char *이 char에 대한 포인터이며 char *array[]은 char 포인터의 배열이지만 정확히 char **은 어떻게 처리합니까?

또한 dereferences라는 단어가 나왔을 때 포인터가 제거되었다고 생각하는 이유는 정확히 포인터를 역 참조하는 것이 무엇입니까? 포인터가 가리키는 값을 변경합니까? 포인터를 역 참조

덕분

답변

10

같은 메모리 할당 기능/조작자로부터 오는 포인터, 포인터가 가리키는 값에 액세스하는 수단 "역 참조". 다음의 선언을 가정

int a = 10; 
int *p = &a; 

여기서 두 변수의 가상 메모리 맵이다 :

 
Item  Address  0x00 0x01 0x02 0x03 
----  -------  ---- ---- ---- ---- 
    a  0x80001000 0x00 0x00 0x00 0x0A 
    p  0x80001004 0x80 0x00 0x10 0x00 

a 10. pa (0x80001000)의 어드레스를 포함하는 정수 값을 포함한다. a부터 p까지의 내용에 액세스하려면 p의 간접 참조 연산자 *을 참조하십시오. 따라서 식 *p은 식 a과 같습니다.

#include <stdlib.h> 
#define N  20 // For this example, we will allocate 20 strings 
#define LENGTH 10 // of 10 characters each (not counting 0 terminator) 
... 
char **arr = malloc(sizeof *arr * N); 
if (arr) 
{ 
    size_t i; 
    for (i = 0; i < N; i++) 
    { 
    arr[i] = malloc(sizeof *arr[i] * (LENGTH + 1)); 
    strcpy(arr[i], "   "); 
    } 
} 
: 우리가

a = 16; 

를 작성하는 것과 같은입니다

*p = 16; 

을 썼다면 여기에 문자열 배열을 만들 형 char **의 객체를 사용하는 방법을 보여주는 코드의 짧은 조각이다

줄 단위로 이동,

char **arr = malloc(sizeof *arr * N); 

은 문자 (sizeof *arr == sizeof (char *) 유형이 *arr == char *이므로)를 가리키는 데 충분한 N 개의 요소 블록을 할당하고 결과 포인터 값을 arr에 할당합니다. IOW, arrchar에 대한 첫 번째 포인터를 가리 킵니다. 따라서 char ** 유형입니다. 당신은 선언과 함수 호출을 분리하는 경우, 그렇지 않은 것을 arr에, 우리는 arrmalloc의 결과를 할당 할

char **arr; 
... 
arr = malloc(sizeof *arr * N); 

과 같을 것이다합니다.

if (arr) 

malloc이 실패하는 것이 가능, 그래서 우리는 그것을 사용하기 전에 결과를 확인하고 싶습니다. malloc 이벤트가 실패하면 NULL 포인터 값을 반환합니다.(; sizeof (char)는 항상 1이므로주의 *arr[i] == char의 타입 때문에, sizeof *arr[i] == sizeof (char))

각 문자 포인터 arr[i] 들어
{ 
    size_t i; 
    for (i = 0; i < N; i++) 
    { 
    arr[i] = malloc(sizeof *arr[i] * (LENGTH + 1)); 

우리 LENGTH + 1 개 요소에 대해 충분히 큰 각각은 char 값을 저장하기에 충분히 큰 메모리 블록을 할당 결과를 arr[i]에 할당하십시오.

각 문자열을 별도의 malloc 호출로 할당하므로 메모리에 인접하지는 않습니다. 여기에서 상기 코드의 가능한 결과 도시 다른 메모리 맵이다 ". *의 P1의 == C를, 즉 비 참조 P1은 우리 /로부터 판독 ℃로 쓸 수"

 
Item   Address  0x00 0x01 0x02 0x03 
----   -------  ---- ---- ---- ---- 
arr   0x80001000  0xA0 0xCC 0x00 0x00 
      ... 
arr[0]  0xA0CC0000  0xA0 0xCC 0x20 0x00  
arr[1]  0xA0CC0004  0xA0 0xCC 0x20 0x40 
arr[2]  0xA0CC0008  0xA0 0xCC 0x21 0x28 
      ... 
arr[19]  0xA0CC0014  0xA0 0xCC 0x23 0x10 
      ... 
arr[0][0] 0xA0CC2000  ' ' ' ' ' ' ' ' 
arr[0][4] 0xA0CC2004  ' ' ' ' ' ' ' ' 
arr[0][8] 0xA0CC2008  ' ' ' ' 0x00 0x?? 
      ... 
arr[1][0] 0xA0CC2040  ' ' ' ' ' ' ' ' 
arr[1][4] 0xA0CC2044  ' ' ' ' ' ' ' ' 
arr[1][8] 0xA0CC2048  ' ' ' ' 0x00 0x?? 
      ... 
+1

미안해, 내가 어쩌면 틀렸어.하지만 배정 후에 완전히 정리하려면 총 문자열 수와 자유 arr [i ]뿐만 아니라 전체 배열 free (arr)를 해제하는 것이 맞습니까? 아니면'자유 (arr)만으로 충분할까? '? –

3

포인터를 값을 포인트에 액세스하는 것을 의미한다. 예를 들어,

char c = 'c'; // This is a primitive value. You cannot dereference it. 
char* p1 = &c; // A pointer to the address of c 
char** p2 = &p1; // A pointer to the address of p1 
/* Now, the following is true: 
*p1 == c, i.e. dereferencing p1 allows us to read from/write to c. 
*p2 == p1 
**p2 == *(*p2) == *p1 = c - dereferencing p2 twice is c, too */ 

대신 C를 C에 대한 포인터를 사용하는 이유는 직접 포인터는 1 개 이상의 값에 액세스 할 수 있다는 것입니다. 이 예를 들면 다음과 같습니다.

char[4] str; 
char c0 = 'a', c1 = 'b', c3 = 'c', c4 = '\0'; 
str[0] = c0; str[1] = c1; str[2] = c2; str[3] = c3; 
str = "abc"; // Same as the above line 

이제 두 번째 문자가 필요하다고 가정합니다. c1으로 액세스 할 수 있습니다. 그러나 보시다시피,이 표기법은 정말 귀찮습니다. 또한 파일에서 문자열을 읽는 대신 파일에서 읽는다면 복잡한 작업을해야합니다. 대신, 우리는 첫 번째 요소는 인덱스 0, 두 번째 일을 가지고

str[1] /* or */ *(str+1) 

주 쓰기 - 우리가 여기에 1을 사용하는 이유가 있습니다. char**은 이것을 11까지 바꿉니다. 우리는 char 배열을 가지고 있습니다. 우리가 배열을 가지고 있다고 가정하고, 그것을 input이라고하고, 그 안에있는 모든 문자열의 길이를 찾아야합니다. 이 방법은 다음과 같습니다.

int lensum(char **input) { 
    int res = 0; 
    while (*input) { // This loops as long as the value input points to is not 0. 
     char* p = *input; // Make a copy of the value input currently points to 
     while (*p != '\0') { // Loop while the copy does not point to a char '\0' 
      res += 1; // We found a character 
      p++; // Check next character in the next iteration 
     } 
     input++; // Check next string in the next iteration 
    } 
    return res; 
} 
+0

은 어떤 라인이 완성 되었습니까? char * p1 = & c; ? – jarryd

+0

@alJaree 정확히. & c는 c의 주소입니다. – phihag

9

포인터는 실제 값을 보유하는 대신 주소에 값을 저장하는 유형입니다.

char * p의 경우 한 번 할당하면 p에는 주소 A가 포함됩니다. 포인터를 역 참조한다는 것은 주소 A에 저장된 값을 액세스한다는 의미입니다. char *에 문자열을 저장할 수있는 이유는 다음과 같습니다. 할당 된 메모리는 연속적입니다. 따라서 A는 첫 번째 문자를 저장하는 주소이고 A + 1은 두 번째 문자를 저장하는 주소입니다.

char ** pp의 경우 char * 주소를 저장합니다. 이 주소 B를 호출하십시오. 따라서 dereferencing pp는 주소 B의 값을 액세스하는 것을 의미합니다.이 주소는 char * 일 수 있으며, 이는 문자열을 보유하게됩니다. 마찬가지로 B + 1 (실제로 B + sizeof (char *))은 다른 문자열 인 다음 값을 저장합니다.

pp를 두 번 다시 참조하면 (예 : ** pp) 주소 B의 값 (예 : A)에 액세스 한 다음 다시 한 번 참조 해제하여 다시 문자 A의 값을 가져 오는 것을 의미합니다.

+0

정말 좋은 설명입니다. 감사. – jarryd

3

다이어그램의 길이는 1000 단어입니다. 살펴보기 here

char, char * 및 char **는 변수 (메모리 영역)에 포함 된 것을 설명하는 유형입니다.

변수와 같은 역 참조를 사용하면 실제로 변수의 값을 메모리 주소로 처리하고 실제로 해당 주소의 값을 반환합니다. 이는 간접 참조입니다.

** 변수는 간접적 인 두 수준입니다. 즉, 변수 내의 값은 리턴 될 데이터의 또 다른 메모리 어드레스의 메모리 어드레스이다.

주소 통상적 연산자 &의 주소 또는 new

+1

고마워 :) 5 더 가야 .. : P – jarryd