簡體   English   中英

通過傳遞指針的地址來初始化本地指針

[英]Initializing local pointers by passing the address of a pointer

我在代碼的幾乎每個部分都看到了以下初始化本地指針的方法。 想要了解這樣做的原因和復雜性。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void initialize_p(char **p)
{
        char *p_local = NULL;
        p_local=malloc(6);
        strcpy(p_local,"sandy");
        *p = p_local;
}
int main(void)
{
        char *p = NULL;
        initialize_p(&p);
        printf("Name : %s\n",p);
        return 0;
}

就是這樣,我在這里用簡單的字符串顯示。 在我的實際代碼中,它是使用結構完成的。

我有點理解上面的邏輯而且我也沒有。 請明確上述實施方式所涉及的概念。 另外,如果還有其他更好的方法可以讓我知道。

請啟發.. :)

我可能會返回新分配的字符串,而不是將指針作為參數傳遞給指針:

char *initialize(void) {
    char *init = "sandy"; 
    char *ret = malloc(sizeof(init)+1);
    if (ret != NULL)
        strcpy(ret, init);
    return ret;
}

int main() {
    char *p = initialize();
    printf("Name: %s\n", p);
    free(p);
    return 0;
}

這是一個超出參數。 該函數為您生成結果,並將其保存到您傳遞的參數中。 當結果的大小可能變化,或者參數的類型是不透明時,通常會使用此方法。

就個人而言,我認為返回結果更清晰,並且在需要動態分配時更不容易出錯(如JerryCoffin的答案+1中所示)。

當不需要動態分配時,如果它不是很小的話,則通過引用傳遞它(作為非const參數):

struct t_struct { int a[100]; };

void InitStruct(struct t_struct* pStruct) {
  pStruct->a[0] = 11;
  ...
}

struct t_struct s;
void InitStruct(&s);

如果它很小,你可以考慮按價值返回。

在initialize_p中,分配了一塊內存,並將一些字符串復制到內存中。 為了讓初始化器的調用者獲得這個新的內存塊的地址,指針p的地址被傳遞給initialize_p:

    char **p

         +---+---+---+---+---+----+
   *p -> | s | a | n | d | y | \0 |
         +---+---+---+---+---+----+

如果只傳遞* p,那么在函數內設置指針將相當於:

void foo(int a)
{
  a=3;
  ...
}

更好的方法是使用strdup,它與你在函數中做同樣的事情

char* initialize_p()
{
   return strdup("sandy");
}

還要確保釋放返回的字符串以避免內存泄漏。

我建議你創建分配和釋放功能對

char *createP()
{
    char *p = NULL;
    p=malloc(6);
    strcpy(p,"sandy");
    return p;
}
void freeP(char *p)
{
    if (p) free(p);
}
int main(void)
{
    char *p = createP();
    printf("Name : %s\n",p);
    freeP(p);
    return 0;
}

清除這個概念? 好吧,在這么簡單的情況下,我沒有看到使用byref輸出參數操作的重點 - 對我來說,面向對象的結構構造函數如果它們像這樣工作則更容易理解:

struct foo *bar = myobj_new(); // uses malloc and returns a pointer
// do something with bar
myobj_destroy(bar); // uses free

有些人認為這個設計很好,因為這個函數的返回值可以用作錯誤/成功代碼(你看過SQLite3嗎?),但我不同意。 我認為函數的主要,最重要的結果應該是返回值,而不是一些輔助內容。 (我傾向於編寫庫,其中通過返回NULL並設置byref傳遞的錯誤代碼來指示失敗)。

我能想到的唯一有效的場景是,傳遞這樣的參數更合乎邏輯或更對稱。 例如,想象一個非常奇怪的排序函數,類似於C stdlib函數qsort() ,但需要它的比較函數本身在需要時交換兩個元素。 比較函數顯然需要通過參數訪問它的兩個參數來交換它們,但是為了優化算法,將原始遇到的順序返回給調用者排序函數也是有用的。 所以這個比較函數可能是這樣的:

int compare(void *a, void *b)
{
    int x = *(int *)a;
    int y = *(int *)b;

    if (x > y)
    {
        *(int *)a = y;
        *(int *)b = x;
        return +1;
    } else if (x < x) {
        return -1;
    }

    return 0;
}

嗯,差不多就是我的意見......

暫無
暫無

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

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