Linked List Null in C - c

i dont know why the list returned is NULL, this is the code:
In my List.h
struct nodo_ {
char* dato;
struct nodo_ *next;
};
struct nodo_ *Lista;
/*Def list */
void createList(struct nodo_ **Lista);
in my main.c
struct nodo_ *Lista;
int main(){
createList(Lista);
while(Lista != NULL){
printf("The date is %s\n ",Lista->dato); //Error here now
Lisa = Lista->next;
}
return 0 ;
}
in my List.c im create the List :
void createList(struct nodo_ *Lista){
struct nodo_ *Aux_List = list_D;
aux_List = malloc(sizeof(struct nodo_));
char* path_a = "Hello";
char* path_B = "Minasan";
/* Store */
aux_List->dato = path_a;
aux_List = Aux_List->next;
aux_List = malloc(sizeof(struct nodo_));
aux_List->dato = path_b;
aux_List->next = NULL;
}
Thanks.

That pointer is being passed by value, i.e., a copy is made. If you wish to initialize the pointer to a completely new value then you must use another level of indirection (i.e., a nodo_**).
On a side note, typedefing pointer types is almost always a bad idea unless the type is truly opaque (which yours is not). One reason for this "rule" is evident when you consider another bug in your code:
auxList = (Lista*)malloc(sizeof(Lista));
You're allocating space for a pointer to noda_, not enough for a noda_ object. Also, don't cast the return value of malloc in C. It is redundant as a void* is safely and implicitly converted to any other pointer type and, if you forget to include stdlib.h, malloc will be assumed to be a function which returns int, and the cast hides the error. (only applies to compilers which implement C89 or an older version)
EDIT:
To initialize a pointer argument within a function:
void init(struct node **n) {
if(n)
*n = malloc(sizeof(struct node));
}
int main() {
struct node *n;
init(&n);
}

Short answer to your actual question before I dig into the code:
... why the list returned is NULL ...
There is no returned list, you neither use return to pass a result, nor set the value of an out parameter.
In your edited code:
void createList(struct nodo_ **Lista){
struct nodo_ *Aux_List = list_D;
aux_List = malloc(sizeof(struct nodo_));
you first set Aux_List to the current value of Lista, which you know isn't initialized yet, because you're trying to initialize it. Then you discard that value, overwriting aux_List with a new address returned by malloc. You never store anything into *Lista, which would be the only way for this function to work as declared.
As Ed suggests, your typedef is hiding lots of useful information from you, so let's expand it out
struct nodo {
char* dato;
struct nodo *next;
};
/*Def list */
void createList(struct nodo* list_D);
Now, you can see this createList is wrong: you can pass in the head node of a list (which is no use to it anyway), but there is no way for it to return a newly-allocated list to the caller.
Frankly your createList isn't a useful primitive anyway, so I'm going to start with a sensible foundation first:
struct nodo *alloc_nodo(char *dato, struct nodo *next)
{
struct nodo *n = malloc(sizeof(*n));
n->dato = dato;
n->next = next;
return n;
}
Now, before we re-write your createList using this, let's see what it does now:
void createList(struct nodo *list_D)
{
struct nodo *aux_List = list_D;
aux_List = malloc(sizeof(struct nodo_));
/* ^ so, we take the input argument and immediately discard it */
char* path_a = "Hello";
char* path_B = "Minasan";
/* Store */
aux_List->dato = path_a;
aux_List = Aux_List->next;
/* ^ note that we haven't initialized aux_List->next yet,
so this is a random pointer value */
aux_List = malloc(sizeof(struct nodo_));
/* again, we set aux_List to something,
but immediately overwrite and discard it */
aux_List->dato = path_b;
aux_List->next = NULL;
}
So, it ignores its input, returns no output, and leaks two partially-initialized nodes which aren't connected to each other. I believe you wanted to achieve something more like this:
struct nodo* create_my_list()
{
struct nodo *tail = alloc_nodo("Minasan", NULL);
/* the end (tail) of the linked list has a NULL next pointer */
struct nodo *head = alloc_nodo("Hello", tail);
/* the head of the linked list points to the next node */
return head;
/* like a snake, you hold a singly-linked list by the head */
}
If we write main to use this function now, it looks like:
int main()
{
struct nodo *head = create_my_list();
struct nodo *n;
for (n = head; n != NULL; n = n->next)
{
printf("The date is %s\n ", n->dato);
}
}

Related

i am having problems understanding this code, can someone help me explicitly explain it, expecially " while (size--) & tmp = (int *)&node->n;"

#include <stdio.h>
#include <stdlib.h>
/**
* struct listint_s - Doubly linked list node
*
* #n: Integer stored in the node
* #prev: Pointer to the previous element of the list
* #next: Pointer to the next element of the list
*/
typedef struct listint_s // generating a structure
{
const int n;
struct listint_s *prev;
struct listint_s *next;
} listint_t;
/**
* create_listint - Creates a doubly linked list from an array of integers
*
* #array: Array to convert to a doubly linked list
* #size: Size of the array
*
* Return: Pointer to the first element of the created list. NULL on failure
*/
listint_t *create_listint(const int *array, size_t size)
{
listint_t *list;
listint_t *node;
int *tmp;
list = NULL;
while (size--)
{
node = malloc(sizeof(*node));
if (!node)
return (NULL);
tmp = (int *)&node->n;
*tmp = array[size];
node->next = list;
node->prev = NULL;
list = node;
if (list->next)
list->next->prev = list;
}
return (list);
}
I am having difficulty understanding these lines of code
while (size--)
and
tmp = (int *)&node->n;
When will the code exit the while loop, also i really want to understand how this piece of code works.
Within the structure
typedef struct listint_s // generating a structure
{
const int n;
struct listint_s *prev;
struct listint_s *next;
} listint_t;
the data member n is declared with the qualifier const. So you may not directly assign to it a value like for example
node->n = array[size];
The compiler will issue an error saying that you are trying to change a constant object.
So there is used a trick. At first there is declared a pointer to the object as a pointer to a non-constant object
int *tmp;
and this pointer is assigned with the address of the data member node->n using casting
tmp = (int *)&node->n;
The casting is required because the expression &node->n has the type const int *
And then using the pointer tmp a value is assigned to the constant object
*tmp = array[size];
As for this while loop
while (size--)
the it iterates while the number of elements in the array is not equal to 0. You may rewrite the while loop like
while ( size-- != 0 )
The function adds new elements in the beginning of the list storing in it values of the passed array starting from the last element of the array and down to the first element of the array. .
Pay attention to that the function is unsafe. It can produce memory leaks if some node will not be dynamically allocated due to this if statement
node = malloc(sizeof(*node));
if (!node)
return (NULL);

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);
}
}

