programing

왜 이중 간접을 사용하는가?아니면 왜 포인터에 포인터를 사용하는가?

goodsources 2022. 8. 3. 23:14
반응형

왜 이중 간접을 사용하는가?아니면 왜 포인터에 포인터를 사용하는가?

C에서 이중 간접을 사용해야 하는 경우는 언제입니까?예를 들어 설명할 수 있는 사람이 있나요?

내가 아는 건 이중 간접은 포인터에 대한 포인터라는 거야포인터에 대한 포인터가 왜 필요합니까?

를 는 문(어느 정도)를 사용하면 .char *word

(어느 정도)로 하다, 어(어느 정도)로 하다, 어(어느 정도?char **sentence

'어(어)로 하다'를 사용하시면 됩니다.char ***monologue

는, 「(을 할 수 .char ****biography

도서관 사용하실 수 .char *****biolibrary

이 한 경우 할 수 .char ******lol

... ...

네, 이것이 최적의 데이터 구조가 아닐 수도 있다는 것을 알고 있습니다.


매우 매우 지루한 사용 예(웃음)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int wordsinsentence(char **x) {
    int w = 0;
    while (*x) {
        w += 1;
        x++;
    }
    return w;
}

int wordsinmono(char ***x) {
    int w = 0;
    while (*x) {
        w += wordsinsentence(*x);
        x++;
    }
    return w;
}

int wordsinbio(char ****x) {
    int w = 0;
    while (*x) {
        w += wordsinmono(*x);
        x++;
    }
    return w;
}

int wordsinlib(char *****x) {
    int w = 0;
    while (*x) {
        w += wordsinbio(*x);
        x++;
    }
    return w;
}

int wordsinlol(char ******x) {
    int w = 0;
    while (*x) {
        w += wordsinlib(*x);
        x++;
    }
    return w;
}

int main(void) {
    char *word;
    char **sentence;
    char ***monologue;
    char ****biography;
    char *****biolibrary;
    char ******lol;

    //fill data structure
    word = malloc(4 * sizeof *word); // assume it worked
    strcpy(word, "foo");

    sentence = malloc(4 * sizeof *sentence); // assume it worked
    sentence[0] = word;
    sentence[1] = word;
    sentence[2] = word;
    sentence[3] = NULL;

    monologue = malloc(4 * sizeof *monologue); // assume it worked
    monologue[0] = sentence;
    monologue[1] = sentence;
    monologue[2] = sentence;
    monologue[3] = NULL;

    biography = malloc(4 * sizeof *biography); // assume it worked
    biography[0] = monologue;
    biography[1] = monologue;
    biography[2] = monologue;
    biography[3] = NULL;

    biolibrary = malloc(4 * sizeof *biolibrary); // assume it worked
    biolibrary[0] = biography;
    biolibrary[1] = biography;
    biolibrary[2] = biography;
    biolibrary[3] = NULL;

    lol = malloc(4 * sizeof *lol); // assume it worked
    lol[0] = biolibrary;
    lol[1] = biolibrary;
    lol[2] = biolibrary;
    lol[3] = NULL;

    printf("total words in my lol: %d\n", wordsinlol(lol));

    free(lol);
    free(biolibrary);
    free(biography);
    free(monologue);
    free(sentence);
    free(word);
}

출력:

내 lol의 총 단어 수: 243
  • 포인터가 있다고 칩시다.값은 주소입니다.
  • 하지만 지금은 주소를 바꾸려고 하는군요
  • 될 것 같아요.pointer1 = pointer2 1에 2. 포인터 1 포인터 2의 를 지정합니다.
  • 하지만! 함수 내에서 그렇게 하고, 함수가 끝난 후에도 결과를 유지하려면 추가 작업이 필요합니다.포인터1을 가리키기 위해서만 새 포인터3이 필요합니다. 포인터3을 함수에 전달합니다.

  • 여기 예가 있습니다.먼저 아래 출력을 보고 이해하십시오.

#include <stdio.h>

int main()
{

    int c = 1;
    int d = 2;
    int e = 3;
    int * a = &c;
    int * b = &d;
    int * f = &e;
    int ** pp = &a;  // pointer to pointer 'a'

    printf("\n a's value: %x \n", a);
    printf("\n b's value: %x \n", b);
    printf("\n f's value: %x \n", f);
    printf("\n can we change a?, lets see \n");
    printf("\n a = b \n");
    a = b;
    printf("\n a's value is now: %x, same as 'b'... it seems we can, but can we do it in a function? lets see... \n", a);
    printf("\n cant_change(a, f); \n");
    cant_change(a, f);
    printf("\n a's value is now: %x, Doh! same as 'b'...  that function tricked us. \n", a);

    printf("\n NOW! lets see if a pointer to a pointer solution can help us... remember that 'pp' point to 'a' \n");
     printf("\n change(pp, f); \n");
    change(pp, f);
    printf("\n a's value is now: %x, YEAH! same as 'f'...  that function ROCKS!!!. \n", a);
    return 0;
}

void cant_change(int * x, int * z){
    x = z;
    printf("\n ----> value of 'a' is: %x inside function, same as 'f', BUT will it be the same outside of this function? lets see\n", x);
}

void change(int ** x, int * z){
    *x = z;
    printf("\n ----> value of 'a' is: %x inside function, same as 'f', BUT will it be the same outside of this function? lets see\n", *x);
}

출력은 다음과 같습니다(먼저 읽어주세요).

 a's value: bf94c204

 b's value: bf94c208 

 f's value: bf94c20c 

 can we change a?, lets see 

 a = b 

 a's value is now: bf94c208, same as 'b'... it seems we can, but can we do it in a function? lets see... 

 cant_change(a, f); 

 ----> value of 'a' is: bf94c20c inside function, same as 'f', BUT will it be the same outside of this function? lets see

 a's value is now: bf94c208, Doh! same as 'b'...  that function tricked us. 

 NOW! lets see if a pointer to a pointer solution can help us... remember that 'pp' point to 'a' 

 change(pp, f); 

 ----> value of 'a' is: bf94c20c inside function, same as 'f', BUT will it be the same outside of this function? lets see

 a's value is now: bf94c20c, YEAH! same as 'f'...  that function ROCKS!!!. 

함수 인수로 함수에 전달되는 포인터의 값을 변경하려면 포인터에 대한 포인터가 필요합니다.

간단히 말하면 함수 호출 외부에서도 Memory-Alocation 또는 Assignment를 유지(또는 유지)하고 싶을 사용합니다(따라서 이러한 함수를 더블 포인터 arg로 전달합니다).

이것은 그다지 좋은 예는 아니지만 기본적인 사용법을 보여줍니다.

#include <stdio.h>
#include <stdlib.h>

void allocate(int **p)
{
    *p = (int *)malloc(sizeof(int));
}

int main()
{
    int *p = NULL;
    allocate(&p);
    *p = 42;
    printf("%d\n", *p);
    free(p);
}

Asha의 응답에 더해, 아래 예에 대한 단일 포인터(예: allocate1())를 사용하면 함수 내부에 할당된 메모리에 대한 참조가 손실됩니다.

#include <stdio.h>
#include <stdlib.h>

void alloc2(int** p) {
    *p = (int*)malloc(sizeof(int));
    **p = 10;
}

void alloc1(int* p) {
    p = (int*)malloc(sizeof(int));
    *p = 10;
}

int main(){
    int *p = NULL;
    alloc1(p);
    //printf("%d ",*p);//undefined
    alloc2(&p);
    printf("%d ",*p);//will print 10
    free(p);
    return 0;
}

는 렇렇게 the alloc1이치노즉, 그 결과가 재할당되었을 때mallocalloc1변경은 다른 범위의 코드와는 관련이 없습니다.

파티에 조금 늦었지만 이게 도움이 됐으면 좋겠어.

C 어레이에서는 실행이 현재 블록의 끝에 도달하면 스택에 할당된 메모리가 자동으로 해방되기 때문에 항상 스택에 메모리를 할당할 수 없기 때문에 함수는 (비정적) 어레이를 반환할 수 없습니다.2차원 배열(매트릭스)을 처리하여 매트릭스를 변경 및 반환할 수 있는 몇 가지 함수를 구현하고 싶을 때는 매우 귀찮습니다.이를 실현하기 위해 포인터 투 포인터를 사용하여 동적으로 할당된 메모리를 가진 매트릭스를 구현할 수 있습니다.

/* Initializes a matrix */
double** init_matrix(int num_rows, int num_cols){
    // Allocate memory for num_rows float-pointers
    double** A = calloc(num_rows, sizeof(double*));
    // return NULL if the memory couldn't allocated
    if(A == NULL) return NULL;
    // For each double-pointer (row) allocate memory for num_cols floats
    for(int i = 0; i < num_rows; i++){
        A[i] = calloc(num_cols, sizeof(double));
        // return NULL if the memory couldn't allocated
        // and free the already allocated memory
        if(A[i] == NULL){
            for(int j = 0; j < i; j++){
                free(A[j]);
            }
            free(A);
            return NULL;
        }
    }
    return A;
} 

예를 들면 다음과 같습니다.

double**       double*           double
             -------------       ---------------------------------------------------------
   A ------> |   A[0]    | ----> | A[0][0] | A[0][1] | A[0][2] | ........ | A[0][cols-1] |
             | --------- |       ---------------------------------------------------------
             |   A[1]    | ----> | A[1][0] | A[1][1] | A[1][2] | ........ | A[1][cols-1] |
             | --------- |       ---------------------------------------------------------
             |     .     |                                    .
             |     .     |                                    .
             |     .     |                                    .
             | --------- |       ---------------------------------------------------------
             |   A[i]    | ----> | A[i][0] | A[i][1] | A[i][2] | ........ | A[i][cols-1] |
             | --------- |       ---------------------------------------------------------
             |     .     |                                    .
             |     .     |                                    .
             |     .     |                                    .
             | --------- |       ---------------------------------------------------------
             | A[rows-1] | ----> | A[rows-1][0] | A[rows-1][1] | ... | A[rows-1][cols-1] |
             -------------       ---------------------------------------------------------

투 더블 포인트A 번째 요소를 A[0]메모리 블록의 소자는 이중으로 되어 있습니다.이 더블 포인트 슛을 매트릭스의 열로 생각할 수 있습니다.이것이 모든 더블 포인터가 double 타입의 num_cols 요소에 메모리를 할당하는 이유입니다. ★★★★★★★★★★★★★★★★.A[i] 행.A[i]A[i][0]i번째 행의 메모리 블록의 첫 번째 더블 클리닝입니다.에 쉽게 할 수 .A[i][j].

다음은 사용법을 보여주는 완전한 예입니다.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/* Initializes a matrix */
double** init_matrix(int num_rows, int num_cols){
    // Allocate memory for num_rows double-pointers
    double** matrix = calloc(num_rows, sizeof(double*));
    // return NULL if the memory couldn't allocated
    if(matrix == NULL) return NULL;
    // For each double-pointer (row) allocate memory for num_cols
    // doubles
    for(int i = 0; i < num_rows; i++){
        matrix[i] = calloc(num_cols, sizeof(double));
        // return NULL if the memory couldn't allocated
        // and free the already allocated memory
        if(matrix[i] == NULL){
            for(int j = 0; j < i; j++){
                free(matrix[j]);
            }
            free(matrix);
            return NULL;
        }
    }
    return matrix;
}

/* Fills the matrix with random double-numbers between -1 and 1 */
void randn_fill_matrix(double** matrix, int rows, int cols){
    for (int i = 0; i < rows; ++i){
        for (int j = 0; j < cols; ++j){
            matrix[i][j] = (double) rand()/RAND_MAX*2.0-1.0;
        }
    }
}


/* Frees the memory allocated by the matrix */
void free_matrix(double** matrix, int rows, int cols){
    for(int i = 0; i < rows; i++){
        free(matrix[i]);
    }
    free(matrix);
}

/* Outputs the matrix to the console */
void print_matrix(double** matrix, int rows, int cols){
    for(int i = 0; i < rows; i++){
        for(int j = 0; j < cols; j++){
            printf(" %- f ", matrix[i][j]);
        }
        printf("\n");
    }
}


int main(){
    srand(time(NULL));
    int m = 3, n = 3;
    double** A = init_matrix(m, n);
    randn_fill_matrix(A, m, n);
    print_matrix(A, m, n);
    free_matrix(A, m, n);
    return 0;
}

1. 기본 개념 -

다음과 같이 선언하는 경우: -

char * 포인터라고 함) 1. char *ch - (문자 포인터라고 함)
는 한합니다.- ch는 한 글자의 주소입니다.
(* (*ch)는 문자 값을 참조합니다.

2. char **ch -
는 문자의 주소를 합니다.'1과 같이요.
ch' (일부러 하다)
(**ch)아카데미타령하다

포인터를 더 추가하면 데이터 유형의 차원이 문자에서 문자열로, 문자열 배열 등으로 확장됩니다.1d, 2d, 3d 매트릭스와 연관지을 수 있습니다.

따라서 포인터의 사용법은 선언 방법에 따라 달라집니다.

여기 간단한 코드가 있습니다.

int main()
{
    char **p;
    p = (char **)malloc(100);
    p[0] = (char *)"Apple";      // or write *p, points to location of 'A'
    p[1] = (char *)"Banana";     // or write *(p+1), points to location of 'B'

    cout << *p << endl;          //Prints the first pointer location until it finds '\0'
    cout << **p << endl;         //Prints the exact character which is being pointed
    *p++;                        //Increments for the next string
    cout << *p;
}

응용 . 더블 포인터의 다른 적용 -
도 참고문헌에 입니다.)

함수의 문자를 업데이트한다고 가정합니다.다음을 시도하면 다음과 같습니다.

void func(char ch)
{
    ch = 'B';
}

int main()
{
    char ptr;
    ptr = 'A';
    printf("%c", ptr);

    func(ptr);
    printf("%c\n", ptr);
}

출력은 AA가 됩니다.함수에 "Passed By Value"가 있으므로 이 방법은 작동하지 않습니다.

올바른 방법은 다음과 같습니다.

void func( char *ptr)        //Passed by Reference
{
    *ptr = 'B';
}

int main()
{
    char *ptr;
    ptr = (char *)malloc(sizeof(char) * 1);
    *ptr = 'A';
    printf("%c\n", *ptr);

    func(ptr);
    printf("%c\n", *ptr);
}

이제 문자 대신 문자열을 업데이트하기 위해 이 요건을 확장합니다.
이를 위해서는 함수의 파라미터를 더블 포인터로 수신해야 합니다.

void func(char **str)
{
    strcpy(str, "Second");
}

int main()
{
    char **str;
    // printf("%d\n", sizeof(char));
    *str = (char **)malloc(sizeof(char) * 10);          //Can hold 10 character pointers
    int i = 0;
    for(i=0;i<10;i++)
    {
        str = (char *)malloc(sizeof(char) * 1);         //Each pointer can point to a memory of 1 character.
    }

    strcpy(str, "First");
    printf("%s\n", str);
    func(str);
    printf("%s\n", str);
}

이 예에서는 메서드는 문자열 값을 갱신하기 위한 파라미터로서 더블 포인터를 상정하고 있습니다.

저는 오늘 이 블로그 투고에서 다음과 같이 매우 좋은 예를 보았습니다.

링크된 목록에 노드 구조가 있다고 가정해 보겠습니다.이 구조는 아마 다음과 같습니다.

typedef struct node
{
    struct node * next;
    ....
} node;

'을 실행하려고 합니다.remove_iffunction:.rm로서 링크( 「」등).rm(entry)==true의 노드가 목록에서 삭제됩니다.마내입니다.remove_if링크된 목록의 머리(원래 머리와는 다를 수 있음)를 반환합니다.

쓰셔도 됩니다.

for (node * prev = NULL, * curr = head; curr != NULL; )
{
    node * const next = curr->next;
    if (rm(curr))
    {
        if (prev)  // the node to be removed is not the head
            prev->next = next;
        else       // remove the head
            head = next;
        free(curr);
    }
    else
        prev = curr;
    curr = next;
}

for이 메시지는 이중 포인터가 없으면 포인터를 재구성하기 위해 변수를 유지해야 하며 두 개의 다른 경우를 처리해야 한다는 것입니다.

하지만 이중 포인터만 있으면 실제로 글을 쓸 수 있습니다.

// now head is a double pointer
for (node** curr = head; *curr; )
{
    node * entry = *curr;
    if (rm(entry))
    {
        *curr = entry->next;
        free(entry);
    }
    else
        curr = &entry->next;
}

필필은 필요 prev이제 지시된 내용을 직접 수정할 수 있기 때문입니다.

좀 더 알기 쉽게 하기 위해, 조금 더 코드를 따라해 봅시다.제거 중:

  1. entry == *head: 입니다.*head (==*curr) = *head->nexthead이제 새 머리글 노드의 포인터를 가리킵니다. 직접 바꾸면 .head는 새로운 포인터에 대한 콘텐츠입니다.
  2. entry != *head로 : ""*curr이 바로 '무엇'이다.prev->nextentry->next.

어떤 경우에도 더블 포인터를 사용하여 통일된 방법으로 포인터를 재구성할 수 있습니다.

포인터에 대한 포인터는 위치 재지정 가능한 메모리를 위해 함수 간에 "핸들"을 전달하고자 하는 메모리에 대한 "핸들"로서도 유용합니다.이는 기본적으로 함수가 핸들 변수 내의 포인터로 가리키고 있는 메모리를 변경할 수 있으며 핸들을 사용하는 모든 함수 또는 객체가 새로 재배치된(또는 할당된) 메모리를 적절하게 가리킬 수 있음을 의미합니다.라이브러리에서는, 「불투명」데이터 타입을 사용해 이것을 실시합니다.즉, 데이터 타입은, 가리키는 메모리의 기능에 대해 걱정할 필요가 없는 경우, 라이브러리의 기능간에 「핸들」을 돌리기만 하면, 그 메모리에서 몇개의 조작을 실행할 수 있습니다.라이브러리 기능은 메모리 관리 프로세스나 핸들이 가리키는 위치에 대해 명시적으로 걱정할 필요 없이 메모리 언더 더 후드의 할당 및 해제를 할 수 있습니다.

예:

#include <stdlib.h>

typedef unsigned char** handle_type;

//some data_structure that the library functions would work with
typedef struct 
{
    int data_a;
    int data_b;
    int data_c;
} LIB_OBJECT;

handle_type lib_create_handle()
{
    //initialize the handle with some memory that points to and array of 10 LIB_OBJECTs
    handle_type handle = malloc(sizeof(handle_type));
    *handle = malloc(sizeof(LIB_OBJECT) * 10);

    return handle;
}

void lib_func_a(handle_type handle) { /*does something with array of LIB_OBJECTs*/ }

void lib_func_b(handle_type handle)
{
    //does something that takes input LIB_OBJECTs and makes more of them, so has to
    //reallocate memory for the new objects that will be created

    //first re-allocate the memory somewhere else with more slots, but don't destroy the
    //currently allocated slots
    *handle = realloc(*handle, sizeof(LIB_OBJECT) * 20);

    //...do some operation on the new memory and return
}

void lib_func_c(handle_type handle) { /*does something else to array of LIB_OBJECTs*/ }

void lib_free_handle(handle_type handle) 
{
    free(*handle);
    free(handle); 
}


int main()
{
    //create a "handle" to some memory that the library functions can use
    handle_type my_handle = lib_create_handle();

    //do something with that memory
    lib_func_a(my_handle);

    //do something else with the handle that will make it point somewhere else
    //but that's invisible to us from the standpoint of the calling the function and
    //working with the handle
    lib_func_b(my_handle); 

    //do something with new memory chunk, but you don't have to think about the fact
    //that the memory has moved under the hood ... it's still pointed to by the "handle"
    lib_func_c(my_handle);

    //deallocate the handle
    lib_free_handle(my_handle);

    return 0;
}

이게 도움이 됐으면 좋겠는데

제이슨이야.

문자열은 이중 포인터의 좋은 예입니다.문자열 자체는 포인터이므로 문자열을 가리킬 때마다 이중 포인터가 필요합니다.

지금까지 여러 번 본 적이 있는 간단한 예

int main(int argc, char **argv)

두 번째 파라미터에는 char로의 포인터가 있습니다.

표기법(「」)에 해 주세요.char* c 표기법 「」 「」 「」char c[] 인수로 할 수 있습니다는 함수 인수로 교환할 수 있습니다. 쓸 수 요.char *argv[] 말하면 .꿔 . . . . . . . .char *argv[] ★★★★★★★★★★★★★★★★★」char **argv호환성이 있습니다.

위의 내용은 실제로 일련의 문자 시퀀스(시작 시 프로그램에 주어지는 명령줄 인수)를 나타냅니다.

위의 함수 시그니처에 대한 자세한 내용은 이 답변도 참조하십시오.

예를 들어, 메모리의 빈 공간을 확보할 때 포인터를 null로 설정할 수 있습니다.

void safeFree(void** memory) {
    if (*memory) {
        free(*memory);
        *memory = NULL;
    }
}

이 함수를 호출할 때 포인터의 주소를 사용하여 호출합니다.

void* myMemory = someCrazyFunctionThatAllocatesMemory();
safeFree(&myMemory);

, 이제myMemory를 NULL로 설정해 두면, 그것을 재이용하는 것은 분명히 잘못된 것입니다.

왜 이중 포인터야?

목적은 함수를 사용하여 학생 A가 가리키는 내용을 변경하는 것입니다.

#include <stdio.h>
#include <stdlib.h>


typedef struct Person{
    char * name;
} Person; 

/**
 * we need a ponter to a pointer, example: &studentA
 */
void change(Person ** x, Person * y){
    *x = y; // since x is a pointer to a pointer, we access its value: a pointer to a Person struct.
}

void dontChange(Person * x, Person * y){
    x = y;
}

int main()
{

    Person * studentA = (Person *)malloc(sizeof(Person));
    studentA->name = "brian";

    Person * studentB = (Person *)malloc(sizeof(Person));
    studentB->name = "erich";

    /**
     * we could have done the job as simple as this!
     * but we need more work if we want to use a function to do the job!
     */
    // studentA = studentB;

    printf("1. studentA = %s (not changed)\n", studentA->name);

    dontChange(studentA, studentB);
    printf("2. studentA = %s (not changed)\n", studentA->name);

    change(&studentA, studentB);
    printf("3. studentA = %s (changed!)\n", studentA->name);

    return 0;
}

/**
 * OUTPUT:
 * 1. studentA = brian (not changed)
 * 2. studentA = brian (not changed)
 * 3. studentA = erich (changed!)
 */

예를 들어 연속되지 않은 데이터에 대한 랜덤 액세스를 원하는 경우입니다.

p -> [p0, p1, p2, ...]  
p0 -> data1
p1 -> data2

--C에서

T ** p = (T **) malloc(sizeof(T*) * n);
p[0] = (T*) malloc(sizeof(T));
p[1] = (T*) malloc(sizeof(T));

합니다.p이치노각 포인터는 하나의 데이터를 가리킵니다.

ifsizeof(T)('malloc'의 연속 블록를 사용하여)을 할 수 .sizeof(T) * n

항상 사용하는 한 가지 이유는 오브젝트 배열이 있고 다른 필드별로 룩업(바이너리 검색)을 수행해야 하는 경우입니다.
★★★★★★★★★★★★★★★...

int num_objects;
OBJECT *original_array = malloc(sizeof(OBJECT)*num_objects);

그런 다음 오브젝트에 대한 정렬된 포인터의 배열을 만듭니다.

int compare_object_by_name( const void *v1, const void *v2 ) {
  OBJECT *o1 = *(OBJECT **)v1;
  OBJECT *o2 = *(OBJECT **)v2;
  return (strcmp(o1->name, o2->name);
}

OBJECT **object_ptrs_by_name = malloc(sizeof(OBJECT *)*num_objects);
  int i = 0;
  for( ; i<num_objects; i++)
    object_ptrs_by_name[i] = original_array+i;
  qsort(object_ptrs_by_name, num_objects, sizeof(OBJECT *), compare_object_by_name);

필요한 만큼 정렬된 포인터 배열을 만든 다음 정렬된 포인터 배열에서 이진 검색을 사용하여 데이터를 기준으로 필요한 개체에 액세스할 수 있습니다.개체의 원래 배열은 정렬되지 않은 상태로 유지될 수 있지만 각 포인터 배열은 지정된 필드에 따라 정렬됩니다.

변수의 수정 값과 포인터의 수정 값 비교:

#include <stdio.h>
#include <stdlib.h>

void changeA(int (*a))
{
  (*a) = 10;
}

void changeP(int *(*P))
{
  (*P) = malloc(sizeof((*P)));
}

int main(void)
{
  int A = 0;

  printf("orig. A = %d\n", A);
  changeA(&A);
  printf("modi. A = %d\n", A);

  /*************************/

  int *P = NULL;

  printf("orig. P = %p\n", P);
  changeP(&P);
  printf("modi. P = %p\n", P);

  free(P);

  return EXIT_SUCCESS;
}

이를 통해 호출된 함수에 의해 포인터가 수정되었을 때 포인터의 값이 반환되는 것을 피할 수 있었습니다(단일 링크 리스트에서 사용).

이전(불량):

int *func(int *P)
{
  ...
  return P;
}

int main(void)
{
  int *pointer;
  pointer = func(pointer);
  ...
}    

새로운 기능(더 나은 기능):

void func(int **pointer)
{
  ...
}

int main(void)
{
  int *pointer;
  func(&pointer);
  ...
}    

다음은 객체를 가리키도록 함수를 사용하여 포인터를 설정하는 경우 포인터에 대한 포인터가 필요하다는 것을 보여주는 매우 간단한 C++ 예입니다.그렇지 않으면 포인터는 계속 null로 돌아갑니다.

(C++의 답변입니다만, C에서도 마찬가지라고 생각합니다.)

(또한 참고:Google("pass by value c++") = "기본적으로 C++의 인수는 값으로 전달됩니다.인수가 값으로 전달되면 인수의 값이 함수의 매개 변수로 복사됩니다.")

포인터를 .ba.

#include <iostream>
#include <string>

void Function_1(std::string* a, std::string* b) {
  b = a;
  std::cout << (b == nullptr);  // False
}

void Function_2(std::string* a, std::string** b) {
  *b = a;
  std::cout << (b == nullptr);  // False
}

int main() {
  std::string a("Hello!");
  std::string* b(nullptr);
  std::cout << (b == nullptr);  // True

  Function_1(&a, b);
  std::cout << (b == nullptr);  // True

  Function_2(&a, &b);
  std::cout << (b == nullptr);  // False
}

// Output: 10100

에서 일Function_1(&a, b);

  • □□□□□□□□□'의&main::a(어드레스)에됩니다.std::string* Function_1::a.그러므로Function_1::a 주소대한 입니다.main::a.

  • □□□□□□□□□'의main::b메모리내의 는, (메모리내의 주소)에됩니다.std::string* Function_1::b따라서 메모리에는 이들 주소 중 2개가 있으며 둘 다 늘 포인터입니다.【 】b = a;, " " "Function_1::b '같다'로 .Function_1::a(=)&main::a단입니다.main::b변경되지 않습니다.에 콜 후Function_1,main::b는 아직 늘 포인터입니다.

에서 일Function_2(&a, &b);

  • 그 의 처리의 치료법은a변수는:함수 내에서,변수도 같습니다 같다.함수 내에서Function_2::a문자열문자열 주소입니다의 거주지가 있나.main::a.

  • 하지만 가변 하지만 변수는b지금은 포인터에 대한 포인터로 전달되고 있습니다.이제포인터로 전달되고 있습니다.의"가치'의"값"&main::b(포인터의 주소) main::b))는,에 카피됩니다에 복사됩니다.std::string** Function_2::bFunction_2 내에. 따라서, 따라서 Function_2 이 역 참조 내에서이것을 참조합니다.*Function_2::b그리고 액세스및 변경 수정에 접속할 것main::b. 그래서 그 라인 그래서 선이*b = a;실제로실제로 설정을 차리고 있중main::b(주소)(주소)와에 동등한 같다Function_2::a:main::a그게 우리가 원하는 거야

오브젝트나 주소(포인터)에 관계없이, 오브젝트를 수정하기 위해서 함수를 사용하고 싶은 경우는, 포인터를 그 오브젝트에 건네주어야 합니다.로컬 복사가 이루어지므로 실제로 전달한 내용은 (발신 범위 내에서) 변경할 수 없습니다.

(예외는 다음과 같은 파라미터가 참조일 경우입니다.std::string& a 게 있어요const으로는, 「 」라고 하는 이 있습니다.f(x) if, if, if, if.x라고 생각할 수 있는 오브젝트입니다.f 수정하지 않다x, ★★★★★★★★★★★★★★★★★★★★x포인터라고 요.그러면f 가리키는 오브젝트를 변경할 수 있습니다.x

저는 오늘 업무용 프로그래밍을 하면서 더블 포인터를 사용했기 때문에 왜 사용해야 했는지 알 수 있습니다(실제로 더블 포인터를 사용해야 했던 것은 이번이 처음입니다).일부 구조의 멤버인 버퍼에 포함된 프레임의 실시간 인코딩을 처리해야 했습니다.인코더에서는 그 구조 중 하나에 대한 포인터를 사용해야 했습니다.문제는 포인터가 다른 스레드에서 다른 구조물을 가리키도록 변경되고 있다는 것입니다.인코더에서 현재 구조를 사용하기 위해서는 더블 포인터를 사용해야 하며, 다른 스레드에서 수정되는 포인터를 가리켜야 했습니다.처음에는 적어도 우리에게는 이 방법을 택해야 한다는 것이 명확하지 않았습니다.이 프로세스에서는, 많은 주소가 인쇄되었습니다. : )

프로그램의 다른 위치에서 변경된 포인터에 대해 작업할 때는 이중 포인터를 사용해야 합니다.또한 반환 및 수신처를 지정하는 하드웨어를 다룰 때 반드시 필요한 이중 포인터도 있을 수 있습니다.

이 답변의 대부분은 애플리케이션 프로그래밍과 거의 관련되어 있습니다.다음은 임베디드 시스템 프로그래밍의 예입니다.다음 예시는 NXP의 Kinetis KL13 시리즈 마이크로 컨트롤러의 레퍼런스 매뉴얼에서 발췌한 것입니다.이 코드 스니펫은 펌웨어에서 ROM에 있는 부트로더를 실행하기 위해 사용됩니다.

" 진입점의 주소를 얻기 위해 사용자 애플리케이션은 부트로더의 벡터 테이블의 오프셋 0x1C에 있는 부트로더 API 트리에 대한 포인터를 포함하는 단어를 읽습니다.벡터 테이블은 부트로더의 주소 범위(ROM의 경우 0x1C00_0000)의 베이스에 배치됩니다.따라서 API 트리 포인터는 주소 0x1C00_001C에 있습니다.

부트로더 API 트리는 부트로더의 기능과 데이터 주소를 가진 다른 구조물에 대한 포인터를 포함하는 구조체입니다.부트로더 엔트리 포인트는 항상 API 트리의 첫 번째 단어입니다."

uint32_t runBootloaderAddress;
void (*runBootloader)(void * arg);
// Read the function address from the ROM API tree.
runBootloaderAddress = **(uint32_t **)(0x1c00001c);
runBootloader = (void (*)(void * arg))runBootloaderAddress;
// Start the bootloader.
runBootloader(NULL);

언급URL : https://stackoverflow.com/questions/5580761/why-use-double-indirection-or-why-use-pointers-to-pointers

반응형