簡體   English   中英

有人可以解釋指針如何工作嗎?

[英]Can someone explain how pointer to pointer works?

我不太了解指針的工作原理。 有什么方法可以在不使用指針的情況下完成相同的工作?

struct customer
{
    char name[20];
    char surname[20];
    int code;
    float money;
};
typedef struct customer customer;
void inserts(customer **tmp)
{
    *tmp = (customer *)malloc(sizeof(customer));
    puts("Give me a customer name, surname code and money");
    scanf("%s %s %d %f", (*tmp)->name, (*tmp)->surname, &(*tmp)->code, &(*tmp)->money);
}

指向指針的指針101

假設您有一個int變量xint x;

  • 內存的一部分將被分配給x足夠大的空間以容納int。
  • 分配給x的存儲器在過程存儲器映射中具有一個地址。
  • 要查看x在內存中的地址,請使用:
    printf("x's memory address = %p\\n", &x);
  • `&x`表示`x`的地址。
  • 要查看存儲在`x`中的整數值,請使用:
    printf("x=%d\\n", x);
  • be manipulated directly within it's scope of existence. x 在其存在范圍內直接操作。 例如,可以在聲明它的函數中對其進行操作:
    x = 42;
  • 如果內存地址已知,則可以在其存在范圍之外操作x的值。
  • 如果將x的值(即42)傳遞給函數x ,則該函數無法操縱x的值。
  • 如果將&x的地址傳遞給函數( &x ),則該函數可以操縱&x的值。

