简体   繁体   English

C 编程 - 如何在 header 文件中正确声明结构指针

[英]C Programming - How to properly declare a struct pointer in header file

I have three files: link_list_test.c , which has main() function.我有三个文件: link_list_test.c ,其中有 main() function。 test_lib.h , and test-lib.c test_lib.htest-lib.c

I defined struct pointer in test_lib.h, and uses the same struct pointers in test_lib.c.我在 test_lib.h 中定义了结构指针,并在 test_lib.c 中使用了相同的结构指针。 However, it is not letting me compile.但是,它不允许我编译。

The complain I get is我得到的抱怨是

#  test_lib.c, on this line `first_node = malloc(sizeof(struct node_lib));`
conflicting types for 'first_node'; have 'int'
 
# test_lib.c, struct node_lib *first_node;
previous declaration of 'first_node' with type 'struct node_lib *'

# test_lib.c, if (first_node == NULL) {
expected identifier or '(' before 'if'

# test_lib.c, line first_node->value = 0;
expected '=', ',', ';', 'asm' or '__attribute__' before '->' token

# test_lib.c, first_node = malloc(sizeof(struct node_lib));
data definition has no type or storage class


# test_lib.c, first_node = malloc(sizeof(struct node_lib));
type defaults to 'int' in declaration of 'first_node' [-Wimplicit-int]

What does this mean?这是什么意思?

I use VScode and GDB.我使用 VScode 和 GDB。

Content of test_lib.h : test_lib.h的内容:

#ifndef TEST_LIB_H
#define TEST_LIB_H

#include <stdio.h>

struct node_lib {
    int value;
    struct node_lib *next;
};
extern struct node_lib *first_node;
extern struct node_lib *current_node;
#endif

Content of test_lib.c test_lib.c的内容

#include "test_lib.h"
#include <stdlib.h>
#include <stdio.h>

struct node_lib *first_node;

first_node = malloc(sizeof(struct node_lib));

if (first_node == NULL) {
    printf("Unable to allocate memory for new node_lib\n");
    exit(EXIT_FAILURE);
}

first_node->value = 0;

// every time calling create_new_node(new_value),
// expect first_node to append a new node with new_value.
void create_new_node(int value) {
    
    struct node_lib *new_list, *p;    

    new_list = malloc(sizeof(struct node_lib));

    if (new_list == NULL) {
        printf("Unable to allocate memory for new node_lib\n");
        exit(EXIT_FAILURE);
    }
    new_list->value = value;
    new_list->next = NULL;

    p = first_node;
    while (p->next != NULL) {
        p = p->next;
    }
    p->next = new_list;
    
   printf("%n\n", value);


}

Content of link_list_test.c link_list_test.c的内容

#include "test_lib.h"
#include <stdio.h>
#include <stdlib.h>

int main() {

    create_new_node(1);
    create_new_node(2);
    create_new_node(3);

    return 0;
}

You cannot have code outside a function.您不能在 function 之外拥有代码。 Combined your 3 files into 1 as it's just easier to talk about.将您的 3 个文件合并为 1 个,因为它更容易谈论。 create_new_node() becomes a little more compact if you use a pointer to pointer ( n ) to where you want to insert a new node:如果您使用指向要插入新节点的指针 ( n ) 的指针, create_new_node()会变得更加紧凑:

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

struct node_lib {
    int value;
    struct node_lib *next;
};
struct node_lib *first_node = NULL;

void create_new_node(int value) {
    struct node_lib **n;
    for(n = &first_node; (*n); n = &(*n)->next);
    *n = malloc(sizeof(**n));
    if(!*n) {
        printf("Unable to allocate memory for new node_lib\n");
        exit(EXIT_FAILURE);
    }
    (*n)->value = value;
    (*n)->next = NULL;
}

void print_nodes() {
    for(struct node_lib *n = first_node; n; n = n->next) {
        printf("value=%d\n", n->value);
    }
}

int main() {
    create_new_node(1);
    create_new_node(2);
    create_new_node(3);
    print_nodes();
    return 0;
}

and it prints:它打印:

1
2
3

The first message compiling your code is编译代码的第一条消息是