Sorted Insertion in linked list

I'm trying to create a function that does sorted insertion based on two variables, level and name. Apparently I'm having some logic and syntax errors.
My linked list structure:
struct node {
struct node *next;
int level;
char name;
};
My string compare function:
int compare(struct node *one, struct node *two)
{
return strcmp(one->name, two->name);
}
My insertion function:
void insert(struct node **head, const int level, const char name, int(*cmp)(struct node *l, struct node *r))
{
struct node *new =NULL;
/* Find the insertion point */
for (; *head; head = &(*head)->next)
{
if ((*head)->level > level) { // I think this is what is causing the issue
if (compare(*head, new) > 0)
break;
}
}
new = malloc(sizeof *new);
new->level = level;
new->name = name;
new->next = *head;
*head = new;
}
and this is the call stack:
insert(node **head, const int level, const char name, int(*)(node *, node *))
Your syntax error is this line:
return strcmp(one->name, two->name);
The function strcmp expect two char* (aka char pointers) but you give it two char.
The problem is... Do you want
char name;
or
char* name;
That is important in order to get compare right.
Further you need to rearrange your insert function so that you create the new node before using it. Something like:
void insert(struct node **head, const int level, const char name, int(*cmp)(struct node *l, struct node *r))
{
struct node *new =NULL;
// Create and initialize new....
new = malloc(sizeof *new);
new->level = level;
new->name = name;
/* Find the insertion point */
for (; *head; head = &(*head)->next)
{
if ((*head)->level > level) { // I think this is what is causing the issue
if (cmp(*head, new) > 0)
// ^^^ So that you can use it here
break;
}
}
new->next = *head;
*head = new;
}
You are passing a NULL value to the cmp function (?!? probably the correct function is int compare(...). Try to initialize the value of the new variable before to pass it to the function.
You declare node.name to be of type char, but your comparison function is written as if they were null-terminated arrays of char or pointers into such arrays (i.e. C strings). You appear to want this:
struct node {
struct node *next;
int level;
char *name;
};
or maybe this:
struct node {
struct node *next;
int level;
char name[MY_MAXIMUM_NAME_LENGTH_PLUS_ONE];
};
Furthermore, your insert() function passes a NULL pointer to the comparison function as its second argument, because you never allocate any memory for pointer new, and, of course, never assign values to the non-existent members. That doesn't even make sense. What do you think you're comparing to? You seem to want something like this:
struct node *new = malloc(sizeof *new);
if (!new) {
// allocation failure -- abort ...
}
new->level = level;
new->name = /* hmmmm ... */;
Of course, the problem with the type of your names crops up here, too.

How to make use of a structure pointer inside the structure itself

I am studying the following C code:
typedef struct msg *m_;
struct msg
{
long from;
long to;
m_ link;
};
m_ queue;
I would like to see an example that explains the role of the pointer, i.e. m_, of the structure inside the structure itself m_ link!
Thank you very much.
To be pedantic: link is a pointer. m_ is not a pointer, it's a typedef. It is used to avoid the need to say "struct msg* link;" inside the struct definition.
As answered in the comment above, the queue is represented by a pointer to the first item, which has a pointer to the second (if any), and so on until you reach a NULL pointer.
It's important to take care when building such lists that no node points to itself or to any precursor, or you get an infinite loop chasing to the tail.
Pointers to the structure type inside the structure itself are very often used for linked lists, trees, etc. In your example, it is referring to a queue implementation.
Here is a very minimal example of a stack implementation using a linked list. The functions require the address of a stack pointer, and an empty stack is a NULL pointer.
struct linked_stack
{
int data;
struct linked_stack *next;
};
void linked_stack_push(linked_stack **stck, int data)
{
struct linked_stack *node = malloc(sizeof(struct linked_stack));
if (node != NULL)
{
node->data = data;
node->next = *stck;
}
*stck = node;
}
int linked_stack_top(linked_stack **stck)
{
if (*stck != NULL)
return (*stck)->data;
return 0; /* stack is empty */
}
void linked_stack_pop(linked_stack **stck)
{
struct linked_stack *node = *stck;
if (*stck != NULL)
{
*stck = node->next;
free(node);
}
}
Example usage:
int main(void)
{
struct linked_stack *stack = NULL;
linked_stack_push(&stack, 10);
printf("top of stack = %d\n", linked_stack_top(&stack));
linked_stack_pop(&stack);
return 0;
}

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