現在,假設您有一個指針變量p ,它假定它指向一個intint *p;

  • 一部分內存將被分配給足以容納一個內存地址的“ p”。
  • 分配給“ p”的存儲器在過程存儲器映射中具有一個地址。
  • “&p”表示“ p”的地址。
  • 要查看“ p”在內存中的地址,請使用:
    printf("p's memory addr = %p\\n", &p
  • 要查看“ p”指向的地址,請使用:
    printf("Address where `p` is pointing: %p\\n", p);
  • 要查看所指稱的整數,請使用:
    printf("int = %d\\n", *p);
  • p的值是內存中的地址。 可以將p和p設置為指向任何地址,無論該地址是否實際存在於過程內存映射中。
  • 對象的地址是指向該對象的指針。 因此,要使p指向x:
    p = &x
  • p指向的對象可以通過指針類型(p的int類型)來引用。
  • 分配給“ p”的內存量將根據機器的體系結構而有所不同。 以及它如何表示地址。
  • be manipulated directly within it's scope of existence. p 在其存在范圍內直接操作。 例如,可以在聲明它的函數中對其進行操作:
    p = &x; p = NULL
  • 如果內存地址已知,則可以在其存在范圍之外操作p的值。
  • 如果將值“ p”(地址)傳遞給函數( p ),則該函數無法操縱“ p”來更改其指向的位置。
  • 如果將`p`的地址傳遞給函數( &p ),則該函數可以操縱`p`指向的內容。

現在,假設您有一個指向指針變量pp的指針,假定它指向一個指向“ int”的指針: int **pp; ...或:void inserts(客戶** tmp ):

  • 指針的地址是指向指針的指針。
  • ...

在此處輸入圖片說明

回到問題

否。假設以下內容:

void inserts(customer **tmp);

...
   {
   customer cust;
   custPtr  custPtr = &cust;

   inserts(&custPtr);
   ... 

inserts()函數需要一個指針的地址才能操縱custPtr指向的位置。

如果相反:

void inserts2(customer *tmp);

...
   {
   customer cust;
   custPtr  custPtr = &cust;

   inserts2(custPtr);
   ... 

insert2()將獲得custPtr值的副本,該值是cust的地址。 因此, insert2()可以修改cust的值,但不能更改custPtr指向的位置。

對於類型T任何參數,如果要修改參數的值並使更改反映在調用方中,則必須傳遞一個指針:

void foo( T *ptr ) 
{
  *ptr = new_value();
}

void bar( void )
{
  T var;
  foo( &var ); // writes to var
}

如果T是一個指針類型Q * ,那么您將獲得一個指向該指針的指針:

void foo( Q **ptr )
{
  *ptr = new_value();
}

void bar( void )
{
  Q *var;
  foo( &var ); // writes to var
}

您可以使用typedefs隱藏變量的指針,但是以我的經驗,將指針隱藏在typedefs后面是不好的做法。

您可以更改函數以返回指針值,而不是像@Namfuak建議的那樣寫入參數:

Q *foo( void )
{
  Q *val = new_value();
  return val;
}

void bar( void )
{
  Q *var;
  var = foo();
}

如果指針是您的電話簿條目,則可以認為指向該指針的指針是告訴您該條目所在的電話簿。

查看您的代碼:

struct customer {
    char name[20];
    char surname[20];
    int code;
    float money;
};

首先, 您不應將float類型用於money

您的問題與C FAQ 4.8有關 基本上,您具有插入客戶記錄的功能。 您想在哪里插入記錄? 很顯然,有記錄的東西,例如電話簿,數據庫等。因此,您需要的是指向某個東西的指針,該東西包含指向要插入的對象的指針。

現在,對於其余的代碼,首先請注意, 您不應該malloc的返回值 其次, 使用scanf是嚴重的安全風險 第三,您正在inserts函數中分配新的客戶記錄,但是您無法將任何失敗傳達給調用函數的代碼。

可以說,函數的名稱應類似於create_customer_interactive以表明它所做的不僅僅是在記錄列表中插入一條記錄。

這是代碼的結構方式:

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

struct customer {
    char *name;
    char *surname;
    int code;
    int money; /* in cents */
};

typedef struct customer *PCustomer;

int read_customer_record(FILE *fp, PCustomer customer) {
    /* dummy implementation */
    customer->name = "A. Tester";
    customer->surname = "McDonald";
    customer->code = 123;
    customer->money = 100 * 100;
    return 1;
}

PCustomer insert_record_interactive(PCustomer *db, FILE *fp) {
    PCustomer tmp = malloc(sizeof(*tmp));
    if (!tmp) {
        return NULL;
    }
    if (!read_customer_record(fp, tmp)) {
        free(tmp);
        return NULL;
    }
    *db = tmp;
    return tmp;
}

int main(void) {
    PCustomer new_customer;
    PCustomer *db = malloc(3 * sizeof(*db));
    if (!db) {
        perror("Failed to allocate room for customer records");
        exit(EXIT_FAILURE);
    }

    /* insert a record in the second slot */
    new_customer = insert_record_interactive(&db[1], stdin);
    if (!new_customer) {
        perror("Failed to read customer record");
        exit(EXIT_FAILURE);
    }

    printf(
            "%s %s (%d) : $%.2f\n",
            new_customer->name,
            new_customer->surname,
            new_customer->code,
            ((double)new_customer->money) / 100.0
            );
    return 0;
}

多個間接級別可能導致混亂。 一個好的策略是通過減少間接級別來減少混亂。

除了使用scanf()之外,還有其他合法的問題,以下是實現此目的的一種方法:

void inserts(customer **tmp)
{
    customer *new_cust = malloc(sizeof *new_cust);
    if ( !new_cust ) {
        fprintf(stderr, "Couldn't allocate memory.\n");
        exit(EXIT_FAILURE);
    }

    puts("Give me a customer name, surname code and money");
    scanf("%s %s %d %f", new_cust->name, new_cust->surname,
                         new_cust->code, new_cust->money);

    /*  We delay using multiple levels of indirection
        until we get to the very last line, here.      */

    *tmp = new_cust;
}

正如其他人提到的那樣,在這種特殊情況下,僅返回指針可能會更容易。

void inserts(customer *tmp[])
{
    *tmp = malloc(sizeof(customer));
    puts("Give me a customer name, surname code and money");
    scanf("%s %s %d %f", (*tmp)->name, (*tmp)->surname, &(*tmp)->code, &(*tmp)->money);
}

那是等效的。 指向指針的指針也可以表示為指向未知大小數組的指針。

發生的是,* tmp被分配給類型為“ customer”的1個元素的數組。 tmp本身以兩種方式(** tmp和* tmp [])都指向未知大小的“客戶”元素數組的指針。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM