我的问题是对此的扩展:Returning pointer to a local structure
我编写了以下代码来创建一个空列表:
struct node* create_empty_list(void)
{
struct node *head = NULL;
return head;
}
我刚才读到返回指向局部变量的指针是没用的,因为当函数退出时,变量将被销毁。我相信上面的代码返回了NULL
指针,所以我不认为它是指向局部变量的指针。
在这种情况下,分配给指针的内存在哪里。我没有在堆上分配任何内存,它应该在堆栈上,作为自动变量。但是当代码退出(指针)时会发生什么,如果我尝试在程序中使用它,通过为指针分配一些pointees / de-referencing等等?
答案 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)
检查。没有它,你会尝试取消引用列表,从而产生分段错误。