Kindly explain push function. I could not get why loop is used . For char and int (new_node->data=new_data) works fine . But for string , it doesn't . For string , error is produced. If char(%c) is printed for new_data in push() method then only first character is printed , while if char(%c) is printed for new_node->data then last characater is printed.
// C program for generic linked list
#include<stdio.h>
#include<stdlib.h>
/* A linked list node */
struct node
{
// Any data type can be stored in this node
void *data;
struct node *next;
};
/* Function to add a node at the beginning of Linked List.
This function expects a pointer to the data to be added
and size of the data type */
void push(struct node** head_ref, void *new_data, size_t data_size)
{
// Allocate memory for node
struct node* new_node = (struct node*)malloc(sizeof(struct node));
new_node->data = malloc(data_size);
new_node->next = (*head_ref);
// Copy contents of new_data to newly allocated memory.
// Assumption: char takes 1 byte.
int i;
//Why loop is used for copying data from new_data to new_node data.
for (i=0; i<data_size; i++)
*(char *)(new_node->data + i) = *(char *)(new_data + i);
// Change head pointer as new node is added at the beginning
(*head_ref) = new_node;
}
/* Function to print nodes in a given linked list. fpitr is used
to access the function to be used for printing current node data.
Note that different data types need different specifier in printf() */
void printList(struct node *node, void (*fptr)(void *))
{
while (node != NULL)
{
(*fptr)(node->data);
node = node->next;
}
}
// Function to print an integer
void printInt(void *n)
{
printf(" %d", *(int *)n);
}
// Function to print a float
void printFloat(void *f)
{
printf(" %f", *(float *)f);
}
/* Driver program to test above function */
int main()
{
struct node *start = NULL;
// Create and print an int linked list
unsigned int_size = sizeof(int);
int arr[] = {10, 20, 30, 40, 50}, i;
for (i=4; i>=0; i--)
push(&start, &arr[i], int_size);
printf("Created integer linked list is \n");
printList(start, printInt);
// Create and print a float linked list
unsigned float_size = sizeof(float);
start = NULL;
float arr2[] = {10.1, 20.2, 30.3, 40.4, 50.5};
for (i=4; i>=0; i--)
push(&start, &arr2[i], float_size);
printf("\n\nCreated float linked list is \n");
printList(start, printFloat);
return 0;
}
yes , we can also do new_node->data=new_data instead of using this loop
for (i=0; i<data_size; i++)
*(char *)(new_node->data + i) = *(char *)(new_data + i);
but there is difference between them. when we simply using new_node->data=new_data we are shallow copying.therefore two pointers pointing to the same location i.e if you change the values of arr[] then automatically the values in the struct changes.
when you using loop you are deep copying i.e if you change the values of the arr[] then the values of the struct will not get changed.
run the below code to understand the differnce.
// C program for showing shallow copy in generic linked list
#include<stdio.h>
#include<stdlib.h>
/* A linked list node */
struct Node
{
// Any data type can be stored in this node
void *data;
struct Node *next;
};
/* Function to add a node at the beginning of Linked List.
This function expects a pointer to the data to be added
and size of the data type */
void push(struct Node** head_ref, void *new_data, size_t data_size)
{
// Allocate memory for node
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
new_node->data = malloc(data_size);
new_node->next = (*head_ref);
// Copy contents of new_data to newly allocated memory.
// Assumption: char takes 1 byte.
int i;
// no loop just normal assignment of new_data
new_node->data=new_data;
printf("\n");
// Change head pointer as new node is added at the beginning
(*head_ref) = new_node;
}
/* Function to print nodes in a given linked list. fpitr is used
to access the function to be used for printing current node data.
Note that different data types need different specifier in printf() */
void printList(struct Node *node, void (*fptr)(void *))
{
while (node != NULL)
{
(*fptr)(node->data);
node = node->next;
}
}
// Function to print an integer
void printInt(void *n)
{
printf(" %d", *(int *)n);
}
// Function to print a float
void printFloat(void *f)
{
printf(" %f", *(float *)f);
}
/* Driver program to test above function */
int main()
{
struct Node *start = NULL;
// Create and print an int linked list
unsigned int_size = sizeof(int);
int arr[] = {1,2,3,4,5}, i;
for (i=4; i>=0; i--)
push(&start, &arr[i], int_size);
printf("Created integer linked list is \n");
printList(start, printInt);
printf("\n");
// changing the values in arr[]
arr[1]=45;
arr[3]=1000;
//printing the struct
printf("printing the struct after changing the values in the array \n");
printList(start, printInt);
/*
// Create and print a float linked list
unsigned float_size = sizeof(float);
start = NULL;
float arr2[] = {10.1, 20.2, 30.3, 40.4, 50.5};
for (i=4; i>=0; i--)
push(&start, &arr2[i], float_size);
printf("\n\nCreated float linked list is \n");
printList(start, printFloat);*/
return 0;
}
Related
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);
}
}
I am currently attempting to load values from an array into a stack data structure that I have implemented with a linked list. In my push() function I create each new node in my linked list through the use of a pointer so that they do not disappear when the push() stack frame collapses and control returns to reverse(). However, even though I am passing information through the use of pointers, the item I am referencing appears not be returning, as I keep getting NULL values in the calling function despite getting valid values in the called function. Why is this information not returning to my calling function?
#include<stdio.h>
#include<stdlib.h>
struct Node
{
char data;
struct Node* next;
};
void push(char x, struct Node* tp)
{
struct Node* temp = (struct Node*)malloc(sizeof(struct Node*));
temp->data = x;
temp->next = tp;
tp=temp;
printf("\ntp points to %p", tp);
}
void reverse (char c[])
{
struct Node* tp = NULL;
int i = 0, j = 0;
while (c[i] != '\0')
{
push(c[i], tp);
printf("\ntp points to %p", tp);
i++;
}
}
int main(void)
{
char c[] = {"coolio"};
printf("\n%s", c);
reverse(c);
}
The problem is that push cannot change tp that you pass it from reverse, because tp is passed by value. Change the function to return the value to be assigned to tp, like this:
struct Node* push(char x, struct Node* tp) {
... // your code here
return temp;
}
The call should look like this:
while (c[i] != '\0') {
tp = push(c[i], tp);
printf("\ntp points to %p", (void*)tp);
i++;
}
Note that using %p requires a cast to void*.
Demo.
I've implemented a Singly Linked List, and I'm noticing really strange behavior but can't pinpoint the exact reason why it's happening. I've tried using gdb to figure out what the problem is, and it looks like whenever I compute the size of a list, that's when things start to go wrong. This is the program I'm using to test out my implementation, and following is the actual implementation.
#include <stdio.h>
#include "singlylinked.h"
slist initialize(void); /* initializes test singly linked list */
slist initialize(){
int i, a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
slist l = sl_alloc();
int a_size = sizeof(a)/sizeof(a[0]);
for(i=0;i<a_size;i++){
sl_add(l, (void *)&a[i]);
}
return l;
}
int main(){
slist l = initialize();
int i, size = sl_size(l);
for(i = 0; i < size; i++){
printf("%d ", *(int *)sl_get(l,i));
}
fputc('\n',stdout);
return 0;
}
And now the actual implementation, I'm only going to post the methods used in the testing:
/* allocates an empty slist */
slist sl_alloc(){
return (slist) calloc(1, sizeof(struct node));
}
/* adds val to linked list */
void sl_add(slist l, void *val){
node *current, *new;
new = calloc(1, sizeof(struct node));
new->content = val;
new->next = NULL;
if((current = *l)){
while(current->next){
current = current->next;
}
current->next = new;
} else {
*l = new;
}
}
/* returns ith value in singly linked list l */
void *sl_get(slist l, int i){
node *current;
int j; /* counter */
void *result = NULL;
if((current = *l)){
int size = sl_size(l);
if(i < size){
for(j = i; j > 0; j--){
current = current->next;
}
result = current->content;
}
}
return result;
}
/* returns the size of the singly linked list */
int sl_size(slist l){
int size = 0;
node *current;
if((current = *l)){
do {
size++;
current = current->next;
} while (current);
}
return size;
}
And now this is how I define slist and struct node:
typedef struct node **slist;
typedef struct node {
void *content;
struct node *next;
} node;
EDIT: The strange behavior is this: When I try to print things out, it prints out the wrong values in the list. When I ran the program using gdb, this starts to happen after the first call to sl_size.
The problem is your initialisation of the list.
You add the 10 elements of the array a[] to the list that you are creating in initialize(). The only problem is that you store in your list nodes pointers to the data in the array a[]. Unfortunately this array is local to the function ! As soon as you return from initialize(), this array is no longer valid, and the pointer point to no valid place anymore. In consequence, the numbers that you expect to point to will be replaced by "garbage" value.
I want to create a linked list.
The user adds numbers and the idea is that the numbers are inserted to the list in descending order.
Here goes what I did, but when rearranging, it just orders the first number...
int addInputNumber(numberList **node){
numberList *temp;
int userInput;
temp = (numberList*)malloc(sizeof(numberList));
//Memory Check
if ( temp == 0 )//out of memory, return 0
return 0;
//Get the users input
printf("Give me a Number!\n");
scanf("%d",&userInput);
//Add it to the list.
temp->numbero = userInput;
///Link to the list.
temp->next = *node;
*node = temp;
//Lets cycle through the list.
numberList *temp2;
int helpNumber;
temp2 = *node;
//Rearrange the list.
while(temp2 != 0){
if(temp->numbero < temp2->numbero){
//Switch position..
helpNumber= temp2->numbero;
temp2->numbero = temp->numbero;
temp->numbero = helpNumber;
temp2 = *node;// If we change number, we must cycle from the beginning AGAIN.
}//eof if
temp2 = temp2->next;
}//eof while
return 0;
}//eof addNUmber function.
Here's the structure just in case:
typedef struct dynamicNumberList {
int numbero;
struct dynamicNumberList *next;
}numberList;
I've got 2 quick questions.
Why would it only arrange the first number?
This list adds a space towards the left (visually), how could I make it so I can add a space to the right?
You need to get into the habit of creating one function per task, instead of cramming everything into a single one. It makes the code easier to read and reuse and reduces the chance of errors.
A correct implementation could look like this:
#include <stdio.h>
#include <stdlib.h>
typedef struct s_List
{
int n;
struct s_List *next;
} List;
void print_list (List *head)
{
List *ptr;
for (ptr = head; ptr; ptr = ptr->next) {
printf ("%d\t", ptr->n);
}
putchar ('\n');
}
List * make_node (int n, List *next)
{
List * node = malloc (sizeof(List));
node->n = n;
node->next = next;
return node;
}
void insert_number_front (List **head, int n)
{
*head = make_node (n, *head);
}
void insert_number_after (List *prev, int n)
{
prev->next = make_node (n, prev->next);
}
// If HEAD is sorted, it will stay sorted after insertion
void insert_number_sorted (List **head, int n)
{
List *ptr;
List *ptr2;
// search for the rightmost node whose number is smaller than n.
ptr2 = NULL;
for (ptr = *head; ptr; ptr = ptr->next) {
if (ptr->n >= n)
break;
ptr2 = ptr;
}
// If such a node exists we insert the new node after it,
// otherwise we insert it at the front of the list.
if (ptr2) {
insert_number_after (ptr2, n);
}
else {
insert_number_front (head, n);
}
}
int input_number ()
{
int n;
printf ("enter a number: ");
scanf ("%d", &n);
return n;
}
int main ()
{
List *head = NULL;
int i;
// By adding elements exclusively with insert_number_sorted()
// we ensure the list is always sorted
for (i = 0; i < 5; i++) {
int n;
n = input_number ();
insert_number_sorted (&head, n);
}
print_list (head);
return 0;
}
To answer your second question, what you have here is a singly linked list, which can be described by a pointer to the first node. If you want to be able to insert nodes at the back you need to maintain an additional pointer to the last node. However this is not necessary in this case.
I'm trying to implement a hash table in C, and almost have it. I'm implementing collision resolution via chaining using a linked list in each array slot, and I'd like to be able to chain inside a function call.
Now, the problem is that in order for the modifications to be permanent I believe that I need an additional level of indirection. This is a problem in that when I try to traverse the list the previous element is overwritten by the next (see my comment inside the insert() function). I've tried to pass this array with an additional level of indirection specified a few different ways but I get compiler warnings and seg faults.
This may seem simple to some of you, but it's had me scratching my head for quite some time now, and this scenario (passing array of pointers for modification) is treated nowhere in my text and I can't seem to find this exact question asked (although it may be in a form I don't recognize). I'm not necessarily looking for a 'quick fix' to my code, but I want to understand what is the best practice to accomplish what I'm looking to do.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
//#include "list.c"
struct node{
int key;
struct node* next;
};
void createTable(struct node *table[], int numEls, int numSlots);
int hash(int key, int numSlots);
void insert(struct node *table[], int key, int slot, int numSlots);
void display(struct node *table[], int numEls);
int main(void){
srand(time(NULL));
int numEls, numSlots;
printf("Please enter the desired number of slots in the hash table: ");
scanf("%d", &numSlots);
struct node *table[numSlots];
printf("\nPlease enter the desired number of elements: ");
scanf("%d", &numEls);
printf("\nYour load factor will be %f", (float)numEls/numSlots);
createTable(table, numEls, numSlots);
}
void createTable(struct node *table[], int numEls, int numSlots){
for(int i = 0; i < numSlots; i++)
table[i] = NULL;
for(int j = 0; j < numEls; j++){
for(int k = 0; k < 99999999; k++){}//give the rand function time
int el = rand()%100;
insert(table, el, hash(rand()%100, numSlots), numSlots);
}
display(table, numSlots);
}
int hash(int key, int numSlots){
return((int)(pow(key, 2.819)) % numSlots);
}
void insert(struct node *table[], int key_, int slot, int numSlots){
printf("\nInserting %d into slot %d", key_, slot);
fflush(stdout);
struct node* new = malloc(sizeof(struct node));
(new)->key = key_;
(new)->next = NULL;
struct node** temp = &(table[slot]);
if((*temp) == NULL){
printf(" (*temp) == NULL");
(*temp) = new;
}
else{
printf(" %d", (*temp)->key);
while((*temp)->next != NULL){
printf(" %d", (*temp)->next->key);
(*temp) = (*temp)->next; //head is overwritten with head->next
}
(*temp)->next = new;
printf(" %d", (*temp)->next->key);
}
}
void display(struct node *table[], int numSlots){
for(int i = 0; i < numSlots; i++){
printf("\nSlot %d:", i);
struct node* temp = table[i];
while(temp != NULL){
printf(" %d", temp->key);
temp = temp->next;
}
}
}
In the line with the comment, you are overwriting the pointer to the head (inside the outermost array) with the next element in the linked list, which was probably not your intent.
The correction is to walk down the list of pointers until you found the last pointer, without modifying the main data structure during the walk.
Here is a corrected version of insert().
void insert(struct node *table[], int key_, int slot, int numSlots){
printf("\nInserting %d into slot %d", key_, slot);
fflush(stdout);
struct node* new = malloc(sizeof(struct node));
new->key = key_;
new->next = NULL;
// Here we make a copy of the pointer to the head node in the linked list.
// This way, we never overwrite the original copy which lives in the array itself.
struct node* head = table[slot];
if(head == NULL){
printf(" head == NULL");
table[slot] = new;
}
else{
while(head->next != NULL) {
head = head->next; //head is overwritten with head->next
}
head->next = new;
}
}
This isn't an answer but is too big for a comment... can you explain what this code is meant to be doing?
while((*temp)->next != NULL)
{
printf(" %d", (*temp)->next->key);
(*temp) = (*temp)->next; //head is overwritten with head->next
}
(*temp)->next = new;
I would expect that you want to append the new node at the end of the linked list of existing nodes in this slot. But this code actually updates the head to point to the last node in the list , just like your comment says (leaking memory - the earlier nodes in the list are now unreachable). Then it makes the last node (which is now the only node in the list) point to new.
So your "list" only ever has length 1 or 2, and it leaks memory each time you try to put a third entry in.
It seems to me that there is nothing wrong with your passing of table (which is a list of heads of linked lists) but the problem is that the code that maintains the list for which those are heads, is not right.