adding item to the end of linked list segfault - c

struct vehicle *add_vehicle(struct vehicle *v){
struct vehicle *newcar = (struct vehicle*)malloc(sizeof(struct
vehicle));
scanf("%s", newcar->regnro);
scanf("%s", newcar->model);
newcar->next = NULL;
if(v->next == NULL){
v->next =newcar;
}
else{
struct vehicle *current = v;
while(current->next != NULL){
current = current->next;
}
current->next = newcar;
}
return v;
}
I am trying to add vehicle to end of the list but it gives me Segmentation fault after second scanf, I dont know is my mistake in loops or in scanf. My struct is like:
struct vehicle {
char regnro[7];
char *model;
struct vehicle *next;
};

Firstly as pointed by other in comments model is pointer member of structure & its not initialzed. When you do scanf("%s", newcar->model); it gives seg. fault. So first allocate memory for it dynamically. For e.g
newcar->model = malloc(SIZE); /* define SIZE */
Secondly, you are passing just normal struct vehicle variable to add_vehicle() method So whatever changes are done with v in add_vehicle() won't affect in main() method. Instead pass the address of struct vehicle variable to add_vehicle() method, in that case you no need to return the struct variable as it will be call by reference. for e.g
main() method call looks like
struct vehicle *head = NULL;
add_vehicle(&head);
And definition of add_vehicle() looks like
void add_vehicle(struct vehicle **v){
/* some code */
}
Here is the sample code you may want
void add_vehicle(struct vehicle **v){
struct vehicle *newcar = malloc(sizeof(struct vehicle));/* no need to type cast the result of malloc */
scanf("%s", newcar->regnro);
/* model is pointer member of dtruct, you need to do malloc for it */
newcar->model = malloc(SIZE)); /*define the size value */
scanf("%s", newcar->model);
newcar->next = NULL;
if((*v) == NULL){ /* first node */
newcar->next = *v; /* newnode next make it to head node */
(*v) = newcar; /*update the head node and */
return;
}
else{
struct vehicle *current = *v;
while(current->next != NULL){ /* move temp to the end node of list */
current = current->next;
}
current->next = newcar;/* add the new_node at last of the list */
}
}
void print_info(struct vehicle *temp) {
while(temp) {
printf("%s %s\n",temp->regnro,temp->model);
temp= temp->next;
}
}
int main(void) {
struct vehicle *head = NULL;
add_vehicle(&head); /* pass the address of head */
print_info(head);
return 0;
}

Related

I cant find the error of my linked list( why is my head pointer moving?)

