Structs with linked lst - c

I am new to C programming. I am trying to calculate the sum of the price field for each node and ended up getting a segmentation fault here. The sum should be 300 but it is giving me 100? seems like not traversing properly. Any ideas as to how to ensure this works?
Can anybody tell me where am I going wrong?
typedef struct Type_Of_item
{
int item_id; // A unique identifier for each item
char name[1024]; // The items name
float price; // The items price
float discount_pct; // Discount percentage in [0, .5] (0% up to 50%)
int quantity; // Item quantity in the cart
}Item;
// The 'Item' itself contains;
typedef struct Item_Node
{
Item item_info;
struct Item_Node *next;
}node_item;
node_item *new_Item_Node(void){ // I have this also in my code pasted later
node_item *new_item=NULL;
new_item=(node_item *)calloc(1, sizeof(node_item ));
new_item->item_info.item_id=0;
strcpy(new_item->item_info.name,"");
new_item->item_info.price = 0;
new_item->item_info.discount_pct = 0;
new_item->item_info.quantity = 0;
new_item->next=NULL;
return new_item;
}
int calc_price(node_item *head){ // THIS ONE
node_item *p = NULL;
p = head;
int price;
while (p!= NULL)
{
price+=head->item_info.price;
printf("%d", item_info.price)
p=p->next;
}
return price;
}
int main(int argc, char const *argv[])
{
node_item *product1 = NULL;
node_item *product2 = NULL;
node_item *product3= NULL;
node_item* head = NULL;
product1 ->item_info.item_id=22;
strcpy(product1->item_info.name,"");
product1->item_info.price = 100;
product1->item_info.discount_pct = 0.5;
product1->item_info.quantity = 2;
product1->next=NULL;
product1 ->item_info.item_id=33;
strcpy(product1->item_info.name,"");
product1->item_info.price = 200;
product1->item_info.discount_pct = 0.8;
product1->item_info.quantity = 3;
head = product1;
float result = calc_price(head); // fcn call
printf("%f",result);
}

You haven't allocated the memory for your struct
int main(int argc, char const *argv[])
{
node_item *product1 = NULL;
node_item *product2 = NULL;
node_item *product3= NULL;
node_item* head = NULL;
product1 = malloc(sizeof node_item); // add this
product2 = malloc(sizeof node_item); // add this
product3 = malloc(sizeof node_item); // add this

Related

C clone linked list

I would like to ask how to modify the cloneList function to work properly?
I always want to add a new element to the top of the list. I want Peter still at the top of the cloned list. I can't change the function header
typedef struct TEmployee
{
struct TEmployee *m_Next;
struct TEmployee *m_Bak;
char *m_Name;
} TEMPLOYEE;
TEMPLOYEE *newEmployee (const char *name, TEMPLOYEE *next)
{
TEMPLOYEE *n = (TEMPLOYEE*) malloc(sizeof(*next));
n->m_Name = (char*) malloc(sizeof(char)*100);
strcpy(n->m_Name, name);
n->m_Bak = NULL;
n->m_Next = next;
return n;
}
TEMPLOYEE *cloneList(TEMPLOYEE *src)
{
TEMPLOYEE *x;
x = NULL;
TEMPLOYEE *tmp = src;
while(tmp)
{
x = newEmployee(tmp->m_Name, x);
x->m_Bak = tmp->m_Bak;
tmp = tmp->m_Next;
}
return x;
}
int main ()
{
TEMPLOYEE *a, *b;
a = NULL;
b = NULL;
a = newEmployee("Peter",a);
a = newEmployee("John",a);
...
b = clone(a);
}
Modify your cloneList function as below, so that you can get head node as return value.
TEMPLOYEE *cloneList(TEMPLOYEE *src)
{
TEMPLOYEE *x;
x = NULL;
int nCtr=0;
TEMPLOYEE *head=NULL;
TEMPLOYEE *tmp = src;
while(tmp)
{
x = newEmployee(tmp->m_Name, tmp->m_Next); //note the change
x->m_Bak = tmp->m_Bak;
if(nCtr == 0)
head = x;
tmp = tmp->m_Next;
nCtr++;
}
return head; //return the first node
}

munmap_chunk(): invalid pointer while freeing a struct in an array

So I wrote a program where I have to realloc an array of structs whenever I want to add something to it.
But when I try to free the array, I free every element individually but I get a munmap_chunk(): invalid pointer at some point.
Here is the full code :
#include <stdlib.h>
#include <string.h>
struct Date {
int day;
int month;
int year;
};
struct Person {
char *name;
char *surname;
struct Date birth;
};
struct Directory {
int size;
struct Person *array;
};
struct Date create_date() {
struct Date date = {
.day = 0,
.month = 0,
.year = 0
};
return date;
}
struct Directory create_directory() {
struct Directory directory = {
.size = 0,
.array = NULL
};
return directory;
}
struct Person *create_person() {
struct Person *person_ptr = (struct Person *) malloc(sizeof(struct Person));
person_ptr->name = NULL;
person_ptr->surname = NULL;
return person_ptr;
}
void copy_date(struct Date *dest, struct Date *src) {
dest->day = src->day;
dest->month = src->month;
dest->year = src->year;
}
void initialize_person(struct Person *person_ptr, char *name, char *surname, struct Date *birth) {
if (name != NULL && surname != NULL && birth != NULL) {
person_ptr->name = realloc((*person_ptr).name, (strlen(name) * sizeof(char)) + 1);
strcpy(person_ptr->name, name);
person_ptr->surname = realloc((*person_ptr).surname, (strlen(surname) * sizeof(char)) + 1);
strcpy(person_ptr->surname, surname);
copy_date(&person_ptr->birth, birth);
}
}
void copy_person(struct Person *dest, struct Person *src) {
dest->name = realloc((*dest).name, (strlen(src->name) * sizeof(char)) + 1);
dest->surname = realloc((*dest).surname, (strlen(src->surname) * sizeof(char)) + 1);
struct Date date = create_date();
dest->birth = date;
strcpy(dest->name, src->name);
strcpy(dest->surname, src->surname);
copy_date(&dest->birth, &src->birth);
}
int add_person(struct Directory *directory_ptr, const struct Person *new_person_ptr) {
int return_code = 0;
directory_ptr->size++;
directory_ptr->array = realloc(directory_ptr->array, (directory_ptr->size * sizeof(struct Person)));
if (directory_ptr->array) {
copy_person(&directory_ptr->array[directory_ptr->size - 1], (struct Person *) new_person_ptr);
} else {
return_code = 1;
}
return return_code;
}
int add_multiple_persons(struct Directory *directory_ptr, const struct Person **persons_ptr, int nb_persons) {
for (int i = 0; i < nb_persons; i++) {
add_person(directory_ptr, (persons_ptr[i]));
}
return 0;
}
void destroy_person(struct Person *person_ptr) {
free(person_ptr->name);
person_ptr->name = NULL;
free(person_ptr->surname);
person_ptr->surname = NULL;
free(person_ptr);
person_ptr = NULL;
}
void destroy_directory(struct Directory *directory_ptr) {
if (directory_ptr->array) {
for (int i = 0; i < directory_ptr->size; i++) {
destroy_person(&directory_ptr->array[i]);
}
directory_ptr->array = NULL;
directory_ptr->size = 0;
}
}
int main(void) {
struct Directory directory = create_directory();
struct Person *person1 = create_person();
struct Person *person2 = create_person();
struct Person *person3 = create_person();
struct Date date = {
.day = 17,
.month = 04,
.year = 1999};
initialize_person(person1, "Marcel", "Juan", &date);
initialize_person(person2, "Albin", "Michel", &date);
initialize_person(person3, "Suzerain", "Bernard", &date);
const struct Person *array[] = {
person1,
person2,
person3
};
add_multiple_persons(&directory, array, 3);
destroy_person(person1);
destroy_person(person2);
destroy_person(person3);
destroy_directory(&directory);
return 0;
}
I've been on this error for more than a week, and it keeps bugging me.
How can I fix this ?
In the destroy_directory function, you freed the persons contained by the array. But in this array you didn't put pointers to structures but the structures themselves. Therefore you must free the space you allocated for the array and nothing else :
void destroy_directory(struct Directory *directory_ptr) {
if (directory_ptr->array) {
free(directory_ptr->array); //<==== Here
directory_ptr->array = NULL;
directory_ptr->size = 0;
}
}
person_ptr is a part of the memory allocated at directory_ptr->array. You need to remove this line.
As a rule of gold, memory responsible is the same while allocation and while freeing. In your code, the person holder is the array inside directory_ptr, which is allocated by add_person. Despite its name, it is a directory manager, so freeing its memory should be done only on directory destroyer.

Linked lists and arrays

I have to make linked lists that contain all the non zero values from an array and print it out. However, my code is printing out the same value for how many non zero elements there are in the array.
The creation of the linked list and printing of the linked list are two separate functions.
The addLink function creates the linked list
void addlink(DataPtr *start, int element, double value) {
Data last = *start;
Data newPtr;
newPtr = malloc(sizeof(Data));
newPtr->element = element;
newPtr->usage = value;
newPtr->next = NULL;
if(*start == NULL) {
*start = newPtr;
return;
newPtr->element = element;
newPtr->usage = value;
newPtr->next = NULL;
}
while(last->next != NULL) {
last = last->nextPtr;
last->next = newPtr;
return;
}
}
The print function prints the linked list
void print(Data *start) {
Data current = *start;
while(current != NULL) {
printf("%d ", current->element);
printf("%.3lf", current->value);
current = current->next;
}
printf("\n");
}
This is how i call it in my main
for(k = 0; k < 50; k++) {
if(values[k] != 0) {
value = values[k];
addlink(&start,k,value);
print(&start);
}
}
struct data{
int element;
double value;
struct data *next;
};
typedef struct data Data;
typedef Data *DataPtr;
DataPtr start = NULL;
Here is correct implementation of your list:
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
typedef struct data {
int element;
double value;
struct data *next;
} data_t;
void print(data_t *start);
void addlink(data_t **start, int element, double value);
int main()
{
int values[50] = { 0 };
int value = 0;
int k;
data_t *start = NULL;
//Give values some value
values[0] = 100;
values[1] = 250;
for(k = 0; k < 50; k++)
{
if(values[k] != 0)
{
value = values[k];
addlink(&start,k,value);
print(start);
}
}
}
void addlink(data_t **start, int element, double value)
{
data_t *newPtr;
newPtr = malloc(sizeof(data_t));
newPtr->element = element;
newPtr->value = value;
*start = newPtr;
}
void print(data_t *start)
{
data_t *current = start;
while(current != NULL)
{
printf("%d ", current->element);
printf("%f", current->value);
current = current->next;
}
printf("\n");
}
Your DataPtr idea, is no good. The "data_t" implementation is generally what you will see when seeing linked lists. It is easiest implemented this way.
If you are trying to implement a list that adds the newest data_t to the end of the list...
Check out http://www.learn-c.org/en/Linked_lists for further explanation.
A correct function implementation can look the following way
int addlink( DataPtr *start, int element, double value )
{
DataPtr newPtr = malloc(sizeof(Data));
int success = newPtr != NULL;
if ( success )
{
newPtr->element = element;
newPtr->value = value;
newPtr->next = NULL;
while ( *start != NULL ) start = &( *start )->next;
*start = newPtr;
}
return success;
}
If you want to add new elements at the beginning of the list then the function can look like
int addlink( DataPtr *start, int element, double value )
{
DataPtr newPtr = malloc(sizeof(Data));
int success = newPtr != NULL;
if ( success )
{
newPtr->element = element;
newPtr->value = value;
newPtr->next = *start;
*start = newPtr;
}
return success;
}
As for showed by you the function implementation then it shall not even compile. For example in this code snippet
Data last = *start;
Data newPtr;
newPtr = malloc(sizeof(Data));
the expression *start has the type DataPtr while the initialized variable last has the type Data. The same problem exists for the variable newPtr.
The function print can look like
void print( DataPtr *start )
{
for ( DataPtr current = *start; current != NULL; current = current->next )
{
printf("%d ", current->element);
printf("%.3lf", current->value);
}
printf("\n");
}
And it is called like
print( &start );

Unable to delete value from HashTable in C

I'm trying to delete a value from hash table, the code works when I delete a value from the array where the linked list size is one, then segfaults if the size is greater than 1.
typedef struct hash {
char *key;
char *value;
struct hash *next;
} hashTable;
// generate hash code
unsigned int hashCode(char *key) {
int sum;
int i;
sum = 0;
i = 0;
while (key[i])
sum += key[i++];
return sum % MAX_HASH;
}
// get hash item size
int hash_size(hashTable *head) {
int i;
hashTable *list;
i = 0;
list = head;
if (list) {
while (list != NULL) {
i++;
list = list->next;
}
}
return (i);
}
// free item
void free_hash(hashTable *item) {
free(item->key);
free(item->value);
free(item);
}
// function for deleting item from hash table
void deleteItem(hashTable *table[], char *key) {
hashTable *head = table[hashCode(key)];
hashTable *tmp = head;
hashTable *prev = NULL;
if (!head)
return;
if (hash_size(tmp) == 1) {
table[hashCode(key)] = 0;
free_hash(tmp);
return;
}
while (strcmp(tmp->key, key) != 0 && tmp->next != NULL) {
prev = tmp;
tmp = tmp->next;
}
if (strcmp(tmp->key, key) == 0) {
if (prev)
prev->next = tmp->next;
else
head = tmp->next;
free_hash(tmp);
}
}
// function for inserting item into the table
void insert(hashTable *table[], char *key, char *value) {
hashTable *tmp;
hashTable *item;
unsigned int code;
item = (hashTable *)malloc(sizeof(hashTable));
if (!item)
return;
item->key = (char *)malloc(sizeof(char) * strlen(key) + 1);
item->value = (char *)malloc(sizeof(char) * strlen(value) + 1);
item->next = NULL;
code = hashCode(key);
strcpy(item->key, key);
strcpy(item->value, value);
if (!table[code])
table[code] = item;
else {
tmp = table[code];
item->next = tmp;
table[code] = item;
}
}
// displaying items
void display(hashTable *table[]) {
int i = 0;
hashTable *tmp;
while (i < MAX_HASH) {
if (table[i] != NULL) {
tmp = table[i];
if (hash_size(tmp) == 1)
printf("%s=%s\n", tmp->key, tmp->value);
else {
while (tmp != NULL) {
printf("%s=%s\n", tmp->key, tmp->value);
tmp = tmp->next;
}
}
}
i++;
}
}
int main(int argc, char const *argv[]) {
hashTable *table[MAX_HASH];
memset(table, 0, MAX_HASH * sizeof(hashTable *));
insert(table, "Bart", "first");
insert(table, "Lisa", "Second");
insert(table, "Foo", "bar");
deleteItem(table, "Lisa");
display(table);
return 0;
}
There are many issues in your code:
do include the standard header files, and define HASH_MAX:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HASH_MAX 1027
the type hashTable is confusing: it is really an entry list, the hash table itself is the array.
the while loops are error prone: use the much preferred for loops where the initialization, test and increment of the loop index are conveniently located on the same line:
for (int i = 0; i < HASH_MAX; i++) {
// printf hashTable[i]
}
I know the local style conventions at 42 explicitly exclude the for loop, but you should lobby against this questionable choice.
there is no need to special case hash_size(tmp) == 1 in display_table()
there is no need to cast the return value of malloc(). sizeof(char) is 1 by definition. You could use strdup() to duplicate C strings.
in deleteItem() you always remove the entry if it is alone: this is incorrect if the entry has a different key. Furthermore, you do not link the previous node or the table slot to the next element of the list.
Here is a corrected version of this function:
// function for deleting item from hash table
void deleteItem(hashTable *table[], const char *key) {
hashTable **link = &table[hashCode(key)];
while (*link) {
hashTable *tmp = *link;
if (strcmp(tmp->key, key) == 0) {
*link = tmp->next; // unlink the list node
free_hash(tmp);
break; // remove this if you mean for deleteItem to remove all matching nodes
} else {
link = &(*link)->next;
}
}
}
Here is a simplified version of the whole program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_HASH 1027
typedef struct HashItem {
char *key;
char *value;
struct HashItem *next;
} HashItem;
// generate hash code
unsigned int hashCode(const char *key) {
unsigned int sum = 0;
for (int i = 0; key[i]; i++) {
sum += (unsigned char)key[i] * (i + 1);
}
return sum % MAX_HASH;
}
// free item
void freeItem(HashItem *item) {
free(item->key);
free(item->value);
free(item);
}
// function for deleting item from hash table
void deleteItem(HashItem *table[], const char *key) {
HashItem **link = &table[hashCode(key)];
while (*link) {
HashItem *tmp = *link;
if (strcmp(tmp->key, key) == 0) {
*link = tmp->next; // unlink the list node
freeItem(tmp);
break;
} else {
link = &(*link)->next;
}
}
}
// function for inserting item into the table
void insertItem(HashItem *table[], const char *key, const char *value) {
unsigned int code = hashCode(key);
HashItem *item = malloc(sizeof(*item));
if (item != NULL) {
item->key = strdup(key);
item->value = strdup(value);
item->next = table[code];
table[code] = item;
}
}
// displaying items
void displayHashTable(HashItem *table[]) {
for (int i = 0; i < MAX_HASH; i++) {
for (HashItem *tmp = table[i]; tmp; tmp = tmp->next) {
printf("%s=%s\n", tmp->key, tmp->value);
}
}
}
int main(int argc, char const *argv[]) {
HashItem *table[MAX_HASH] = { 0 };
insertItem(table, "Bart", "first");
insertItem(table, "Lisa", "Second");
insertItem(table, "Foo", "bar");
deleteItem(table, "Lisa");
displayHashTable(table);
return 0;
}

Relocating a Node in a Singly Linked List Creates Infinite Loop

In my homework I was asked to relocate a specific node by his name field to specific index. I'm having trouble to figure out why is my list becomes an infinite list. The problem is in the function "changePlacement" Example: Given linked list : 1->2->3->4 Output : 1->3->3->3... Expected output : 1->3->2->4
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Frame
{
char *name;
unsigned int duration;
char *path; // may change to FILE*
};
typedef struct Frame frame_t;
struct Link
{
frame_t *frame;
struct Link *next;
};
typedef struct Link link_t;
int listLen = 0;
link_t* lastNode = NULL;
void addFrame(link_t** list);
void frameData(frame_t* frame);
void freeVideo(link_t* video);
void showList(link_t* list);
void freeNode(link_t* list);
void changePlacement(link_t** list, int newIndex, char* name);
int main(void)
{
link_t* video = NULL;
lastNode = video;
if (!video)
{
perror(video);
}
addFrame(&video);
addFrame(&video);
addFrame(&video);
addFrame(&video);
showList(video);
changePlacement(&video, 2, "3");
showList(video);
printf("\n");
freeVideo(&video);
_flushall();
getchar();
return 0;
}
void addFrame( link_t** video)
{
char strTemp[200] = { 0 };
link_t* newFrame = (link_t*) calloc(1, sizeof(link_t));
newFrame->frame = (frame_t*) malloc(sizeof(frame_t));
printf(" *** Creating new frame ***\n");
printf("Please insert a frame path:\n");
scanf(" %s", &strTemp);
newFrame->frame->path = (char*) calloc(strnlen(strTemp, 200) + 1, sizeof(char));
strncpy(newFrame->frame->path, strTemp, strnlen(strTemp, 200));
printf("Please insert frame duration(in miliseconds):\n");
scanf(" %d", &(newFrame->frame->duration));
printf("Please choose a name for that frame:\n");
scanf(" %s", &strTemp);
newFrame->frame->name = (char*) calloc(strnlen(strTemp, 200) + 1, sizeof(char));
strncpy(newFrame->frame->name, strTemp, strnlen(strTemp, 200));
if (!(*video))
{
(*video) = newFrame;
}
else
{
lastNode->next = newFrame;
}
lastNode = newFrame;
++listLen;
}
void freeVideo(link_t** video)
{
link_t* currNode = NULL;
int loop = 0;
for (; currNode; currNode = *video) // set curr to head, stop if list empty.
{
// advance head to next element.
freeNode(currNode);
(*video) = (*video)->next; // delete saved pointer.
}
freeNode((*video)->next);
freeNode((*video));
}
void showList(link_t* list)
{
printf("\n\t|Name\t\t| Duration | Path\n");
printf("\t+++++++++++++++++++++++++++++++++++++++++++++++\n");
for (;list; list = list->next)
{
printf("\t|%10s\t|%10d\t|\t%s\n", list->frame->name, list->frame->duration, list->frame->path);
printf("\t+++++++++++++++++++++++++++++++++++++++++++++++\n");
}
}
void freeNode(link_t* node)
{
free(node->frame->name);
free(node->frame->path);
free(node->frame);
free(node);
}
void changePlacement(link_t** list, int newIndex, char* name)
{
link_t *prevOldNode = (*list), *prevTemp = NULL, *oldNode = NULL, *newNode = NULL;
link_t *temp = (*list), *PrevNewNode = NULL, *nodeAfterNewNode = NULL;
int currIndex = 0, i = 0, flag = 0;
while ((temp->next))
{
++currIndex;
if (!strcmp(temp->frame->name, name)) //looking for the wanted node
{
oldNode = temp;
prevOldNode = prevTemp;
}
if (currIndex == newIndex)
{
PrevNewNode = prevTemp;
newNode = temp;
}
prevTemp = temp;
temp = temp->next;
}
nodeAfterNewNode = newNode->next; //temporal variable that stores the node after the new node
prevOldNode->next = oldNode->next;
newNode->next = oldNode;
oldNode->next = nodeAfterNewNode;
}
Do you have any ideas after looking on my code? any help would be blessed
Your code at the end of changePlacement() doesn't account for the case of oldNode and newNode being adjacent to each other, i. e. e. g. nodeAfterNewNode = newNode->next being identical to oldNode. (Besides it doesn't account for the case of not finding the name.) It is far easier to just exchange the frame pointers; change
nodeAfterNewNode = newNode->next; //temporal variable that stores the node after the new node
prevOldNode->next = oldNode->next;
newNode->next = oldNode;
oldNode->next = nodeAfterNewNode;
to
if (!oldNode) return; // wanted node name not found
frame_t *f = oldNode->frame;
oldNode->frame = newNode->frame;
newNode->frame = f;

Resources