返回本地指针

时间:2014-06-12 12:35:07

标签: c pointers

我的问题是对此的扩展:Returning pointer to a local structure

我编写了以下代码来创建一个空列表:

struct node* create_empty_list(void)
{
    struct node *head = NULL;
    return head;
}

我刚才读到返回指向局部变量的指针是没用的,因为当函数退出时,变量将被销毁。我相信上面的代码返回了NULL指针,所以我不认为它是指向局部变量的指针。
在这种情况下,分配给指针的内存在哪里。我没有在堆上分配任何内存,它应该在堆栈上,作为自动变量。但是当代码退出(指针)时会发生什么,如果我尝试在程序中使用它,通过为指针分配一些pointees / de-referencing等等?

4 个答案:

答案 0 :(得分:5)

struct node* create_empty_list(void)
{
    struct node *head = NULL;
    return head;
}

相当于:

struct node* create_empty_list(void)
{
    return NULL;
}

这完全没问题。

如果你有类似的话会出现问题:

 struct node head;
 return &head;  // BAD, returning a pointer to an automatic object

答案 1 :(得分:5)

在这里,您将返回本地变量的值,这是正常的:

struct node* create_empty_list()
{
    struct node* head = NULL;
    return head;
}

head的值恰好是NULL(0),在函数create_empty_list返回之前被复制到堆栈中。调用函数通常会将此值复制到其他变量中。

例如:

void some_func()
{
    struct node* some_var = create_empty_list();
    ...
}

在下面的每个示例中,您将返回本地变量的地址,这不是正常的:

struct node* create_empty_list()
{
    struct node head = ...;
    return &head;
}

struct node** create_empty_list()
{
    struct node* head = ...;
    return &head;
}

head的地址,每次调用函数create_empty_list时可能是不同的地址(取决于该点的堆栈状态),返回。该地址通常是4字节值或8字节值(取决于系统的地址空间),在函数返回之前被复制到堆栈中。您可以“以任何您喜欢的方式”使用此值,但您不应该依赖于它表示有效变量的内存地址这一事实。


关于变量的一些基本事实,对您来说很重要:

  • 每个变量都有一个地址和一个值。
  • 变量的地址是常量(即,在声明变量后它不能改变)。
  • 变量的值不是常量(除非您明确地将其声明为const变量)。
  • 使用指针这个词,暗示变量的值本身就是某个其他变量的地址。尽管如此,指针仍然有自己的地址(与其值无关)。

请注意,上述说明不适用于阵列。

答案 2 :(得分:3)

正如其他人所提到的,你正在回归价值,这是完全正常的。

但是,如果您已将函数体更改为:

struct node head;
return &head;

你会返回地址变量的地址(指针),这可能会有危险,因为它在堆栈上分配并在离开函数体后立即释放。

如果您将代码更改为:

struct node * head = (struct node *) malloc( sizeof( struct node ) );;
return head;

然后你返回本地值的 value ,这是指向堆分配内存的指针,它将一直有效,直到你在它上面调用free

答案 3 :(得分:1)

回答

  

在这种情况下,分配给指针的内存在哪里。我没有   在堆上分配任何内存,它应该在堆栈上,作为   自动变量。但是当代码退出时会发生什么   指针),如果我尝试在程序中使用它,通过分配这个指针   一些pointees / de-referencing and alike?

您的案例中没有为指针分配内存。存在分配给包含指针的内存,该指针位于堆栈上,但由于它指向NULL,因此它不指向任何可用内存。此外,您不必担心指针在堆栈上,因为返回它会创建指针的副本

(正如其他人提到的)当您在函数体中声明对象时,内存在隐式堆栈中分配。您可能知道(根据您的问题判断),内存是通过显式请求在堆上分配的(在C中使用malloc

如果您尝试取消引用指针,则会出现分段错误。您可以分配给它,因为这只会覆盖NULL值。为确保您不会出现分段错误,您需要检查您使用的列表是否不是NULL指针。例如,这是一个追加函数:

struct node
{
    int elem;
    struct node* next;
};

struct node* append(struct node* list, int el) {
    // save the head of the list, as we would be modifying the "list" var
    struct node* res = list;

    // create a single element (could be a separate function)
    struct node* nn = (struct node*)malloc(sizeof(struct node));
    nn->elem = el;
    nn->next = NULL;

    // if the given list is not empty
    if (NULL != list) {
        // find the end of the list
        while (NULL != list->next) list = list->next;

        // append the new element
        list->next = nn;
    } else {
        // if the given list is empty, just return the new element
        res = nn;
    }
    return res;
}

关键部分是if (NULL != list)检查。没有它,你会尝试取消引用列表,从而产生分段错误。