link_list_test.c(7,5): warning C4013: 'create_new_node' undefined; \
assuming extern returning int

And where are the lines of create_new_node() ? create_new_node()的行在哪里? Just below the floating lines就在浮线下方

struct node_lib *first_node;

first_node = malloc(sizeof(struct node_lib));

if (first_node == NULL) {
    printf("Unable to allocate memory for new node_lib\n");
    exit(EXIT_FAILURE);
}

first_node->value = 0;

in link_list_test.clink_list_test.c

as told in other answers you can not have this code outside functions.如其他答案所述,您不能在函数之外使用此代码。 Wrapping those misplaced lines inside a function, let us say first_code()将那些错位的行包裹在 function 中,让我们说first_code()

void first_code()
{
    first_node = malloc(sizeof(struct node_lib));
    if (first_node == NULL)
    {
        printf(
            "Unable to allocate memory for new node_lib\n");
        exit(EXIT_FAILURE);
    }
    first_node->value = 0;
    return;
}

makes the compiler ok with the code and 2 errors remain:使编译器可以使用代码,并且仍然存在 2 个错误:

test_lib.c(41,12): warning C4477: 'printf' : format string '%n' \
requires an argument of type 'int *', but \
 variadic argument 1 has type 'int'
test_lib.c(41,12): warning C4313: 'printf': '%n' in format string \
 conflicts with argument 1 of type 'int'

here这里

    printf("%n\n", value);

and by changing %n to the normal %d your code compiles ok.通过将%n更改为正常的%d您的代码可以编译。

I will go on a bit to write something that you may or may not find useful, so you can stop reading here.我会在 go 上写一些你可能会或可能不会觉得有用的东西,所以你可以在这里停止阅读。

A linked list is a data structure.链表是一种数据结构。 A container of some stuff.一些东西的容器。 In your case you are trying to build a list of int .在您的情况下,您正在尝试构建一个int列表。

But a list is a collection of nodes and are the nodes that point to (or contain) a unit of the thing that is supposed to go into the list.但是列表是节点的集合,并且是指向(或包含)一个单元的节点,该单元应该是 go 进入列表。

You should write the code in this way and your life will be easier: your next list can be the unavoiadable list of books, then the playlists, them some Person struct ;)您应该以这种方式编写代码,您的生活会更轻松:您的下一个列表可以是不可避免的书籍列表,然后是播放列表,它们是一些 Person struct ;)

Also you shoud never use globals.你也不应该使用全局变量。 Globals are a maintenance disaster and forbidden in may places, business and academy. Globals 是一种维护灾难,在可能的地方、商业和学院中是被禁止的。

  • As a list is a dynamic thing consider using only pointers.由于列表是动态的,请考虑仅使用指针。
  • For help in testing write at first a function to navigate the list.如需测试帮助,请首先编写 function 以导航列表。
  • avoid extern as long as you could.尽可能避免extern This can lead you to many errors on linking programs.这可能会导致您在链接程序时出现许多错误。 You do not need this here你在这里不需要这个
  • always write your code the way you did: a header and the functions, and the main() program in a separate file.始终按照您的方式编写代码:header 和函数以及main()程序在单独的文件中。 This way you can write many tests using 10s of main without changing the code in main.这样,您可以使用 10 秒的main编写许多测试,而无需更改 main 中的代码。 Never write all in a single file: testing is a mess and you will not be able to use the same code in other programs...永远不要将所有内容都写在一个文件中:测试是一团糟,您将无法在其他程序中使用相同的代码......

I will change your code as an example:我将更改您的代码作为示例:

Here we can have the node and the list:这里我们可以有节点和列表:

typedef struct st_node
{
    int             value;
    struct st_node* next;
}   Node;

typedef struct
{
    size_t size;
    Node*  start;
}   List;

And you see the list has a convenient size that is size_t , unsigned.您会看到列表有一个方便的size ,即size_t ,无符号。 And the list contains only a pointer to Node并且该列表仅包含指向Node的指针

making life easier: creating and destroying List让生活更轻松:创建和销毁List

List* create();
List* destroy(List*);

Use pointers.使用指针。 Pointers are great in C .指针在C中很棒。 Also we will need我们也需要

