【问题标题】:why and when is a double-pointer required?为什么以及何时需要双指针?
【发布时间】:2013-12-15 09:48:40
【问题描述】:

我大部分时间都是系统管理员,但最近决定练习一些我的开发知识并尝试担任 devops 职位。因此,我一直在练习一些 C 和 Python 技能,并编写了一些用于将数字插入到链表中的代码。

void list_insert(struct list *h, int d)
{
        struct list *elem = malloc(sizeof(struct list));

        elem->data = d;
        elem->next = NULL;

        if (!h) {
                h = elem;
        } else {
                elem->next = h;
                h = elem;
        }
}           

我注意到这个函数似乎并没有改变变量 h 的外部视图(即传递给 list_insert 的任何内容),我注意到在插入函数末尾打印似乎有效。因此,尝试在线寻找答案后,我什么也找不到,很明显,但我发现大多数列表实现都会有双指针。我将函数更改为使用双指针,然后它突然开始工作。有人可以帮我理解这里发生了什么,因为我知道指针管理是一个重要的概念,我想我理解指针是什么以及它与内存的关系,但我不认为我明白为什么单个指针不会改变,而双指针可以。

谢谢!

【问题讨论】:

  • 当您将参数传递给函数时,该参数将被复制,并且该函数使用原始副本。当您传递一个指针(pointer=int 被复制)并且您执行 *pointer=something 时,您修改了指针指向的数据,“允许您查看函数外部的更改”。因此, var * * 将是一个可写指针。

标签: c pointers linked-list


【解决方案1】:

在 C 中,函数的参数是按值传递的。甚至指针也是按值传递的。

例如:

#include<malloc.h>
#include<stdio.h>
int allocatingMemory(int* ptr)
{
    ptr = malloc(sizeof(int)); 
    if(ptr==NULL)
        return -1;
    else 
        return 0;
}// We are not returning the pointer to allocated memory

int main(void)
{
    int* ptr;
    int allocated = allocatingMemory(ptr);
    if(allocated == 0)
    {
        *ptr = 999;// Boom!!! 
        free(ptr);
    }

    return 0;
}

为了解决这个问题,我们使用

int allocatingMemory(int** ptr)
{
    *ptr = malloc(sizeof(int));
    if(*ptr == NULL)
        return -1;
    else 
        return 0;
}

int main(void)
{
    int* ptr;
    int isAllocated = allocatingMemory(&ptr);
    if(isAllocated == 0)
    {
        *ptr = 999;
        free(ptr);
    }

    return 0;
}

如果您正在使用linked lists 并说,例如,您想修改头部。你将传递一个pointer to pointer(注意,它不是双指针)给head node

【讨论】:

  • 谢谢!需要澄清一下,指针按值传递是什么意思?
  • 因为变量是按值传递给函数的。这意味着变量值被复制到函数参数列表中的参数。同样,指针也是按值传递的。这意味着,指针值(指针具有某个内存位置的地址)被复制(地址被复制)到函数参数列表中的另一个指针。他们称之为通过地址传递。
【解决方案2】:

要在调用者的上下文中更改内存,函数需要有一个指向该内存的指针。

如果您的函数的调用者在变量中有一个空列表,并且像这样在该列表上插入:

struct list *numbers = NULL;

list_insert(numbers, 4711);

那么当然在list_insert()内部我们只有NULL指针,所以我们不能在调用者的上下文中改变变量numbers的值。

另一方面,如果我们得到一个指向变量的指针,我们可以更改该变量。

也就是说,(在我看来)返回列表的新头部要干净得多,即将函数的签名设为struct list * list_insert(struct list *head, int x);

【讨论】:

  • +1 用于建议“返回列表的新头部”。使其更具可读性。
  • 我希望两全其美,所以要返回值并使用参考。在这种情况下,您可以将该函数用作另一个函数的参数,并且您可以稍后处理。
  • 谢谢放松。如果我能赞成你的回答,我会的。感谢您花时间回答我的问题:) 然后您将如何使用它。 h = list_insert(h, 1) 例如?
【解决方案3】:

h 实际上是原始指针的副本,因此您的原始指针不会被修改。这就是为什么你应该使用双指针。

关于 SO 有很多与此相关的问题。例如Using single versus double pointers in Linked lists implemented in C

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多