Troubleshooting compile time circular linked list errors - c

Okay, so I'm getting these errors upon compile with gcc:
prelab6.h: In function âinsertHeadCircularâ:
prelab6.h:45: error: incompatible types in assignment
prelab6.h:46: error: incompatible types in assignment
prelab6.c: At top level:
prelab6.c:41: warning: data definition has no type or storage class
prelab6.c:41: warning: parameter names (without types) in function declaration
prelab6.c:41: error: conflicting types for âprintInOrderâ
prelab6.h:81: error: previous definition of âprintInOrderâ was here
prelab6.c:42: warning: data definition has no type or storage class
prelab6.c:42: warning: parameter names (without types) in function declaration
prelab6.c:42: error: conflicting types for âprintReverseâ
prelab6.h:112: error: previous definition of âprintReverseâ was here
I've tried and tried, but to no avail to fix these errors. Thanks for any and all help.
Here's my .c file:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "my.h"
int main ( int argc, char **argv )
{
char firstname[100];
char lastname[100];
int monthsEmployed;
FILE *fptr;
fptr = fopen(argv[1], "r");
if (fptr == NULL)
printf ("Incorrect file reading!");
if (argc != 2)
printf ("Incorrect number of arguments!");
employeeInfo *insert;
insert = malloc(sizeof(employeeInfo));
employeeList *head;
head = NULL;
while(!feof(fptr))
{
fscanf (fptr, "%100s %100s %d", firstname, lastname, &monthsEmployed);
strcpy(insert->firstname, firstname);
strcpy(insert->lastname, lastname);
insert->monthsEmployed = monthsEmployed;
head = insertHeadCircular(head, insert);
}
}
printInOrder(head); // display the linked list
printReverse(head); // display the linked list in reverse
And my .h file (note things are commented out because I tried things differently with no results):
typedef struct employeeInfo{
char firstname[100];
char lastname[100];
int monthsEmployed;
}employeeInfo;
//Struct containing pointers to the next and previous used to make a circular linked list
typedef struct list{
employeeInfo emp;
struct list *next;
struct list *previous;
}employeeList;
employeeList *insertHeadCircular(employeeList *head, employeeInfo *emp);
void printInOrder(employeeList head);
void printReverse(employeeList head);
employeeList *insertHeadCircular(employeeList *head, employeeInfo *emp)
{
employeeList *theprevious = head;
employeeList *current;
employeeList *thenext = head;
current = malloc(sizeof(employeeList));
employeeInfo *employee;
if(thenext==NULL)
{
current->next = current;
current->previous = current;
}
else
{
current->next = thenext;
thenext->previous = current;
while(theprevious->next != thenext)
{
theprevious = theprevious->next;
}
current->previous = theprevious;
theprevious->next = current;
}
current->emp = (employeeInfo *)malloc(sizeof(employeeInfo));
employee = current->emp;
employee = malloc(sizeof(employeeInfo));
strcpy(employee->firstname, emp->firstname);
strcpy(employee->lastname, emp->lastname);
employee->monthsEmployed = emp->monthsEmployed;
/*
employeeList *newcell, *first = head;
if(head == NULL)
{
newcell = (struct list *)malloc(sizeof(struct list));
strcpy(newcell->firstname, emp->firstname);
strcpy(newcell->lastname, emp->lastname);
newcell->monthsEmployed = emp->monthsEmployed;
return newcell;
}
while(head->next != first)
{
head = head->next;
}
newcell = (struct list *)malloc(sizeof(struct list));
head->next = newcell;
strcpy(newcell->firstname, emp->firstname);
strcpy(newcell->lastname, emp->lastname);
newcell->monthsEmployed = emp->monthsEmployed;
newcell->next = first;
*/
return current;
}
void printInOrder(employeeList head)
{
/*employeeInfo *first = head;
if (head == NULL)
{
printf("The circularly linked list is empty!\n");
return;
}
do
{
printf("%s %s %d\n", emp.firstname, emp.lastname, head.monthsEmployed);
head = head->next;
} while(head != first);
*/
/*employeeInfo current = head;
employeeInfo start = head;
int loop = 0;
printf("--------------\n");
while(current != start || loop==0)
{
loop++;
printf("Employee: %s %s\nMonths Employed: %d", current->firstname, current->lastname, current->monthsEmployed);
printf("--------------\n");
current=current->next;
}*/
}
void printReverse(employeeList head)
{/*
employeeList current = head
employeeInfo start = head
int theloop=0;
printf("--------------\n");
while(current! = start || loop==0)
{
loop++;
printf("Employee: %s %s\nMonths Employed: %d", current->firstname, current->lastname, current->monthsEmployed);
printf("--------------\n");
current=current->previous;
}*/
}
EDITED PROGRAM
Error:
file.c: In function âmainâ:
file.c:37: error: incompatible type for argument 2 of âinsertHeadCircularâ
The .c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "file.h"
int main ( int argc, char **argv )
{
char firstname[100];
char lastname[100];
int monthsEmployed;
FILE *fptr;
fptr = fopen(argv[1], "r");
if (fptr == NULL)
printf ("Incorrect file reading!");
if (argc != 2)
printf ("Incorrect number of arguments!");
employeeInfo *insert;
insert = malloc(sizeof(employeeInfo));
employeeList *head;
head = NULL;
while(!feof(fptr))
{
fscanf (fptr, "%100s %100s %d", firstname, lastname, &monthsEmployed);
strcpy(insert->firstname, firstname);
strcpy(insert->lastname, lastname);
insert->monthsEmployed = monthsEmployed;
head = insertHeadCircular(head, insert);
}
printInOrder(head); // display the linked list
printReverse(head); // display the linked list in reverse
}
The .h:
typedef struct employeeInfo{
char firstname[100];
char lastname[100];
int monthsEmployed;
}employeeInfo;
typedef struct list{
employeeInfo emp;
struct list *next;
struct list *previous;
}employeeList;
typedef employeeList *listnode;
employeeList *insertHeadCircular(employeeList *head, employeeInfo emp);
void printInOrder(employeeList *head);
void printReverse(employeeList *head);
employeeList *insertHeadCircular(employeeList *head, employeeInfo emp)
{
listnode newPtr;
listnode firstPtr;
listnode tempPtr;
newPtr = (employeeList *)malloc(sizeof(employeeList));
strcpy(newPtr->emp.firstname, emp.firstname);
strcpy(newPtr->emp.lastname, emp.lastname);
newPtr->emp.monthsEmployed = emp.monthsEmployed;
if(head == NULL)
{
newPtr->next = newPtr;
newPtr->previous = newPtr;
head = newPtr;
firstPtr = newPtr;
}
else
{
tempPtr = firstPtr;
newPtr->next = tempPtr;
tempPtr->previous = newPtr;
newPtr->previous = head;
head->next = newPtr;
firstPtr = newPtr;
}
return head;
}
void printInOrder(employeeList *head)
{
listnode currentPtr = head;
do
{
printf("%s %s %d\n",currentPtr->emp.firstname, currentPtr->emp.lastname, currentPtr->emp.monthsEmployed);
currentPtr= currentPtr->previous;
}
while(currentPtr !=head);
}
void printReverse(employeeList *head)
{
listnode currentPtr = head->next;
do
{
printf("%s %s %d\n",currentPtr->emp.firstname, currentPtr->emp.lastname, currentPtr->emp.monthsEmployed);
currentPtr = currentPtr->next;
}
while(currentPtr != head->next);
}

In your insertHeadCircular() function, you treat the emp member of employeeList as though it were an employeeInfo *. For example, you declare:
employeeInfo *employee;
but then later do this:
employee = current->emp;
However, your employeeList type contains an instance of employeeInfo, not a pointer to one:
typedef struct employeeInfo{
char firstname[100];
char lastname[100];
int monthsEmployed;
}employeeInfo;
/* ... */
typedef struct list{
employeeInfo emp; /* see? Not a pointer. */
struct list *next;
struct list *previous;
}employeeList;
So basically you need to correct your code so that you stop assigning a structure to a pointer, and instead assign the address of the structure to the pointer.
Most likely your printInOrder() and printReverse() functions should take employeeList * arguments, rather than employeeList ones, as well... and you should check the code you use for them to make sure you don't confuse the two anywhere.
It's also a good idea to define your functions somewhere other than the header file, such as in a separate .c source file. The header file should just contain function prototypes, macros, and other declarations that may be needed for other source files; you don't need the function bodies in there, since the linker can find them in the object files created from your other sources. Defining functions in header files like that will cause endless headaches when the header file is #includeed by more than one file.
The error you get with your updated code, file.c:37: error: incompatible type for argument 2 of âinsertHeadCircularâ is pointing out that the type of argument you're passing to insertHeadCircular() isn't the type you gave in its declaration -- which is true. You've declared and defined that function to take an employeeInfo as its second argument:
employeeList *insertHeadCircular(employeeList *head, employeeInfo emp)
...but in main() you pass it a pointer instead:
employeeInfo *insert;
...
head = insertHeadCircular(head, insert);
So you need to change one or the other. Either dereference insert when you call the function from main, or change insertHeadCircular() to take a pointer instead (and update the body accordingly). The latter is probably better, since it avoids copying the entire structure onto the stack when you call the function.
Some other things to point out:
You should really check the return from scanf() in your loop in main(). It would let you know whether all the fields were actually read; right now, if they weren't, your program just proceeds with whatever junk the variables already had (like whatever was read on the previous iteration, possibly). Checking other return values (like the return from malloc()) is a good idea too, but in this case the scanf() return is particularly important.
You also don't free insert at the end of your program; the OS will (almost certainly) clean it up when your program exits, but it's good practice to do it yourself when you're done with it. The way you use it, though, you didn't really need to dynamically allocate it anyway; you could have just declared an employeeInfo and taken its address (works either way, though).

Related

Why is my Professor's Linked List Printing Backwards?

I have a project that I'm working on for a Systems Programming course. I'm building off of my professor's code. (Please don't mind her lack of labelling, etc. - I'm gonna try to clean this up as best as I can.)
Does anybody know why her linked list code is printing backwards?
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Node {
char name[15];
char title[15];
int year;
struct Node *next;
struct Node *prev;
};
typedef struct Node *Box;
Box print_list(Box pointer);
Box insert_node(FILE *inputp);
int main() {
Box head = NULL, temp;
FILE *inputp, *outputp;
int i;
inputp = fopen("input.txt", "r");
outputp = fopen("output.txt", "w");
head = insert_node(inputp);
for (i = 0; i < 4; i++) {
temp = insert_node(inputp);
temp->next = head;
head = temp;
}
print_list(head);
return 0;
}
Box print_list(Box pointer) {
Box here = pointer;
while (here != NULL) {
printf("%s, %s, %d \n", here->name, here->title, here->year);
here = here->next;
}
return pointer;
}
Box insert_node(FILE *inputp) {
Box temp = NULL;
temp = (Box)malloc(sizeof(struct Node));
fscanf(inputp, "%s", &temp->name);
fscanf(inputp, "%s", &temp->title);
fscanf(inputp, " %d", &temp->year);
temp->next = NULL;
temp->prev = NULL;
return temp;
}
This program's purpose is to read a .txt file "playlist" of songs and create a linked list out of them. The input is:
Rachmaninov Concerto_No_2 1999
Mozart Symphony_No_41 2000
Vivaldi The_Seasons 2003
Beethoven Symphony_No_5 1994
Bach Toccatas 2005
While the program outputs:
Bach, Toccatas, 2005
Beethoven, Symphony_No_5, 1994
Vivaldi, The_Seasons, 2003
Mozart, Symphony_No_41, 2000
Rachmaninov, Concerto_No_2, 1999
(I also don't know why she included an output file in the code, all of the output is in the console, not stored in a file. Ignore that.)
The list prints in reverse order because you insert each new node at the beginning of the list. You should use a tail pointer to keep track of the end of the list.
Also note these remarks:
both the next and the prev links should be updated.
hiding pointers behind typedefs as in typedef struct Node *Box; is considered bad practice because it is confusing and error prone.
insert_node is a confusing name for a function that merely allocates a new node from file data.
insert_node should test if fscanf() succeeded at reading the data
fscanf(inputp, "%s", &temp->name); has undefined behavior if the name of the composer exceeds 14 bytes. The same applies to the title. The maximum number of characters to store into the destination arrays before the null terminator should be specified as %14s and these arrays should be defined with a larger length.
main should check if a node was successfully allocated and initialized from file data. Instead of hardcoding the number of nodes, one should iterate as long as nodes can be read from the file.
Here is a modified version:
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Node {
char name[40];
char title[40];
int year;
struct Node *next;
struct Node *prev;
};
void print_list(const Node *pointer);
Node *read_node(FILE *inputp);
int main() {
Node *head = NULL;
Node *tail = NULL;
Node *node;
FILE *inputp, *outputp;
int i;
inputp = fopen("input.txt", "r");
if (!inputp) {
fprintf(stderr, "cannot open input.txt: %s\n", strerror(errno));
return 1;
}
outputp = fopen("output.txt", "w");
if (!outputp) {
fprintf(stderr, "cannot open output.txt: %s\n", strerror(errno));
return 1;
}
while ((node = read_node(inputp)) != NULL) {
if (!head) {
head = tail = node;
} else {
node->prev = tail;
tail = tail->next = node;
}
}
print_list(head);
// should free node list
return 0;
}
void print_list(const Node *pointer) {
while (pointer != NULL) {
printf("%s, %s, %d\n", pointer->name, pointer->title, pointer->year);
pointer = pointer->next;
}
}
Node *read_node(FILE *inputp) {
Node *temp = malloc(sizeof(*temp));
if (temp != NULL
&& fscanf(inputp, "%39s%39s%d", &temp->name, &temp->title, &temp->year) == 3) {
temp->next = NULL;
temp->prev = NULL;
return temp;
} else {
free(temp);
return NULL;
}
}

access to data allocated by pointer in a structure issue

I'm working on code that using structures and Linked list.
Please help me to understand how can I print any added point that is not in the head of the list created.
Any attempt was a failure.
*Issue on the second print call.
Is my only option is to do head = head->next in order to get the next variables?
Structures:
typedef struct
{
int x;
int y;
}point;
typedef struct {
point *p;
struct Item *next;
}Item;
Main:
void main()
{
Item *head = (Item*)malloc(sizeof(Item)); //head of co-list
if (!head) { //allocation check
printf("Allocation failed (head)\n");
exit(1);
}
head = addBegin(head);
printf("head point: (%d,%d)\n",head->p->x,head->p->y);
system("pause");
head = addBegin(head);
**printf("head second point: (%d,%d)\n",head->next->p->x,head->next->p->y);**
system("pause");
free(head->p);
free(head);
}
The function:
Item * addBegin(Item *head)
{
Item *tmp = (Item*)
malloc(sizeof(Item));
if (tmp) {
tmp->p = (point*)malloc(sizeof(point));
printf("Enter x's point: ");
scanf(" %d", &tmp->p->x);
printf("Enter y's point: ");
scanf(" %d", &tmp->p->y);
tmp->next = head;
return tmp;
}
else{ //memory allocation failed
printf("allocation failed (new head)\n");
exit(2);
return head;
}
You would want to walk the list, with code similar to:
for ( Item* current = &head;
current != NULL;
current = current->next ) {
do_stuff_with(current->p);
}
This stops when you reach the end of the list: that is, when you have processed the last node containing data, whose next pointer is NULL, and updated current to NULL.
On a side note, you want to tweak the definition of Item slightly, to:
typedef struct Item {
point *p;
struct Item *next;
} Item;
Some compilers, including GCC, will realize that Item.next has the same type, and stop giving you spurious warnings about anonymous structs and incomplete types.
it might also pay to decide whether you want to use Item and Point, or item and point. Inconsistent capitalization is confusing.

Linked list of chars in C

I'm trying to create a linked list holding char type data.
For some reason, the code does not work. The GCC compiler's warning for function "add_bottom_ListEl" is
"warning: passing argument 2 of 'add_bottom_listEl' makes integer from pointer without a cast"
and
"note: expected 'char' but argument is of type 'char * "
I suspect that there's something wrong about the way I use pointers, but I've tried many, many combinations, passing pointers to the function etc... But nothing seemed to work.
Here's main function and all the others used. MAX_CHAR is defined in all files (#define MAX_CHAR 30)
int main()
{
char name[MAX_CHAR];
scanf("%s", name);
ListEl *head = malloc(sizeof(ListEl));
strcpy(head->name, name);
head->next = NULL;
printf("%s", head->name);
add_bottom_listEl(head, name);
print_listEl(head);
return 0;
}
void add_bottom_listEl (ListEl *head, char name)
{
ListEl *newEl;
while(head->next!=NULL)
{
head=head->next;
}
newEl = (ListEl*) malloc(sizeof(ListEl));
strcpy(newEl->name, name);
newEl->next = NULL;
}
void print_listEl(ListEl* head)
{
puts("print");
ListEl* current = head;
while (current!=NULL)
{
int i=1;
printf("%d.%s\n", i, current->name);
++i;
current = current -> next;
}
}
The ListEl structure is just a regular element of a linked list
struct ListEl
{
char name[MAX_CHAR];
struct ListEl* next;
};
Obviously, I used
typedef struct ListEl ListEl;
Every linked list tutorial on the internet or this site is only showing how to handle lists with integers or numbers in general, but not arrays (chars). Can anyone help me out here?
Your function "add_bottom_listEl" takes one character called "name", not a character array (or a pointer to a character). My guess is you want it to be:
add_bottom_listEl(ListEl *head, char *name)
If your intention in add_bottom_listEl is to modify and pass back head, then head has to be passed as a pointer to a pointer:
void add_bottom_listEl(ListEl** head, char* name) {
if ( head == NULL ) {
//head is invalid, do nothing
return;
}
//Use calloc instead of malloc to initialise the memory area
ListEl* newEl = (ListEl*)calloc(1, sizeof(ListEl));
//Ensure only name of the permissible length is copied
strncpy(newEl->name, name, MAX_CHAR-1);
//No need to do this now...calloc will initialise it to NULL
//newEl->next = NULL;
if ( *head == NULL ) {
//No nodes in list yet, this is the first
*head = newEl;
} else if ( *head != NULL ) {
//Find the end of the list
while((*head)->next!=NULL) {
*head = (*head)->next;
}
}
//Add the new node to the list
*head = newel;
}
When you call this modified version of the function pass the address of the pointer:
add_bottom_listEl(&head, name);
You can make your typedef more readable by doing this:
typedef struct _listEl {
char name[MAX_CHAR];
struct _listEl* next;
} ListEl;
The line
void add_bottom_listEl (ListEl *head, char name)
should be
void add_bottom_listEl (ListEl *head, char* name)

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