使用 C 在双向链表中隐式声明函数

Implicit declaration of function in doubly linked list using C

这不是程序的最终实现,但程序本身有点长,所以我决定改为将其分成小块来创建。我 运行 遇到一个错误

implicit declaration of function list_first.

还有其他错误需要解决,但我想先得到一些帮助,然后再自己解决其余的问题,尽管如果您愿意,欢迎您提供额外的帮助。这是代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

// The type for a node in the list.
struct node
{
    struct node *next;
    struct node *prev;
    char *value;
};

// The type for a list.
typedef struct list
{
    struct node head;
} List;

// The type for a list position.
typedef struct list_pos
{
    struct node *node;
} ListPos;

List *list_create(void)
{
  List *lst = (List*)malloc(sizeof(List));
  if(lst == NULL)
  {
    printf("No more memory!\n");
  }

  return lst;
}

static struct node *make_node(const char *value)
{
  struct node *result = malloc(sizeof(struct node));
  result->value = strdup(value);
  result -> next = NULL;
  result -> prev = NULL;
  return result;
}
static void add_values(List *lst)
{
    ListPos pos = list_first(lst);
    pos = list_insert(pos, "Apple");
    pos = list_next(pos);
    pos = list_insert(pos, "Banana");
    pos = list_next(pos);
    pos = list_insert(pos, "Citrus");
}

ListPos list_end(List *lst)
{
    ListPos pos = {
        .node = &lst->head
    };
    return pos;
}

ListPos list_first(List *lst)
{
    ListPos pos = {
        .node = lst->head.next
    };
    return pos;
}
ListPos list_next(ListPos pos)
{
  struct node* node;

  //pos = node -> next;
  struct node *before = pos.node->prev;
  struct node *after = pos.node;

   node->next = after;
   after->prev = node;

  pos.node = node;
    return pos;
}
ListPos list_insert(ListPos pos, const char *value)
{
    // Create a new node.
    struct node *node = make_node(value);

    // Find nodes before and after (may be the same node: the head of the list).
    struct node *before = pos.node->prev;
    struct node *after = pos.node;

    // Link to node after.
    node->next = after;
    after->prev = node;

    // Link to node before.
    node->prev = before;
    before->next = node;

    // Return the position of the new element.
    pos.node = node;
    return pos;
}


int main(void)
{

    // Create an empty list.

      List *lst = list_create();
      add_values(lst);
    return 0;
}

在使用函数的行之前必须是函数的原型或函数定义本身。在函数和您指定的其他函数的 typedef 声明之后添加原型定义。

函数中add_values

static void add_values(List *lst)
{
    ListPos pos = list_first(lst);
    //..

调用函数 list_first 尚未声明。

您需要在函数 list_first 的使用前声明函数 list_first

例如

ListPos list_first(List *lst);

static void add_values(List *lst)
{
    ListPos pos = list_first(lst);
    //..

注意这个声明

typedef struct list
{
    struct node head;
} List;

没有多大意义。您应该使用列表的以下声明

typedef struct list
{
    struct node *head;
    struct node *tail;
} List;

函数list_create没有初始化动态分配对象的数据成员。

因此其他函数,例如 list_first 调用未定义的行为来访问未初始化的数据成员 head 就像在这个声明中一样

ListPos pos = {
    .node = lst->head.next
};

implicit declaration of function list_first.

这意味着编译器已经看到一个名为list_first的函数调用,但是您(或您在编译单元中使用的包含文件)没有提供该函数的接口(它返回的类型,或传递给它的参数的列表和类型)在旧 C 中,这是允许的,默认情况下(这可能太大胆了)函数 returns 一个 int 值并采用未定义的列表参数的数量,由此原型定义(可能不正确):

int list_first();

所以您可能需要在头文件中为该函数提供正确的定义(如果该函数是您编写的)并 #include 在您的源文件中,或者只是 #include给出函数定义的文件。

旧版本的标准允许这样做,编译器中的默认行为如上所示,但最新版本的标准禁止这样做(好吧,如果你写了这个函数,为什么不包含一个头文件告诉编译器如何使用它?或者如果你没有,为什么要让编译器猜测而不提供正确的接口?)