[英]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.h
和test-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.c
在
link_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 是一种维护灾难,在可能的地方、商业和学院中是被禁止的。
extern
as long as you could.extern
。 This can lead you to many errors on linking programs.main()
program in a separate file.main()
程序在单独的文件中。 This way you can write many tests using 10s of main
without changing the code in main.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
的指针
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*);
test_lib.h
is nowtest_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
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.以这种方式返回一个新列表更容易,每个新
List
的size
为 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;
}
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_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;
}
#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.如果您仍在阅读,您可能会发现以这种方式编写更容易阅读和维护。
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.