int   show(List*, const char*);
int   insert(int, List*);

So test_lib.h is now所以test_lib.h现在是

#ifndef TEST_LIB_H
#define TEST_LIB_H
#include <stdio.h>

typedef struct st_node
{
    int             value;
    struct st_node* next;
}   Node;

typedef struct
{
    size_t size;
    Node*  start;
}   List;

List* create();
List* destroy(List*);
int   show(List*, const char*);
int   insert_end(int, List*);
int   insert_start(int, List*);

#endif

implementing the 4 functions实现4个功能

create()

List* create()
{
    List* one = (List*) malloc(sizeof(List));
    if ( one == NULL ) return NULL;
    one->size = 0;
    one->start = NULL;
    return one;
};

It is easier to return a new List this way and each new List will have size 0 and pointers and whatever metadata you can need.以这种方式返回一个新列表更容易,每个新Listsize为 0 和指针以及您可能需要的任何元数据。 A name maybe?可能是名字? Date of creation?创建日期?

destroy()

Since we know the size it is just a loop.因为我们知道size ,所以它只是一个循环。

List* destroy(List* L)
{  // here you write the code to
    // delete the `size` nodes and
    // free them
    if (L == NULL) return NULL;
    Node* p = L->start; // the 2nd or NULL
    Node* temp = NULL;
    for (size_t i = 0; i < L->size; i += 1)
    {   // delete a node
        temp = p->next;
        free(p);
        p = temp;        
    }   // for
    free(L);
    return NULL;
}

Why return NULL ?为什么返回NULL For safety.为了安全。 This code:这段代码:

#include <stdio.h>
#include <stdlib.h>
#include "test_lib.h"
int main(void)
{
    List* one = create();
    show(one, "still empty");
    one = destroy(one);
    return 0;
}

Runs and shows跑步和表演

still empty
List: 0 elements

So you see that the pointer to the list can be set to NULL at the same line the list is destroyed: zero chances of using an invalid List pointer.所以你看到指向列表的指针可以在列表被破坏的同一行设置为NULL :使用无效List指针的机会为零。

show()

Also simple, since each List has a size inside (encapsulation).也很简单,因为每个List内部都有一个size (封装)。 And the msg is very convenient for test, as in the example above而且msg很方便测试,如上例

int show(List* L, const char* msg)
{
    if (L == NULL) return -1;  // no list
    if (msg != NULL) printf("%s\n", msg);
    Node* p = L->start;  // can be NULL
    printf("List: %d elements\n", (int)L->size);
    for (size_t i = 0; i < L->size; i += 1, p = p->next)
        printf("  %d", p->value);
    printf("\n"); // all in one line: just a test
    return 0;
}

Inserting at the end of the list insert_end()在列表末尾插入insert_end()

This is very similar to show since we have only forward pointers这与 show 非常相似,因为我们只有前向指针

int insert_end(int value, List* l)
{   // the list has `size` elements
    // to insert at the end the last one
    // will point to this new one
    // the code is similar to show()
    if (l == NULL) return -1;  // no list
    Node* new  = (Node*)malloc(sizeof(Node));
    new->value = value;
    new->next  = NULL; // will be the last
    Node* p = l->start; 
    Node* last = NULL;
    for (size_t i = 0; i<l->size; i += 1,p=p->next)
        last = p;
    // so `last` points to the last
    //  even if the list was empty
    l->size += 1;
    if (l->size == 1)
    {   // ok: was empty
        l->start = new; // new start
        return 1;
    }
    last->next = new;
    return (int) l->size;
}

Insert at the start is easier insert_start()在开头插入更容易insert_start()

int insert_start(int value, List* l)
{
    if (l == NULL) return -1; // no list
    Node* new = (Node*)malloc(sizeof(Node));
    new->value = value;
    new->next = NULL;
    // list may be empty
    if (l->size == 0)
    {
        l->start = new;
        l->size   = 1;
        return 1;
    }
    new->next = l->start;
    l->start = new;
    l->size += 1;
    return (int) l->size;
}

a test: insert 1 to 5 at start 10 to 6 at the end一个测试:在开头插入 1 到 5 到结尾插入 10 到 6