I have tried so many times to set my head pointer pointing to the first node. At first(in the empty list) it correctly points the first node. But after the first loop, the head pointer points to the newnode linked. Actually now Im quite unsure about my whole code as well.
int main(void){
struct library *head = NULL; //set the head pointer to NULL
int option;
printf("Enter the number:");
while((option = getchar())!= 9){
switch(option){
case '1':
{
char title[1000];
char author[1000];
char subject[1000];
printf("Enter title of the book you want to add:");
scanf("%s",title);
printf("Enter author of the book you want to add:");
scanf("%s",author);
printf("Enter subject of the book you want to add:");
scanf("%s",subject);
add_book(title,author,subject,&head);
printf("successful! and head pointer is pointing to %s\n",head->collection.title);
break;
}
}
}
void add_book(char title[],char author[],char subject[], struct library ** head){
struct library *current;
struct library *newnode = malloc(sizeof(struct library));
newnode->collection.title = title;
newnode->collection.author = author;
newnode->collection.subject = subject; // assigning value inside newnode
newnode->num_books = 0;
newnode->next = NULL; // assign NULL value to the end of newnod
//when the head is NULL which means when the list is empty
if(*head == NULL)
{
current = newnode;
*head = current;
return;
}
else
{
current = *head; //assign the first node to current pointer
//find the last node of the list
while(current->next != NULL)
{
current = current->next;
}
current->next = newnode; // link the last node to new node
return;
}
}
This is struct for this
struct book {
char* title;
char* author;
char* subject;
};
struct library {
struct book collection;
int num_books;
struct library* next;
};
The lifetime of char title[1000];, char author[1000];, and char subject[1000]; ends when execution reaches the end of the block inside case '1': { /* ... */ }. Once this happens, the pointers that were assigned in add_book become dangling pointers - pointing to invalid memory.
To remedy this, you must ensure the lifetime of your strings matches the lifetime of the structures that contain them. This can be done either by allocating enough space in the structure itself
struct book {
char title[1000];
/* etc. */
};
or by dynamically allocating enough space for a copy of each string. In any case you must copy the string to this memory (man 3 strcpy).
If it is available on your system, man 3 strdup does both steps of the second form at once. Otherwise, it is roughly the same as strcpy(malloc(strlen(source_string) + 1), source_string);.
Also note that the scanf specifier %s is as dangerous as gets when used without a field-width specifier (e.g., char buffer[1000]; scanf("%999s", buffer);), as it can potentially overflow your buffer.
An example program. Enter strings one-by-one, and terminate with EOF CTRL+D (Windows: CTRL+Z, RETURN).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct link {
char *string;
/* alternatively: char string[512]; */
struct link *next;
};
void add_link(struct link **root, const char *string) {
struct link *node = calloc(1, sizeof *node);
node->string = strdup(string);
/* alternatively: strcpy(node->string, string) */
if (*root) {
struct link *tail = *root;
while (tail->next)
tail = tail->next;
tail->next = node;
} else
*root = node;
}
int main(void) {
struct link *head = NULL;
while (1) {
char buffer[512];
if (!fgets(buffer, sizeof buffer, stdin))
break;
/* remove newline */
buffer[strcspn(buffer, "\n")] = '\0';
add_link(&head, buffer);
}
for (struct link *node = head, *next; node; node = next) {
next = node->next;
printf("STRING: %s\n", node->string);
free(node->string);
free(node);
}
}
Note: in a real program you should always check the return values of your memory allocating functions (malloc, calloc, strdup, etc.) as they can fail.

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}

Segmentation Fault occurring when accessing the same memory in one function instead of another

I am implementing a LinkedList with a bunch of ListNodes that are structs which contain some basic information about people. I have two files, one that is main.c, and another that is main.h. Whenever I attempt to print the list by passing the root to a function, I get an error.
Here is main.c:
#include "main.h"
/* Edward Nusinovich
This C file is going to have a LinkedList containing information about people.
The user can interact with it and manipulate the list.
*/
int main(int argc, char **argv){
if(!checkIfValidArguments(argc).value){return -1;}
ListNode *root = askForDetails(1,argv);
ListNode *current = root;
current->next = NULL;
ListNode *temp;
int index = 2;
while(index<argc){
temp = askForDetails(index,argv);
current->next = temp;
current = current->next;
index++;
}
userLoop(root);
return 0;
}
In my main.h file, I have no problem printing attributes of the root parameter in the function "userLoop", but as soon as I pass ListNode *root to "print" or "stuff" I get a seg fault when trying to print its values.
Here is main.h:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define true 1
#define false 0
typedef struct bool{
int value:1;
} boolean;
//this is going to store info about a person
typedef struct people{
char *name;
char *hairColor;
char *eyeColor;
char *age;
struct people *next;
} ListNode;
//using a 1 bit bitfield we have constructed, stores whether or not the user has entered a proper number of inputs
boolean checkIfValidArguments(int numArgs){
boolean validArguments;
if(numArgs>1){validArguments.value=true;}
else{validArguments.value=false; printf("We need some names of people.\n");}
return validArguments;
}
//this will construct a new Person and return him to
ListNode *askForDetails(int personIndex, char **argv){
ListNode toReturn;
char *name = argv[personIndex];
printf("Please enter the hair color, eye color, and age of %s.\n",name);
char *inBuf=malloc(100);
char nextchar=getchar();
int index = 0;
if(nextchar!='\n'){inBuf[index]=nextchar; index++;}
while((nextchar=getchar())!='\n'){
inBuf[index] = nextchar;
index ++;
}
toReturn.name = name;
toReturn.hairColor = strtok(inBuf," ");
toReturn.eyeColor = strtok(NULL," ");
toReturn.age = strtok(NULL,"\n");
ListNode *newNode = malloc(sizeof(ListNode));
newNode = &toReturn;
return newNode;
}
char *getInput(char *message){
printf("%s",message);
char *inBuf = malloc(40);
char nextchar=getchar();
int index = 0;
if(nextchar!='\n'){inBuf[index]=nextchar; index++;}
while((nextchar=getchar())!='\n'){
inBuf[index] = nextchar;
index ++;
}
return inBuf;
}
void addToEnd(ListNode *root){
ListNode *current = root;
char *inBuf = getInput("\nEnter the name of a person who you want to add: \n");
ListNode *toAdd = malloc(sizeof(ListNode));
toAdd = askForDetails(0,&inBuf);
toAdd->name = inBuf;
toAdd->next = NULL;
while((current->next) != NULL){
current = current->next;
}
current->next = toAdd;
}
void print(ListNode *root){
printf("The name is %s.\n",root->name);
/*
ListNode *current = root;
do{
printf("\n%s's hair is %s, their eyes are %s and they are %s years old.\n",current->name,current->hairColor,current->eyeColor,current->age);
current = current->next;
}while(current!=NULL);
*/
}
void remEnd(ListNode *root){
ListNode *current = root;
if(current == NULL){ return; }
}
void addAfter(ListNode *root){
ListNode *current = root;
char *name = getInput("\nWho do you want to add after?\n");
int comparison = 0;
while(current!=NULL&&(comparison = strcmp(name,current->name))!=0){
current = current -> next;
}
if(current==NULL){printf("\nIndividual not found.\n"); return;}
else{
char *newPerson = getInput("What's the name of the person you wish to add? ");
ListNode *toAdd = askForDetails(0,&newPerson);
ListNode *next = current->next;
current -> next = toAdd;
toAdd->next = next;
return;
}
}
void stuff(ListNode *root){
printf("name is %s.\n",root->name);
printf("Root lives at %u.\n",root);
}
void userLoop(ListNode *root){
char input = ' ';
printf("Root lives at %u.\n",root);
while(true){
printf("name is %s.\n",root->name);
if(input!='\n'){
printf("\nWhat would you like to do with your list:\n");
printf("A) Add an element at the end of the list\n");
printf("B) Remove an element from the end of the list\n");
printf("C) Add an element after an element on your list\n");
printf("D) Print your list\n");
printf("E) Quit this program\n\n");
}
input = getchar();
switch(input){
case 'A': addToEnd(root); break;
case 'B': remEnd(root); break;
case 'C': addAfter(root); break;
case 'D': stuff(root); break;
case 'E': return;
}
}
}
When printing the address in memory of root in both functions, I get the same value, so I'm not sure why I am unable to access the values in root in one function instead of the other.
Thank you so much for any help.
You don't seem to quite grasp how the memory model works in C. Your offending piece of code is probably:
ListNode *newNode = malloc(sizeof(ListNode));
newNode = &toReturn;
return newNode;
This returns a pointer to the local variable toReturn, not the malloc'd memory address. You need to copy the data from toReturn into your malloc'd memory space. However, even worse you don't malloc space for each of your strings, so each of your nodes point to the same input buffer. This should work, since you malloc with for every node, however if
you are going to start deleting nodes managing your memory is going to be a little awkward. You also don't make sure there is enough room in your buffer.
I suggest looking at some online resources (or ideally a book) to refresh on how C memory works.
Edit: I did not learn C online, but a quick google search turned up this, which at a quick glance seems to be a decent resource.
I would recommend looking into book list. I used C Programming A Modern Approach.
I'm going to assume you're on a 64 bit system so that pointers are 8 bytes & integers are 4 bytes. Use %p for pointers, not %u

Linked list questions

Hey so i am trying to create a linked list. The following code segment opens the file for reading, which then gets passed into a function to take the string break it down and place it into a node which is suppose to be placed into the list in an appropriate location.
void print_list(struct vm_node *root);
int addNodeBottom(char *val, struct vm_node *head);
struct stock_item* setupNode(char *line);
int main(int argc, char * argv[]) {
struct vm vm;
struct menu_item menu_items[NUM_MENU_ITEMS];
struct vm_node *vmNode;
vmNode = malloc(sizeof(struct vm_node));
/* The UNUSED() function is designed to prevent warnings while your
* code is only partially complete. Delete these 4 function calls once
* you are using the data structures declared above in your own code */
UNUSED(argc);
UNUSED(argv);
UNUSED(vm);
UNUSED(menu_items);
if (argc != 3) {
printf("insuffcient arguments \n");
return EXIT_SUCCESS;
}
/*open stock file*/
char* fileName = argv[1];
FILE *file;
file = fopen(fileName, "r+");
char buf[256];
vmNode->next = NULL;
while (fgets(buf, sizeof buf, file) != NULL) {
addNodeBottom(buf,vmNode);
}
print_list(vmNode);
/* Test reason for reaching NULL. */
if (feof(file)) /* if failure caused by end-of-file condition */
puts("End of file reached");
else if (ferror(file)) /* if failure caused by some other error */
{
perror("fgets()");
fprintf(stderr, "fgets() failed in file %s at line # %d\n", __FILE__,
__LINE__ - 9);
exit(EXIT_FAILURE);
}
fclose(file);
return EXIT_SUCCESS;
}
the following function is how i have described the setupNode function.
struct stock_item* setupNode(char *line) {
struct stock_item *root;
root = malloc(sizeof(struct stock_item));
char *ptr;
const char del[2] = "|";
const char delm[2] = ".";
char *prices;
strcpy(root->id, strtok_r(line, del, &ptr)); // returns the ID and stores in in the root node.
strcpy(root->name, strtok_r(NULL, del, &ptr)); // returns the description and stores it in the root node.
strcpy(root->description, strtok_r(NULL, del, &ptr)); // returns the description and stores it in the root node.
prices = strtok_r(NULL, del, &ptr); // returns a string of the price for vm_item.
int dol = atoi(strtok(prices, delm));
int cent = atoi(strtok(NULL, delm));
root->price.dollars = dol;
root->price.cents = cent;
int quantity = atoi(strtok_r(NULL, del, &ptr)); // returns how many items are in stock.
root->on_hand = quantity;
return root;
}
This is the addNode function
int addNodeBottom(char *val, struct vm_node *head){
//create new node
struct vm_node *newNode = malloc(sizeof(struct vm_node));
if(newNode == NULL){
printf("%s", "Unable to allocate memory for new node\n");
exit(-1);
}
newNode->data = setupNode(val);
newNode->next = NULL; // Change 1
//check for first insertion
if(head->next == NULL){
head->data = newNode->data;
head->next = newNode;
}
else
{
//else loop through the list and find the last
//node, insert next to it
struct vm_node *current = head;
while (TRUE) { // Change 2
if(current->next == NULL)
{
current->next = newNode;
break; // Change 3
}
current = current->next;
};
}
free(newNode);
return 0;
}
and the printList function
void print_list(struct vm_node *root) {
while (root) {
printf("%s ", root->data->id);
root = root->next;
}
printf("\n");
}
Here is the typeDefs
#ifndef VM_TYPE
#define VM_TYPE
#define IDLEN 5
#define NAMELEN 40
#define DESCLEN 255
#define NUMDENOMS 8
#define UNUSED(var) (void)var
#define COIN_COUNT 20
#define DEFAULT_ONHAND 20
/* Type definition for our boolean type */
typedef enum truefalse
{
FALSE, TRUE
} BOOLEAN;
/* Each price will have a dollars and a cents component */
struct price
{
unsigned dollars,cents;
};
/* The different denominations of coins available */
enum denomination
{
FIVE_CENTS, TEN_CENTS, TWENTY_CENTS, FIFTY_CENTS, ONE_DOLLAR,
TWO_DOLLARS, FIVE_DOLLARS, TEN_DOLLARS
};
/* Each coin in the coins array will have a denomination (20 cents,
* 50 cents, etc) and a count - how many of that coin do we have on hand
*/
struct coin
{
enum denomination denom;
unsigned count;
};
/* The data structure that holds the data for each item of stock
*/
struct stock_item
{
char id[IDLEN+1];
char name[NAMELEN+1];
char description[DESCLEN+1];
struct price price;
unsigned on_hand;
};
/* The data structure that holds a pointer to the stock_item data and a
* pointer to the next node in the list
*/
struct vm_node
{
struct stock_item * data;
struct vm_node * next;
};
/* The head of the list - has a pointer to the rest of the list and a
* stores the length of the list
*/
struct vm_list
{
struct vm_node * head;
unsigned length;
};
/* This is the head of our overall data structure. We have a pointer to
* the vending machine list as well as an array of coins.
*/
struct vm
{
struct vm_list * item_list;
struct coin coins[NUMDENOMS];
char * foodfile;
char * coinsfile;
};
#endif
and the format of the text file that is being read in for parsing.
I0001|Coke |375 ml Can of coke |3.50|50
I0002|Pepsi |375 ml Can of pepsi |3.00|20
I0003|Lemon Cheesecake|A delicious, 1/8 size slice of cheesecake |4.00|10
I0004|Mars Bar |A delicious 50 g Mars Bar chilled just the way you like it.|3.00|20
I0005|Lemon Tart |A delicious lemon butter tart with a pastry based |3.75|12
The output when trying to print the list is complete garbage so any thoughts?
You have undefined behavior, because in addNodeBottom you make e.g. current->next point the new node you allocate, then you free the new node, so the pointer in current->next now point to unallocated memory.
Also, when setting up the first node (when head->next is NULL) then don't set the next pointer of head, let it be NULL. Instead to distinguish between an empty list or not, check for a non-null data field:
if (head->data == NULL)
{
// List is empty
}
else
{
// List is not empty
}
Other tips: There's no need to allocate a new node until you actually add it to the list. And the loop to find the last node in the list can be simplified to this:
vm_node *current;
for (current = head; current->next != NULL; current = current->next)
{
// Empty loop body
}
After the above loop current will be the last node in the list, and you can now allocate a new node.
If I would rewrite the addNodeBottom function (without modifying the function signature), it would look something like this (without any error handling):
int addNodeBottom(char *val, struct vm_node *head){
//create new node
stock_item *data = setupNode(val);
if (head->data == NULL)
head->data = data;
else
{
vm_node *current;
for (current = head; current->next != NULL; current = current->next)
;
current->next = malloc(sizeof(*current->next));
current->next->data = data;
current->next->next = NULL;
}
return 0;
}
Note: You must set vmNode->data = NULL before calling the above function for the first time, not only vmNode->next.
The main issue is because you are creating a new Node, storing data in it and then deleting the new node using free.
I understand your logic as it is now in the list so you do not need it anymore. But that is not the issue. In the list you merely put a pointer that points to the new node you created. You do not copy the new node in the list. You only put a pointer that points to the allocated memory for the node you created. If you free that part of the memory then it no longer exists and that part can be overwritten by any other application or yours. So it ends up being garbage.

All Nodes in a linked list point to same object

The problem is somewhere in here....
char buffer[80];
char *name;
while (1) {
fgets(buffer, 80, inf); //reads in at most 80 char from a line
if (feof(inf)) //this checks to see if the special EOF was read
break; //if so, break out of while and continue with your main
name = (char *) malloc(sizeof(char)*20);
....
name = strtok(buffer, " ");//get first token up to space
stock = newStock(name,...)
....
}
I'm working in C with generic linked lists. I made a list implementation that I've tested and know works with chars. I'm trying to add stocks (I created a stock struct) to the linked list, with each node of the linked list holding a stock struct, but when I finish reading in the stocks all of the nodes point to the same struct and I can't figure out why. Here's some snippets of my code
list *list = malloc(sizeof(list));
newList(list, sizeof(stock_t));
while(1) {
...
(read from file)
...
stock_t *stock;
stock = newStock(name, closes, opens, numshares, getPriceF, getTotalDollarAmountF,getPercentChangeF,toStringF);
addToBack(list, stock);
}
Here's the newStock function:
stock_t *newStock(char *name, float closingSharePrice, float openingSharePrice, int numberOfShares, getPrice getP, getTotalDollarAmount getTotal, getPercentChange getPercent, toString toStr) {
stock_t *stock = malloc(sizeof(stock));
stock->stockSymbol = name;
stock->closingSharePrice = closingSharePrice;
stock->openingSharePrice = openingSharePrice;
stock->numberOfShares = numberOfShares;
stock->getP = getP;
stock->getTotal = getTotal;
stock->getPercent = getPercent;
stock->toStr = toStr;
return stock;
}
In a way I see what's wrong. newStock returns a new pointer every time, but it always gets stored in the variable 'stock' which is what every node points to, so it's going to be equal to whatever the last pointer newStock returned was...but I don't see the way around this. I tried having newStock return just a stock_t, and doing addToBack(list, &stock), but that didn't solve the problem either.
Any help would be appreciated!
Here is some code from the list:
typedef struct node {
void *data;
struct node *next;
}node_t;
typedef struct {
int length;
int elementSize;
node_t *head;
node_t *tail;
} list;
void newList(list *list, int elementSize) {
assert(elementSize > 0);
list->length = 0;
list->elementSize = elementSize;
list->head = list->tail = NULL;
}
void addToBack(list *list, void *element) {
node_t *node = malloc(sizeof(node_t));
node->data = malloc(list->elementSize);
node->next = NULL; //back node
memcpy(node->data, element, list->elementSize);
if (list->length == 0) { //if first node added
list->head = list->tail = node;
}
else {
list->tail->next = node;
list->tail = node;
}
list->length++;
}
Here's code from the stock struct:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
typedef float (*getPrice)(void *S);
typedef float (*getTotalDollarAmount)(void *S);
typedef float (*getPercentChange)(void *S);
typedef char *(*toString)(void *S);
typedef struct stock{
char *stockSymbol;
float closingSharePrice;
float openingSharePrice;
int numberOfShares;
getPrice getP;
getTotalDollarAmount getTotal;
getPercentChange getPercent;
toString toStr;
}stock_t;
The generic functions probably seem like overkill but this is for homework (if you couldn't tell already) so we were asked to specifically use them. I don't think that has anything to do with the problem though.
Here are the definitions for those functions anyway
float getPriceF(void *S) {
stock_t *stock = (stock_t*)S;
return stock->closingSharePrice;
}
float getTotalDollarAmountF(void *S) {
stock_t *stock = (stock_t*)S;
return ((stock->closingSharePrice) * (stock->numberOfShares));
}
float getPercentChangeF(void *S) {
stock_t *stock = (stock_t*)S;
return ((stock->closingSharePrice - stock->openingSharePrice)/(stock->openingSharePrice));
}
char *toStringF(void *S) {
stock_t* stock = (stock_t*)S;
char *name = malloc(20*sizeof(char));
//sprintf(name, "Symbol is: %s. ", (stock->stockSymbol));
return stock->stockSymbol;
}
void printStock(void *S) {
char *str = toStringF(S);
printf("%s \n", str);
}
And this is how I'm traversing the list:
typedef void (*iterate)(void *); //this is in the list.h file, just putting it here to avoid confusion
void traverse(list *list, iterate iterator) {
assert(iterator != NULL);
node_t *current = list->head;
while (current != NULL) {
iterator(current->data);
current = current->next;
}
}
And then in my main I just called
traverse(list, printStock);
I can't find any problems with your code (that would cause your problem, anyway - there are places where you don't check the return from malloc() and stuff like that, but those are not relevant to this question). You don't supply the definition of stock_t, so I made a new data struct, and a new couple of functions, otherwise I just copied and pasted the code you provided:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/* Your code starts here */
typedef struct node {
void *data;
struct node *next;
}node_t;
typedef struct {
int length;
int elementSize;
node_t *head;
node_t *tail;
} list;
void newList(list *list, int elementSize) {
assert(elementSize > 0);
list->length = 0;
list->elementSize = elementSize;
list->head = list->tail = NULL;
}
void addToBack(list *list, void *element) {
node_t *node = malloc(sizeof(node_t));
node->data = malloc(list->elementSize);
node->next = NULL; //back node
memcpy(node->data, element, list->elementSize);
if (list->length == 0) { //if first node added
list->head = list->tail = node;
}
else {
list->tail->next = node;
list->tail = node;
}
list->length++;
}
/* Your code ends here */
/* I made a new struct, rather than stock, since you didn't supply it */
struct mydata {
int num1;
int num2;
};
/* I use this instead of newStock(), but it works the same way */
struct mydata * newNode(const int a, const int b) {
struct mydata * newdata = malloc(sizeof *newdata);
if ( newdata == NULL ) {
fputs("Error allocating memory", stderr);
exit(EXIT_FAILURE);
}
newdata->num1 = a;
newdata->num2 = b;
return newdata;
}
/* I added this function to check the list is good */
void printList(list * list) {
struct node * node = list->head;
int n = 1;
while ( node ) {
struct mydata * data = node->data;
printf("%d: %d %d\n", n++, data->num1, data->num2);
node = node->next;
}
}
/* Main function */
int main(void) {
list *list = malloc(sizeof(list));
newList(list, sizeof(struct mydata));
struct mydata * data;
data = newNode(1, 2);
addToBack(list, data);
data = newNode(3, 4);
addToBack(list, data);
data = newNode(5, 6);
addToBack(list, data);
printList(list);
return 0;
}
which outputs this:
paul#MacBook:~/Documents/src$ ./list
1: 1 2
2: 3 4
3: 5 6
paul#MacBook:~/Documents/src$
demonstrating that you have a 3 node list, with all nodes different and where you'd expect them to be.
Either there is some other problem in code you're not showing, or for some reason you are thinking each node points to the same struct when it actually doesn't.
One possibility is that you have a char * data member in your stock struct. It's impossible to tell from the code you provided, but it's possible that you really are creating different nodes, but they all end up pointing to the same name, so they just look like they're the same. If you're assigning a pointer to name, you should make sure it's freshly allocated memory each time, and that you're not just, for instance, strcpy()ing into the same memory and assigning the same address to each stock struct.
EDIT: Looks like that was your problem. This:
name = (char *) malloc(sizeof(char)*20);
....
name = strtok(buffer, " ");
should be:
name = (char *) malloc(sizeof(char)*20);
....
strcpy(name, strtok(buffer, " "));
Right now, you malloc() new memory and store a reference to it in name, but then you lose that reference and your memory when you overwrite it with the address returned from strtok(). Instead, you need to copy that token into your newly allocated memory, as shown.

Resources