Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 返回本地指针_C_Pointers - Fatal编程技术网

C 返回本地指针

C 返回本地指针,c,pointers,C,Pointers,我的问题是这个问题的延伸: 我编写了以下代码来创建一个空列表: struct node* create_empty_list(void) { struct node *head = NULL; return head; } 我刚刚读到,返回局部变量的指针是无用的,因为当函数退出时,变量将被销毁。我相信上面的代码返回了一个NULL指针,所以我不认为它是指向局部变量的指针。 这里是分配给指针的内存。我没有在堆上分配任何内存,它应该作为一个自动变量在堆栈上。但是当代码退出(指向指针)

我的问题是这个问题的延伸:

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

struct node* create_empty_list(void)
{
    struct node *head = NULL;
    return head;
}
我刚刚读到,返回局部变量的指针是无用的,因为当函数退出时,变量将被销毁。我相信上面的代码返回了一个
NULL
指针,所以我不认为它是指向局部变量的指针。
这里是分配给指针的内存。我没有在堆上分配任何内存,它应该作为一个自动变量在堆栈上。但是当代码退出(指向指针)时,如果我尝试在程序中使用它,通过给这个指针分配一些指针对象/取消引用等等,会发生什么呢

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

在这里,您将返回一个局部变量的值,这是正常的:

struct node* create_empty_list()
{
    struct node* head = NULL;
    return head;
}
head
的值恰好是
NULL
(0),在函数
create\u empty\u 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
    变量)
  • 使用单词指针时,意味着变量的值本身就是其他变量的地址。尽管如此,指针仍然有自己的地址(与它的值无关)

请注意,上面的描述不适用于数组。

正如其他人所提到的,您正在返回值,这是完全正确的

但是,如果您已将主体功能更改为:

struct node head;
return &head;
您将返回地址(指针指向)局部变量,这可能是潜在的危险,因为它在堆栈上分配,并在离开函数体后立即释放

如果您将代码更改为:

struct node * head = (struct node *) malloc( sizeof( struct node ) );;
return head;
然后返回本地值的值,即指向堆分配内存的指针,该指针将保持有效,直到您对其调用
free

这里是分配给指针的内存。我没有 在堆上分配任何内存,它应该作为一个 自动变量。但是当代码退出(到 指针),如果我试图在程序中使用它,则通过分配此指针 一些指向对象/取消引用等

struct node* create_empty_list(void)
{
    struct node *head = NULL;
    return head;
}
您的案例中没有为指针分配内存。有分配给的内存包含堆栈上的指针,但由于指针指向
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)
检查。如果没有它,您将尝试取消引用列表,从而导致分段错误。

在这种情况下,用于存储指针的内存分配在堆栈上。您返回的是局部变量的值,这很好。您返回的是局部变量,而不是指向它的指针@flipper:是的,但是你不应该去引用它,当一个空指针被声明时,它是否真的存储了一个
null
而不是内存地址,直到它被分配了一个指针对象?@flipper:我已经添加了一些关于变量的基本事实,这对你理解很重要…@barakmanos:While&x是一个l值,并非每个l值都是&x。看见换句话说,我不会说变量的地址是“aka l-value”。否则-很好的解释。@stanm:我同意,这不是一个很好的相关性,谢谢你指出这一点。答案相应更新(删除l-value和r-value两个词)。快速离题:我们应该在列表的前面或末尾添加新元素(如上所述)?我看不到定义此属性的链表,而且似乎每个人都可以随意添加。什么是标准的链表行为,如果有的话?你可以两者都做——它们是不同的操作。根据您需要列表的目的,您可以避免编写其中一个。