如何在没有警告的情况下返回正确的数据类型

时间:2020-04-22 02:37:30

标签: c linked-list return

我正在尝试构建自己的链表数据结构,但遇到一件事:我不知道返回一个带指针的NULL数据类型。 例如:

item pophead(node *list)
{
    head = list;
    node *newlist = (node *) malloc(sizeof(node*));
    item result;
    if(!list)
    {
        perror("There is nothing to be pop\n");
        return;
    }
    else
    {
        newlist = list->next;
        result = list->data;
        free(list);
        list = newlist;
    }
    return result;
}

这是我的程序,用于从链接列表的顶部弹出一个项目。问题是在第一种情况下检查列表是否为空,因此我希望我的程序报不返回任何内容,但是当我这样写时,它会收到警告消息。

我想补充一点,item是结构数据类型,而不是像intchar这样的单一数据类型。

2 个答案:

答案 0 :(得分:1)

除非您return newlist;,否则您需要传递list的地址,例如item pophead(node **list),因此您可以操作原始指针而不是副本。为什么? C是按值传递,当您将变量作为参数传递时,该函数将接收该变量的副本。您对函数所做的任何更改都会在返回时丢失。

为避免这种情况,您可以传递参数的地址,尽管该函数仍将接收指针的副本,但它将包含原始地址作为其值。您可以这样做:

item pophead(node **list)
{
    head = *list;
    // node *newlist = malloc(sizeof *newlist);  // (no allocation needed)
    node *newlist = NULL;
    item result;
    if(!*list)
    {
        perror("There is nothing to be pop\n");
        return;
    }
    else
    {
        newlist = head->next;
        result = head->data;
        free(head);
        *list = newlist;
    }
    return result;
}

注意:,无需为newlist进行分配,您只需将地址从现有节点分配给指针,而不将内容复制到新存储中)

然后在您的调用函数中而不是调用:

item someitem = pophead (list);

您会打电话

item someitem = pophead (&list);

注意:在C语言中,无需强制转换malloc的返回,这是不必要的。请参阅:Do I cast the result of malloc?


不返回任何内容或struct item,取决于列表是否为空

从我们的广泛讨论中,或者从我从谈话中收集到的信息来看,您用item result;表示如果列表为空,则不返回任何内容,否则返回result

您已声明函数返回类型item,并确认item是类型struct而不是指针的typedef 类型控制您可以返回的内容。当您声明要返回的函数时,键入item -这就是它必须返回的内容。如果类型为item *,则可以选择返回NULL(和空指针)或指向持有类型item的已分配块的指针。

如果列表为空,或者如果列表具有节点,则可以返回初始化为全零的结构item或用值完全填充的结构。您当前声明的位置:

    item result;    /* which leaves the values indeterminate */

您可以使用通用初始化程序{0}进行初始化,或者在C语言中首选的初始化方法是使用命名的初始化程序,您可以在其中将第一个成员的值设置为零(或如果是字符数组,则为空字符串),所有其他成员默认情况下都将初始化为零,例如

    item result = {0};

对于返回类型为item的函数,只有两个选项是返回item初始化为零或返回item且成员填充有值。您不能像使用return;返回类型那样简单地使用void,所以您可以更改函数类型或返回result初始化为全零或使用值。

答案 1 :(得分:1)

您必须首先确定您的前提条件。您是否要求列表为非空,还是要处理一个空列表?给定列表为非空的前提,您可以按值返回该项目,而无需使用错误指示符。如果列表可以为空,那么您将需要返回错误或项目。

如果返回指向头node的指针,则使调用者负责释放node。如果您将item返回头node,那么您将不必担心释放node

您还需要一种方法来修改列表的呼叫者视图。您当前正在按值传递列表,因此您对list变量所做的更改将对调用者不可见。您需要通过引用传递列表。

我将假设您要返回item,并且可以使用node释放free。在这种情况下,我们可以返回成功的0和失败的-1,通过引用传递列表,还可以将指针传递到您希望弹出的item的位置(如果有的话) )放置。

int pophead(node **list, item *item)
{
    node *head = *list; // get a pointer to the head node

    if (head == NULL) {
        return -1; // list is empty; error
    }

    *item = head->data; // copy the data to the output
    *list = head->next; // update the list
    free(head);         // free the head element

    return 0; // success
}

然后您将像这样调用函数:

node *the_list = NULL;

// TODO: populate the_list somehow

item the_item;

if (pophead(&the_list, &the_item) == 0) {
    // process the_item
}

顺便说一句,在C ++中,标准模板库定义了前提条件,即列表必须为非空,以便弹出不会失败。它提供了一个单独的功能来测试列表是否为非空,调用方在尝试弹出之前必须检查该列表。这样,可以按值返回项目,而无需返回错误指示符。

在C语言中,通常不可能返回可能具有任何值或错误的内容。