Trying to make linkedlist in C - c

I am trying to make a struct in C that is a linked list. I am not really sure what is going wrong though. My errors are:
linked.c:6:2: error: unknown type name ‘linkedList’
linked.c: In function ‘makeList’:
linked.c:30:2: error: ‘first’ undeclared (first use in this function)
linked.c:30:2: note: each undeclared identifier is reported only once for each function it appears in
linked.c: In function ‘addToList’:
linked.c:36:9: error: used struct type value where scalar is required
linked.c:43:13: error: incompatible types when assigning to type ‘int *’ from type ‘linkedList’
if anybody can see what is wrong and explain it to me, it would be much appreciated. My code is below.
#include <stdio.h>
typedef struct linkedList
{
int first;
linkedList* rest;
} linkedList;
linkedList makeList(int a, int b, int c);
void addToList(linkedList* ll, int a);
int main()
{
linkedList ll = makeList(1,3,5);
addToList(&ll, 7);
addToList(&ll, 9);
return 0;
}
linkedList makeList(int a, int b, int c)
{
linkedList ll;
ll.first = a;
linkedList second;
second.first = b;
linkedList third;
third.first = c;
third.rest = NULL;
second.rest = &c;
first.rest = &b;
return first;
}
void addToList(linkedList* ll, int a)
{
while (*ll)
{
if (ll->rest == NULL)
{
linkedList newL;
newL.first = a;
newL.rest = NULL;
ll->rest = newL;
break;
} else
{
continue;
}
}
}

The C compiler doesn't have a complete typedef of linkedList before you attempt to use it in your struct. You have a couple of options:
typedef struct linkedList
{
int first;
struct linkedList* rest;
} linkedList;
Or:
typedef struct linkedList linkedList; // C allows this forward declaration
struct linkedList
{
int first;
linkedList* rest;
};
This is your starting point.
Additional problems include but are not limited to:
Your makeList function refers to variable first but it doesn't appear to be defined anywhere.
ll->rest = newL; assigned a type linkedList to a pointer to linkedList (linkedList *) you can't assign a value to a pointer-to-value. The compiler error message linked.c:43:13:... states this. It would need to be ll->rest = &newL;... HOWEVER...
newL is LOCAL to the function addToList, so you can't assign it's address to a persistent list item since it will go out of scope when the code leaves that block.
In addToList you are assigning pointer to integer to a variable that holds pointer to linkedList, e.g., second.rest = &c;.

here's a corrected version of your program :
#include <stdio.h>
#include <stdlib.h>
typedef struct linkedList
{
int first;
struct linkedList* rest; // add struct in the beginning
} linkedList;
linkedList* addToList(linkedList* ll, int a);
void go_trough(linkedList *ll); // here's an extra function to check
int main()
{
linkedList *ll ; // working with a pointer is easier and makelist is pointless work with add to list instead
ll = NULL; // initialize to NULL
ll = addToList(ll, 7);
ll = addToList(ll, 9);
go_trough(ll);
return 0;
}
linkedList* addToList(linkedList* ll, int a) // I didn't understand what you were trying to do so ... here's my version
{
if(!ll)
{
ll = malloc(sizeof(linkedList*)); //allocating enought space to hold the structure
ll->first = a;
ll->rest = NULL;
}
else
ll->rest = addToList(ll->rest , a);
return ll;
}
void go_trough(linkedList *ll)
{
if(ll)
{
printf("%d\n" , ll->first);
go_trough(ll->rest);
}
}

in makeList change
second.rest = &c;
first.rest = &b;
to
ll.rest = &second;
second.rest = &third;
in the original you were giving the adresses of the int variables instead of the linkedList nodes. also, you had a variable 'first' which was never declared, that's where one of errors were taking place.
also try declaring all your variables first, it makes it easier to read.

A few observations,
declare a struct name so that you can use it in the linkedList struct.
DRY - Don't Repeat Yourself, that is why the below ListNew() function is provided
use pointers, that is the whole point to building a linked list anyway,
your list uses one type of node, storing data and the list pointer,
name the pointer to the next node in the list whatever you want, how about 'next'?
name the thing that holds data anything you want, how about 'data'?
print the list, it will help figure out what is going on, :-)
a pointer can be printed in hexadecimal using the %x print format
Anyway, here is a single linked list, without keeping track of the tail of the list, or counting the elements.
#include <stdio.h>
#include <stdlib.h>
typedef struct listnode
{
int data;
struct listnode* next;
} linkedList;
linkedList* makeList(int a, int b, int c);
void addToList(linkedList* ll, int a);
void ListPrint(linkedList* ll);
int main()
{
linkedList* ll = makeList(1,3,5);
addToList(ll, 7);
addToList(ll, 9);
ListPrint(ll);
return 0;
}
linkedList* ListNew(int a) //new linkedList node
{
linkedList* newL = (linkedList*)malloc(sizeof(linkedList));
newL->data = a;
newL->next = NULL;
return newL;
}
linkedList* makeList(int a, int b, int c)
{
linkedList* ll = ListNew(a);
addToList(ll, b);
addToList(ll, c);
return ll;
}
void addToList(linkedList* ll, int a)
{
if(!ll) return;
//find end of list
while (ll->next)
{
ll = ll->next;
}
ll->next = ListNew(a);
return;
}
void ListPrint(linkedList* ll) //print list
{
if(!ll) return;
linkedList* p;
for( p=ll; p; p=p->next )
{
printf("%x: %d\n",p,p->data);
}
return;
}

Related

Code is printing pointer address (I think) instead of value?

I have a list defined as
typedef struct node {
Voo *voo;
ListaReservas nodeReservas; /* Ignore this */
struct node *next;
} *Node;
I created some functions to help me add or remove nodes from the list like:
/* creates a node */
Node criaNode(Voo v) {
Node new = (Node)malloc(sizeof(struct node));
new->voo = &v;
/* I had new->voo = v; but vscode told me it was wrong so i changed it to &v */
new->next = NULL;
return new;
}
Voo is defined as:
typedef struct {
int dia;
int mes;
int ano;
} Data;
typedef struct {
int horas;
int minutos;
} Tempo;
typedef struct {
char codigo[LEN_CODIGO + 1];
char partidaID[LEN_ID + 1];
char chegadaID[LEN_ID + 1];
Data datapartida;
Tempo horapartida;
Tempo duracao;
Data datachegada;
Tempo horachegada;
int capacidade;
} Voo;
Now I wanted to iterate through the list and print its values as such
Voo *v;
for (n = headVoos; n != NULL; n = n->next) {
v = n->voo;
printf("%s %s %s %.2d-%.2d-%d %.2d:%.2d\n",
v->codigo, v->partidaID, v->chegadaID,
v->datapartida.dia, v->datapartida.mes, v->datapartida.ano,
v->horapartida.horas, v->horapartida.minutos);
}
The program is not printing correctly. For example where it should appear
AA1 AAA AAD 16-03-2022 14:50
its appearing instead
� 146187376-32765--1940381952 40355300:50
What's causing this and how can I avoid it in the future?
EDIT
After replacing in the struct node the Voo *voo definition by Voo voo, I am now getting an error in one of the auxiliary functions:
/* deletes node */
Node eliminaNode(Node head, Voo v)
{
Node n, prev;
for (n = head, prev = NULL; n != NULL; prev = n, n = n->next)
{
if (n->voo == v) /* expression must have arithmetic or pointer error */
{
if (n == head)
head = n->next;
else
prev->next = n->next;
free(n->next);
free(n);
break;
}
}
return head;
}
In criaNode you're taking the address of the parameter v and returning it from the function via a pointer to dynamic memory. That address is no longer valid after the function returns. Subsequently dereferencing that invalid address then triggers undefined behavior.
It probably makes more sense for struct node to contain a Voo directly instead of a pointer to one. So change the member to a non-pointer:
Voo voo;
And assign the parameter directly:
new->voo = v;
There are multiple problems here:
there seems to be a confusion between structures and pointers to structures. In C, you must understand the difference between manipulating objects (allocating as local objects or from the head, passing as arguments or returning as values) and pointers to objects, which are a more idiomatic as arguments to functions and allow functions to modify the object they point to.
the confusion is amplified by a very error prone construction: hiding pointers behind typedefs. Do not do that, define object types for the actual structure, using the same or a different name as the struct tag, and make all pointers explicit with the * syntax.
you pass an actual Voo object as an argument and allocate a list node using the address of this argument. This is incorrect because the argument will be discarded as soon as the function returns, makeing the list point to invalid memory and explaining the weird output you observe.
Node eliminaNode(Node head, Voo v) should take a pointer to the head node and return a success indicator. It should take a Voo * argument and it should not free(n->next) because the next node is still in use after the removal.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#define LEN_CODIGO 30
#define LEN_ID 30
typedef struct Data {
int dia;
int mes;
int ano;
} Data;
typedef struct Tempo {
int horas;
int minutos;
} Tempo;
typedef struct Voo {
char codigo[LEN_CODIGO+ 1];
char partidaID[LEN_ID + 1];
char chegadaID[LEN_ID + 1];
Data datapartida;
Tempo horapartida;
Tempo duracao;
Data datachegada;
Tempo horachegada;
int capacidade;
} Voo;
typedef struct Node {
struct Voo *voo;
//ListaReservas nodeReservas; /* Ignore this */
struct Node *next;
} Node;
/* creates a node */
Node *criaNode(Voo *v) {
/* allocation with calloc is safer as the object will be initialized to 0 */
Node *nodep = calloc(1, sizeof(*new));
if (nodep) {
nodep->voo = v;
nodep->next = NULL;
}
return nodep;
}
/* deletes node */
int eliminaNode(Node **head, Voo *v) {
for (Node *n = *head, *prev = NULL; n != NULL; prev = n, n = n->next) {
if (n->voo == v) {
if (n == *head)
*head = n->next;
else
prev->next = n->next;
free(n);
return 1; /* article was found and freed */
}
}
return 0; /* article was not found */
}
void printList(const Node *head) {
for (const Node *n = head; n != NULL; n = n->next) {
const Voo *v = n->voo;
printf("%s %s %s %.2d-%.2d-%.2d %.2d:%.2d\n",
v->codigo, v->partidaID, v->chegadaID,
v->datapartida.dia, v->datapartida.mes, v->datapartida.ano,
v->horapartida.horas, v->horapartida.minutos);
}
}

What does a function whose 'return type' is a tag do?

I've been learning C for a month now and I've learned/remember that functions are defined like this:
return_type function_name( parameter list ) {
...body
}
But in a lecture about 'list ADTs' the example code which illustrates making and printing a full list there were some pieces of code(function declarations) in a form that I've never seen.
...
typedef struct list{ int data; struct list *next; } list;
list* create_list(int d) {
...
}
To my understanding the return type is ' list '(?) which is a structure tag, and the function name is ' * create_list ' (which is a dereferenced pointer??). I couldn't understand why it was written like that. I want to know how it works and how to use it. How does it differ from other (normal looking)functions like struct create_list(int d) {...}? The instructor didn't mention or explain about these so I'm quite confused.
here is the full code just in case
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
typedef struct list{ int data; struct list *next;} list;
int is_empty(const list *l) { return (l == NULL); }
list* create_list(int d) {
list* head = malloc(sizeof(list));
head -> data = d;
head -> next = NULL;
return head;
}
list* add_to_front(int d, list* h) {
list* head = create_list(d);
head -> next = h;
return head;
}
list* array_to_list(int d[], int size) {
list* head = create_list(d[0]);
int i;
for(i = 1; i < size; i++) {
head = add_to_front(d[i], head);
}
return head;
}
void print_list(list *h, char *title) {
printf("%s\n", title);
while (h != NULL) {
printf ("%d :", h -> data);
h = h -> next;
}
}
int main() {
list list_of_int;
list* head = NULL;
int data[6] = {2,3,5,7,8,9};
head = array_to_list(data, 6);
print_list(head, "single element list");
printf("\n\n");
return 0;
}
any help would be appreciated!
Please correct me if I'm wrong in some point. Thank you
You're close, but reading it wrong. Function names do not have things like * in them, only types do.
This defines a function that returns list* (a.k.a. struct list* which is what typedef establishes earlier) given argument d of type int:
list* create_list(int d) {
// ...
}
In other words, create_list returns a pointer to list. In a type definition * means pointer, but it has a different meaning as an operator, such as:
int x = 0;
int* y = &x;
*y = 5; // Dereference y pointer, make assignment, in other words, assign to x
You can usually spot a dereference operator because it is not part of a type either in a return type specifier, an argument, or a variable declaration. In most other cases it's the dereference operator.
To my understanding the return type is ' list '(?) which is a structure tag
In your example list is both a struct tag and a typedef name. The name space rules of C allow four different categories of identifiers:
lables (for goto etc)
struct/union/enum tags (struct this_is_a_tag).
struct/union members
everything else
It's valid to name identifiers from these different name spaces the same.
In the example
typedef struct list{ int data; struct list *next;} list;
the typedef list identifier isn't available until at the end of the declaration (after the ;). The struct tag struct list is, however. So the struct list *next; member refers to the struct tag, which is a convenient way create a self-referencing struct. Once the typedef is declared, we can either use list to refer to the typedef:ed struct type, or we can use struct list which means the very same thing - when used outside the struct declaration it's just a style preference which form to use.
So list* create_list(int d) is using the typedef list to declare the return type of the function as a pointer to struct, list*. No different from returning any variable by value vs returning a pointer to it.
In this case the function is calling malloc to create a struct variable, so the function needs to return a pointer because anything allocated by malloc is always accessed through pointers.

How to make changes in an array through a function

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define SIZE 10
// A hashtable is a mixture of a linked list and array
typedef struct node NODE;
struct node{
int value;
NODE* next;
};
int hash(int);
void insert(int,NODE **);
int main(){
NODE* hashtable[SIZE];
insert(12,&hashtable[SIZE]);
printf("%d\n",hashtable[5]->value);
}
int hash(int data){
return data%7;
}
void insert(int value,NODE **table){
int loc = hash(value);
NODE* temp = malloc(sizeof(NODE));
temp->next = NULL;
temp->value = value;
*table[loc] = *temp;
printf("%d\n",table[loc]->value);
}
The above code prints :
12 and
27475674 (A random number probably the location.)
how do I get it to print 12 and 12 i.e. how to make a change in the array. I want to fill array[5] with the location of a node created to store a value.
The expression *table[loc] is equal to *(table[loc]) which might not be what you want, since then you will dereference an uninitialized pointer.
Then the assignment copies the contents of *temp into some seemingly random memory.
You then discard the memory you just allocated leading to a memory leak.
There's also no attempt to make a linked list of the hash-bucket.
Try instead to initially create the hashtable array in the main function with initialization to make all pointers to NULL:
NODE* hashtable[SIZE] = { NULL }; // Will initialize all elements to NULL
Then when inserting the node, actually link it into the bucket-list:
temp->next = table[loc];
table[loc] = temp;
This is just a simple change which I have made to your program which will tell you what you are actually doing wrong.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define SIZE 10
// A hashtable is a mixture of a linked list and array
typedef struct node NODE;
struct node {
int value;
NODE* next;
};
NODE *hashtable[SIZE] = { NULL };
int hash(int);
int insert(int); //, NODE **);
int main(void)
{
int loc = insert(12); //, &hashtable[SIZE]);
if (loc < SIZE) {
if (hashtable[loc]) {
printf("%d\n", hashtable[loc]->value);
} else {
printf("err: invalid pointer received\n");
}
}
return 0;
}
int hash(int data)
{
return data%7;
}
int insert(int value) //, NODE *table[])
{
int loc = hash(value);
printf("loc = %d\n", loc);
if (loc < SIZE) {
NODE *temp = (NODE *) malloc(sizeof(NODE));
temp->value = value;
temp->next = NULL;
hashtable[loc] = temp;
printf("%d\n", hashtable[loc]->value);
}
return loc;
}
Here I have declared the hashtable globally just to make sure that, the value which you are trying to update is visible to both the functions. And that's the problem in your code. Whatever new address you are allocating for temp is having address 'x', however you are trying to access invalid address from your main function. I just wanted to give you hint. Hope this helps you. Enjoy!

Conflicting type for function error

