通过传递指针的地址来初始化本地指针

时间:2012-08-16 04:41:58

标签: c pointers coding-style

我在代码的几乎每个部分都看到了以下初始化本地指针的方法。我想了解这样做的原因和复杂性。

#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;
}

就是这样,我在这里用简单的字符串显示。在我的实际代码中,它是使用结构完成的。

我有点理解上面的逻辑而且我没有。请明确上述实施方式所涉及的概念。另外,如果还有其他更好的方法可以让我知道。

请启发.. :)

5 个答案:

答案 0 :(得分:4)

我可能会返回新分配的字符串,而不是将指针作为参数传递给指针:

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;
}

答案 1 :(得分: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);

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

答案 2 :(得分:0)

在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");
}

还要确保释放返回的字符串以避免内存泄漏。

答案 3 :(得分:0)

我建议您创建分配和释放功能对

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;
}

答案 4 :(得分: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;
}

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