我正在尝试构建自己的链表数据结构,但遇到一件事:我不知道返回一个带指针的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
是结构数据类型,而不是像int
或char
这样的单一数据类型。
答案 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语言中,通常不可能返回可能具有任何值或错误的内容。