This is my first C program and I don't know why I get the error below.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
struct ListNode* next;
int content;
} ListNode;
int main() {
//puts("Hello UPC World"); /* prints Hello UPC World */
//ListNode* h = malloc(sizeof(ListNode));
gridinit(3, 5);
//int c = h->content;
//printf("%d",c);
return EXIT_SUCCESS;
}
ListNode* gridinit(int numcolumns, int numrows) {
ListNode* head = malloc(sizeof(ListNode));
head->content = 2;
head->next = NULL;
return head;
}
Why do I get an error saying
type conflict in func gridinit()
Define your function declaration at the top of your struct
ListNode* gridinit(int numcolumns, int numrows);
typedef struct {
struct ListNode* next;
int content;
} ListNode;
int main() {
//puts("Hello UPC World"); /* prints Hello UPC World */
//ListNode* h = malloc(sizeof(ListNode));
gridinit(3, 5);
//int c = h->content;
//printf("%d",c);
return EXIT_SUCCESS;
}
ListNode* gridinit(int numcolumns, int numrows) {
ListNode* head = malloc(sizeof(ListNode));
head->content = 2;
head->next = NULL;
return head;
}
That is because your function is defined after it is called. You can declare a prototype of the function just after your struct and before main as
ListNode* gridinit(int numcolumns, int numrows);
and you will be good for compile.
TL;DR answer - For all the functions which are used (called) before they are defined, you need to add a forward declaration for those functions before the caller function. In this case, as the definition of gridinit() is written after main() and main() uses gridinit() you have to add the forward declaration of gridinit() before main() and you'll be good to go.
To elaborate the case, in your main() function, you're calling gridinit(), but till that point, compiler has no idea about the prototype of the gridinit() function.
Due to backward compatibility, a feature called implicit declaration of a function assumes that a function, which has been used before it is defined or declared, accepts any number of parameters and returns an int.
Later, when you're actually defining the function, you're making the return type as ListNode*, which is creating the conflict here.
FWIW, as per the C99 standard (onwards), the (evil) feature of implicit function declaration has been officially removed but compilers still continue to support the same for legacy code. If you enable compiler warnings and compile with strict conformance, you should get warned (or even stopped) by your compiler, in case, a forward declaration is missing.
Add a forward declaration for gridinit() and everything works fine:
...
typedef struct {
struct ListNode* next;
int content;
} ListNode;
// Declare the gridinit function
ListNode* gridinit(int, int);
...
There should be a declaration or definition of gridinit before it is called in main (the compiler needs to know it exists).
Also, you should not ignore the return value of gridinit, which returns a pointer you have allocated memory for (ignoring it would therefore cause a memory leak), instead you should assign it to h without allocating memory in main (because you're doing that already in gridinit).
#include <stdio.h>
#include <stdlib.h>
typedef struct {
struct ListNode* next;
int content;
} ListNode;
ListNode* gridinit(int numcolumns, int numrows) {
int main() {
//puts("Hello UPC World"); /* prints Hello UPC World */
ListNode* h = gridinit(3, 5);
int c = h->content;
printf("%d",c);
return EXIT_SUCCESS;
}
ListNode* gridinit(int numcolumns, int numrows) {
ListNode* head = malloc(sizeof(ListNode));
head->content = 2;
head->next = NULL;
return head;
}

Passing argument from incompatible pointer type warning

I've been trying to figure out pointers in C most of today, even asked a question earlier, but now I'm stuck on something else. I've got the following code:
typedef struct listnode *Node;
typedef struct listnode {
void *data;
Node next;
Node previous;
} Listnode;
typedef struct listhead *LIST;
typedef struct listhead {
int size;
Node first;
Node last;
Node current;
} Listhead;
#define MAXLISTS 50
static Listhead headpool[MAXLISTS];
static Listhead *headpoolp = headpool;
#define MAXNODES 1000
static Listnode nodepool[MAXNODES];
static Listnode *nodepoolp = nodepool;
LIST *ListCreate()
{
if(headpool + MAXLISTS - headpoolp >= 1)
{
headpoolp->size = 0;
headpoolp->first = NULL;
headpoolp->last = NULL;
headpoolp->current = NULL;
headpoolp++;
return &headpoolp-1; /* reference to old pointer */
}else
return NULL;
}
int ListCount(LIST list)
{
return list->size;
}
Now in a new file I have:
#include <stdio.h>
#include "the above file"
main()
{
/* Make a new LIST */
LIST *newlist;
newlist = ListCreate();
int i = ListCount(newlist);
printf("%d\n", i);
}
When I compile, I get the following warning (the printf statement prints what it should):
file.c:9: warning: passing argument 1 of ‘ListCount’ from incompatible pointer type
Should I be worried about this warning? The code seems to do what I want it to, but I'm obviously very confused about pointers in C. After browsing questions on this site, I found that if I make the argument to ListCount (void *) newlist, I don't get the warning, and I don't understand why, nor what (void *) really does...
Any help would be appreciated, thanks.
You're getting confused because of multiple typedefs. LIST is a type representing a pointer to struct listhead. So, you want your ListCreate function to return a LIST, not a LIST *:
LIST ListCreate(void)
The above says: ListCreate() function will return a pointer to a new list's head if it can.
Then you need to change the return statement in the function definition from return &headpoolp-1; to return headpoolp-1;. This is because you want to return the last available head pointer, and you have just incremented headpoolp. So now you want to subtract 1 from it and return that.
Finally, your main() needs to be update to reflect the above changes:
int main(void)
{
/* Make a new LIST */
LIST newlist; /* a pointer */
newlist = ListCreate();
int i = ListCount(newlist);
printf("%d\n", i);
return 0;
}

Resources