Reputation: 960
I have three files: link_list_test.c
, which has main() function. test_lib.h
, and test-lib.c
I defined struct pointer in test_lib.h, and uses the same struct pointers in 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.
Content of 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
#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
#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;
}
Upvotes: 0
Views: 827
Reputation: 1765
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()
? 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
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()
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:
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.
I will go on a bit to write something that you may or may not find useful, so you can stop reading here.
A linked list is a data structure. A container of some stuff. In your case you are trying to build a list of 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.
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
;)
Also you shoud never use globals. Globals are a maintenance disaster and forbidden in may places, business and academy.
extern
as long as you could. This can lead you to many errors on linking programs. You do not need this heremain()
program in a separate file. This way you can write many tests using 10s of main
without changing the code in 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. And the list contains only a pointer to Node
List
List* create();
List* destroy(List*);
Use pointers. Pointers are great in C
. Also we will need
int show(List*, const char*);
int insert(int, List*);
test_lib.h
is now#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. A name maybe? Date of creation?
destroy()
Since we know the size
it is just a loop.
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
? 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.
show()
Also simple, since each List
has a size
inside (encapsulation). And the msg
is very convenient for test, as in the example above
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()
This is very similar to show since we have only forward pointers
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()
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
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;
}
Upvotes: 1
Reputation:
You cannot have code outside a function. Combined your 3 files into 1 as it's just easier to talk about. 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:
#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
Upvotes: 1