#include <stdio.h>
#include <stdlib.h>
#include "test_lib.h"
int main(void)
{
    List* one = create();
    show(one, "still empty");

    for (int i = 5; i >= 1; i -= 1) insert_start(i, one);
    show(one, "1 to 5");

    for (int i = 6; i <= 10; i += 1) insert_end(i, one);
    show(one, "\n1 to 10 if ok...");
    one = destroy(one);
    return 0;
}

That shows这表明

still empty
List: 0 elements

1 to 5
List: 5 elements
  1  2  3  4  5

1 to 10 if ok...
List: 10 elements
  1  2  3  4  5  6  7  8  9  10

If you are still reading you may find writing this way easier to read and maintain.如果您仍在阅读,您可能会发现以这种方式编写更容易阅读和维护。

code for test_lib.c test_lib.c的代码

This is the same as above but easier to copy if you want to test这与上面相同,但如果您想测试更容易复制

#include <stdio.h>
#include <stdlib.h>
#include "test_lib.h"

List* create()
{
    List* one = (List*)malloc(sizeof(List));
    if (one == NULL) return NULL;
    one->size  = 0;
    one->start = NULL;
    return one;
}

List* destroy(List* L)
{  
    if (L == NULL) return NULL;
    Node* p = L->start; // the 2nd or NULL
    Node* temp = NULL;
    for (size_t i = 0; i < L->size; i += 1)
    {   // delete a node
        temp = p->next;
        free(p);
        p = temp;        
    }   // for
    free(L);
    return NULL;
}

int show(List* L, const char* msg)
{
    if (L == NULL) return -1;  // no list
    if (msg != NULL) printf("%s\n", msg);
    Node* p = L->start;  // can be NULL
    printf("List: %d elements\n", (int)L->size);
    for (size_t i = 0; i < L->size; i += 1)
    {
        printf("  %d", p->value);
        p = p->next;
    }
    printf("\n");  // all in one line: just a test
    return 0;
}

int insert_end(int value, List* l)
{   // the list has `size` elements
    // to insert at the end the last one
    // will point to this new one
    // the code is similar to show()
    if (l == NULL) return -1;  // no list
    Node* new  = (Node*)malloc(sizeof(Node));
    new->value = value;
    new->next  = NULL; // will be the last
    Node* p = l->start; 
    Node* last = NULL;
    for (size_t i = 0; i<l->size; i += 1,p=p->next)
        last = p;
    // so `last` points to the last
    //  even if the list was empty
    l->size += 1;
    if (l->size == 1)
    {   // ok: was empty
        l->start = new; // new start
        return 1;
    }
    last->next = new;
    return (int) l->size;
}

int insert_start(int value, List* l)
{
    if (l == NULL) return -1; // no list
    Node* new = (Node*)malloc(sizeof(Node));
    new->value = value;
    new->next = NULL;
    // list may be empty
    if (l->size == 0)
    {
        l->start = new;
        l->size   = 1;
        return 1;
    }
    new->next = l->start;
    l->start = new;
    l->size += 1;
    return (int) l->size;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 header 文件中声明结构并在 .c 文件中定义它 - How do you declare a struct in a header file and define it in the .c file 如何在头文件和c文件中声明函数指针? - How to declare function pointer in header and c-file? 如何用ctypes中的数组声明一个C结构? - How to declare a C struct with a pointer to array in ctypes? 如何在 C 中声明指向结构的指针? - How can I declare a Pointer to a struct in C? 如何声明易失性结构的指针 - how to declare pointer to volatile struct C编程。如果我需要在头文件(.h)中引用它的实例,如何在.c中隐藏结构的实现 - C programming. How to hide implementation of the struct in .c if I need to refer to its instance in header file (.h) 如何在C中声明指向struct的指针数组,然后使用它? - How do declare array of pointer to struct in C and then use it? 如何在 C 中声明和访问指向成员结构成员的指针? - How to declare and access a pointer to a member of a member struct in C? 结构和指针在c中无法正常工作 - struct and pointer not working properly in c 在C中任何方式转发声明struct在头文件而不必在其他文件中使用指针? - Any way in C to forward declare struct in header without having to use pointer in other files?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM