linked list c losing head address - c

I'm implementing a "car fleet" management tool. For start, I declared a "Car" struct:
typedef struct Car{
char ID[9];
struct Car* next;
} Car;
My fleet will simply be a linked list of cars. I begin with an empty head, and add links to it via add_car function.
void add_car (struct Car* cars_fleet){
struct Car* car = malloc (sizeof (car));
scanf("%s",car->ID);
car->next = NULL;
if (cars_fleet == NULL){
printf ("creating new list\n");
cars_fleet = car;
}
else {
printf ("appending\n");
Car* tmp = cars_fleet;
while (! (tmp->next == NULL))
tmp = tmp->next;
tmp->next = car;
}
}
And this is my main program:
int main(){
Car* cars_fleet = NULL;
add_car(cars_fleet);
}
Now, for some reason, my program treats all links as if they were the first one. I assume this is happening because of wrong memory allocation, perhaps at "cars_fleet = car". Any hints, tips or solutions? thanks.

You are passing the pointer by value. So any change in function void add_car (struct Car* cars_fleet) has no effect outside the function. You need to change function prototype :
void add_car (struct Car* cars_fleet)
Like this:
void add_car (struct Car** cars_fleet)
Then use, inside the function :
*cars_fleet = car
While, in main, call:
add_car(&cars_fleet);

You are assigning to a local variable in add_car, change to:
Car *add_car(void){/* Car *x = malloc(...); ... return x */};
And in main:
Car* cars_fleet = NULL;
cars_fleet = add_car();
How am I supposed to iterate through cars_fleet's links if I do not
pass it to add_car? and whose address am i returning? the address of
the new cars_fleet with the car added?
In your question you are passing a NULL, so there is no chance to iterate throug links, divide, use a function to get a fresh node and another one to insert this new Car in the list (passing the tail).

Related

Why my clear function with selected element does not work correctly?

during working on the project to school, i find a little problem, which i do not know remove.
Problem is in fuction clear_train. When i trying to remove 1. element, function return also my element(but empty).
Here is my source code where are definitions of all functions:
(in a_train.h are a declarations and descriptions of functions)
#include "a_train.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct car* add_car(struct car* first,const char* target) {
struct car* adder = malloc(sizeof(struct car));
struct car *current = first;
strcpy (adder->value,target);
adder->next=NULL;
if(first == NULL){
first =adder;}
else{
while (current->next != NULL) {
current = current->next;
}
current->next = adder;
}
return first ;
}
void print_train(struct car* first) {
if (first!=NULL){
while (first!=NULL){
printf("%s\n",first->value);
first=first->next;
}
}
else printf("empty list\n");
}
void cancel_train(struct car* first) {
while(first!=NULL){
struct car* canceler = first->next;
free(first);
first=canceler;
}
}
struct car* clear_train(struct car* first, const char* target) {
if(first == NULL){
return NULL;
}else if (first->next==NULL){
if(strcmp(first->value,target)==0){
free(first);
return NULL;
}else return first;
}
struct car* prev_searcher =first;
struct car* this_searcher =first;
while (this_searcher!=NULL){
if(strcmp(this_searcher->value,target)==0){
prev_searcher->next=this_searcher->next;
free(this_searcher);
}
prev_searcher=this_searcher;
this_searcher=this_searcher->next;
}
return first;
}
here is the definition of linked list:
struct car {
char value[SIZE];
struct car* next;
};
source code of main where i am calling functions:
int main(){
struct car* train = NULL;
train = add_car(train,"Presov");
train = add_car(train,"Bratislava");
train = add_car(train,"Levoca");
train = add_car(train,"Spiska Nova Ves");
train = add_car(train,"Bardejov");
train = add_car(train,"Pichne");
clear_train(train,"Presov");
print_train(train);
cancel_train(train);
return 0;
}
And finally there is output:
//there is empty node
Bratislava
Levoca
Spiska Nova Ves
Bardejov
Pichne
You are making things more difficult to remove a node from a linked list than it needs to be. While you are free to return and assign the head node each time clear_train is called, that's not really the way to do it.
Instead of passing a pointer-to-head (first) as the parameter to clear_train, pass the actual address of the head pointer, e.g.
clear_train(&train,"Presov");
That way you can manipulate the value (node) at that address directly. If the first node in the list is the one being delete, you simply update the node address held by the original pointer to the new first node and you are done.
Instead of trying to keep a previous, current and next node, simply use a pointer-to-pointer to current node. Then when the node containing target is found, you simply update the pointer at that address to the ->next node and you are done. See Linus on Understand Pointers
That reduces your clear_train function to:
void clear_train (struct car **first, const char* target) {
struct car **ppn = first; /* pointer-to-pointer to first */
struct car *pn = *first; /* pointer-to-first */
for (; pn; ppn = &pn->next, pn = pn->next) { /* iterate, find target */
if (strcmp (pn->value, target) == 0) { /* if found */
*ppn = pn->next; /* set pointer at target address = next */
free (pn); /* free node contianing target */
break;
}
}
}
Much simpler than trying to test for different cases of where the node lies.
In clear_train
when you find the car - you free the element and then you try to get to it again so the program will make you problem.
write like this
if(strcmp(this_searcher->value,target)==0){
prev_searcher->next=this_searcher->next;
free(this_searcher);
return prev_searcher}

C-modifying the address of a global variable inside a void function

Working on a linked list where I'm storing a pointer to head as a global variable. My question is: How can I assign a (new)value (in this case address) to head from within a void function?
EDIT
Alright here's some code:
Note: this is not how i would design this, but we're not supposed to stray from the spec.
typedef struct NODE Node;
typedef Node *NodePtr;
struct NODE{
char *item;
Node *next;
};
NodePtr first = NULL; //global
//insert function
Boolean insert( char *new_string ) {
printf("insert called\n");
if(first == NULL) {
first = malloc(sizeof(Node));
first->next = NULL;
first->item = new_string;
}
else {
NodePtr inserted = malloc(sizeof(Node));
inserted->next = first;
inserted->item = new_string;
first = inserted;
}
return 1;
}
the problem is that when i use insert() in a function. it works fine. i get a working list. but when another function tries to access first, its empty.
Am I right in assuming that modifying the global variables within the function does not alter the actual first ptr? I know I could pass in a pointer to first as an argument, but I'm not supposed to modify the prototype design.
You'll need to pass in the pointer and a pointer to pointer to head.. Update pointer to head, and head-> next to old head
if it is a global variable just assign the value like you would have done if it was a local variable in your void function.
assuming your struct is similar to this:
struct list {
int data;
struct list* next;
};
and you have the global variable
struct list* L
you can make a new node by making a new node, making the next variable to the head, and making your global value point to the new node:
newnode->next = L;
L = newnode

deleting all the nodes in a linked list

Anyone know what's wrong with this recrusive function? It doesn't delete all the nodes
struct contact
{
char FirstName[41];
char LastName[41];
int id;
struct contact *next;
};
void ClearList (struct contact *person)
{
struct contact *temp = person;
if (person == NULL) return;
else
{
person = person->next;
free(temp);
ClearList(person);
}
}
this is my main function
void main()
{
struct contact *person = malloc(sizeof(struct contact));
strcpy (person->FirstName, "John");
strcpy (person->LastName, "Doe");
person->id = 10;
person->next = malloc(sizeof(struct contact));
strcpy (person->next->FirstName, "Will");
strcpy (person->next->LastName, "Smith");
person->next->id = 20;
person->next->next = NULL;
PrintList(person);
ClearList(person);
PrintList(person);
}
when I call PrintList after calling ClearList it still prints out some messy stuffs, how do I fix this?
All the nodes are deleted, but you never clear any pointers. So what you're doing is dereferencing invalid pointers leading to undefined behavior.
The free function doesn't automatically set pointers to NULL.
I really don't like this recursive delete on your linked list. If your linked list has 100 elements you will go 100 functions deep in your stack and probably crash.
I suggest a re-write like this:
void ClearList (struct contact *person)
{
while( person != NULL )
{
struct contact * temp = person
person = person->next;
free(temp);
}
}
Joachim has the correct answer though. Although we have cleared the memory that person points to, "ClearList" does not have the right to set the original pointer to NULL. So either you need to make ClearList take a double pointer so it can set the pointer to NULL, or just set "person" to NULL after calling ClearList.
Double pointer example, call with ClearList(&person);
void ClearList (struct contact ** list)
{
struct contact *person = *list;
while( person != NULL )
{
struct contact * temp = person
person = person->next;
free(temp);
}
*list = NULL;
}

Value of Passed-By-Value Struct Does Not Change

I am trying to understand how to pass a struct by reference in order to create a linked list. The method I am using is similar to the example code given below. However, when this code is run, the *tester declared in the main function always stays as NULL. Is the passing of a struct to the addNode() function in this way inappropriate (the compiler does not raise any warnings)?
struct test{
int num;
struct test *next;
};
void addNode (int num, struct test* tester);
int main (void){
struct test *tester = null;
addNode(1, tester);
}
void addNode(int num, struct test* tester){
struct test *example = malloc(sizeof(struct test));
example->num = num;
if (tester == NULL){
tester = example;
} else{
tester->next = example;
}
}
In addNode function the pointer tester no longer points to the location pointed by the tester in main. function and change your function to
void addNode(int num, struct test** tester){
struct test *example = malloc(sizeof(struct test));
if (NULL == example )
exit(0); // Not enough memory
example->num = num;
if (NULL == *tester)
*tester = example;
else
(*tester)->next = example;
}
Call this function from main as addNode(1, &tester);. Now *tester is an alias for tester in main.
First off, you're assigning NULL to your input. This:
if (tester = NULL)
should be
if (tester == NULL)
Secondly, in that same branch, you assign a new value to tester. However, everything in C is passed by value (copy), so your function receives a copy of a pointer. Therefore, you are only mutating the function's local copy. You need another level of indirection:
#include <assert.h>
struct test{
int num;
struct test *next;
};
void addNode (int num, struct test* tester);
int main (void){
struct test *tester = NULL;
addNode(1, &tester);
}
void addNode(int num, struct test** tester){
/ * wrong, check next item */
assert(tester != NULL);
struct test example = malloc(sizeof(struct test));
example->num = num;
if (*tester == NULL){
*tester = example;
} else{
(*tester)->next = example;
}
}
Last, malloc returns a void*, which can implicitly be converted to any other type of pointer. It does not however return an "instance". So this is wrong:
struct test example = malloc(sizeof(struct test));
and should be:
struct test *example = malloc(sizeof *example);
You are saving the pointer returned by malloc as a struct:
struct test example = malloc(sizeof(struct test));
Perhaps you wanted to store it as a pointer to struct, so that example and tester have matching types:
struct test* example = malloc(sizeof(struct test));
Then, this will make sense:
tester = example;

Linked List Null in 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);
}
}

Resources