I just got started on a lab of mine where I calculate the GPA of courses whose information is stored in a linked list of structures. As of now, I'm attempting to just print out all the course information to ensure that they have been properly initialized and added to the link list.
I'm running into a problem though because I keep getting a Segmentation Fault. I understand what the Segmentation Fault means, but I do not know where I am making my mistake. Any help would be appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define MAX_CLASSES 20
/* Function Prototypes */
struct course * initcourse( int, char *, char *, float, char *, char *);
void add( struct course * );
/* Definition of a data node holding course information */
struct course {
int term;
char name[15];
char abbrev[20];
float hours;
char grade [4];
char type[12];
struct course *next;
};
/* head points to first node in list, end points to last node in list */
/* initializes both to NULL, no nodes yet */
struct course *head = (struct course *) NULL;
struct course *end = (struct course *) NULL;
/* Initializes a node, allocates memory for the node, and returns */
/* a pointer to the new node. Must pass correct parameters. */
struct course * initcourse( int term, char *name, char *abbrev, float hours, char *grade, char *type)
{
struct course *ptr;
ptr = (struct course *) calloc( 1, sizeof(struct course ) );
if( ptr == NULL )
return (struct course *) NULL;
else
{
ptr->term = term;
strcpy( ptr->name, name );
strcpy( ptr->abbrev, abbrev );
ptr->hours = hours;
strcpy( ptr->grade, grade );
strcpy( ptr->type, type );
return ptr;
}
}
/* This adds a node to the end of the list. You must allocate a node and */
/* then pass its address to this function */
void add(struct course *new)
{
if (head == NULL)
{
head = new;
}
else
{
end->next = new;
end = new;
}
}
/* Prints all information in a node */
void printnode( struct course *ptr )
{
printf("Term ->%d\n", ptr->term );
printf("Name ->%s\n", ptr->name );
printf("Abbreviation ->%s\n", ptr->abbrev );
printf("Hours ->%f\n", ptr->hours );
printf("Grade ->%s\n", ptr->grade );
printf("Type ->%s\n", ptr->type );
}
/* Prints List of Nodes */
void printlist( struct course *ptr )
{
while( ptr != NULL )
{
printnode( ptr );
ptr = ptr->next;
}
}
/* Calculates GPA */
/* float gpa ( struct course *ptr ) */
/* { */
/* float totalhours; */
/* float gpa; */
/* float gradepoints; */
/* while (ptr != NULL ) */
/* { */
/* totalhours += (ptr->hours); */
/* gradepoints = (ptr->hours * ptr->grade); */
/* } */
/* gpa = (gradepoints /ptr->hours); */
/* } */
int main()
{
int term;
char name[15];
char abbrev[20];
float hours;
char grade[4];
char type[12];
float gpa;
struct course *ptr;
struct course course1, course2, course3;
course1.term = 1234;
strcpy(course1.name,"cse1234");
strcpy(course1.abbrev,"systems");
course1.hours = 4;
strcpy(course1.grade,"A");
strcpy(course1.type,"GEC");
ptr = initcourse(course1.term, course1.name, course1.abbrev, course1.hours, course1.grade, course1.type);
struct course *head, *ptr2;
head = ptr;
// ptr2 = ptr;
add(ptr);
course2.term = 4332;
strcpy(course2.name,"cse4332");
strcpy(course2.abbrev,"Database");
course2.hours = 4;
strcpy(course2.grade,"B");
strcpy(course2.type,"Technical");
ptr2 = initcourse(course2.term, course2.name, course2.abbrev, course2.hours, course2.grade, course2.type);
add(ptr2);
printlist(head);
}
void add(struct course *new)
{
if (head == NULL)
{
head = new;
}
else
{
end->next = new;
end = new;
}
}
You need to set end to new when inserting the first node (when head == NULL), otherwise you're dereferencing a null-pointer when adding further nodes.
And in initcourse, you ought to set the next member to NULL, since it is not guaranteed by the standard that all-bits-0 is a null-pointer representation (it very likely is, but there's no guarantee).
Also,
struct course *head, *ptr2;
head = ptr;
declares a new local variable head that shadows the global one, and instead of assigning directly to head (even though it's the wrong one), you should call add(ptr);.
You dont initialize the next pointer, so the last element contains a bad pointer, pointing to some garbage.
You also don't initialize end.
Another problem (not related to the crash) is that this code will create a duplicate entry:
head = ptr;
add(ptr);
There're other problems. You really should get a debugger and see what's going on.
Related
I'm trying to implement stack using linked list implementation. Its giving me "Segmentation Error". Please help me finding the error. This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 100
struct NODE {
char word;
struct NODE *next;
};
struct STACK {
struct NODE *head;
int size;
};
void pushStack(struct STACK *stack, char s);
void makeStack(struct STACK *stack, char *s);
void printStack(struct STACK *stack);
int main(){
char *s;
fgets(s,100,stdin);
struct STACK stack;
stack.head = NULL;
makeStack(&stack,s);
printStack(&stack);
return 0;
}
void pushStack(struct STACK *stack, char s){
struct NODE temp;
temp.word = s;
temp.next = stack->head;
stack->head = &temp;
}
void makeStack(struct STACK *stack, char *s){
char temp[MAX];
strcpy(temp,s);
for(int i=0; i<MAX; i++){
if(temp[i]=='\0') break;
pushStack(stack,temp[i]);
}
}
void printStack(struct STACK *stack){
struct NODE *trav = stack->head;
while (trav != NULL){
printf("%c", trav->word);
trav = trav->next;
}
}
MAX=100 is the limit I'm taking for string input. I haven't also added increasing the size because I'm just ignoring the increment of size for now. Before I could perfect the implementation
In main the s pointer is not initialized and it points nowhere.
int main(){
char *s; // <<< this is wrong, you want 'char s[100]' instead
fgets(s,100,stdin);
...
However the safest option is this:
int main(){
char s[100]; // declare array of 100 chars
fgets(s, sizeof(s), stdin); // sizeof(s) is the actual size of s (100 here)
...
This is wrong too: you store the pointer to the local variable temp, but that variables ceases to exist once you return from the pushStask function.
void pushStack(struct STACK* stack, char s) {
struct NODE temp;
temp.word = s;
temp.next = stack->head;
stack->head = &temp;
}
Instead you need to create a new struct NODE like this:
void pushStack(struct STACK* stack, char s) {
struct NODE* temp = malloc(sizeof *temp);
temp->word = s;
temp->next = stack->head;
stack->head = temp;
}
Instead of malloc(sizeof *temp) you could write sizeof(struct NODE), it's the same, but it's less fool proof because you could mistakenly write sizeof(struct STACK) which would compile fine, but the size of the allocated memory would be wrong.
Another problem: you don't assign the size field of the struct STACK, this is not a problem now, but it might become a problem later.
There are several drawbacks in your implementation of a stack.
The first one is that you are using a pointer with an indeterminate value to read a string
char *s;
fgets(s,100,stdin);
So the call of fgets invokes undefined behavior.
Moreover there is used a magic number 100.
You need to allocate a character array and use it to read a string.
#define MAX 100
//...
char s[MAX];
fgets( s, MAX, stdin );
Pay attention to that the name word for an object of the type char is confusing
struct NODE {
char word;
struct NODE *next;
};
You could define the structure like for example
struct NODE {
char c;
struct NODE *next;
};
or
struct NODE {
char item;
struct NODE *next;
};
Instead of separating the declaration and the initialization as you did
struct STACK stack;
stack.head = NULL;
forgetting to initialize the data member size (that by the way should have an unsigned integer type as for example size_t) you could just write for example
struct STACK stack = { NULL, 0 };
or
struct STACK stack = { .head = NULL, .size = 0 };
In the declaration of the function makeStack the second parameter should have the qualifier const because the passed string is not being changed within the function. And as a memory allocation in general can fail the function should report whether all characters of the string were pushed successfully. So the function declaration should look like
int makeStack( struct STACK *stack, const char *s );
It does not make a sense to declare a local array temp within the function
void makeStack(struct STACK *stack, char *s){
char temp[MAX];
//...
using the index variable i is redundant. Also the function fgets can append the new line character '\n' to the input string that you should not push on stack.
The function can be defined the following way
int makeStack( struct STACK *stack, const char *s )
{
int success = 1;
for ( ; *s && success; ++s )
{
if ( *s != '\n' )
{
success = pushStack( stack, *s );
}
}
return success;
}
Another approach is to remove the new line character from the input string before passing it to the function makeStack.
For example
s[ strcspn( s, "\n" ) ] = '\0';
makeStack( &stack, s );
If it is the user that is responsible whether to push the new line character on stack or not then the function makeStack can be simplified
int makeStack( struct STACK *stack, const char *s )
{
int success = 1;
for ( ; *s && success; ++s )
{
success = pushStack( stack, *s );
}
return success;
}
Correspondingly the function pushStack also should be redefined.
For starters it shall dynamically allocate a new node. Otherwise you will try to add nodes that are local to the function and will not be alive after exiting the function that again results in undefined behavior.
The function pushStack can be defined the following way.
int pushStack( struct STACK *stack, char c )
{
struct NODE *temp = malloc( sizeof( struct NODE ) );
int success = temp != NULL;
if ( success )
{
temp->word = c;
temp->next = stack->head;
stack->head = temp;
++stack->size;
}
return success;
}
The parameter of the function printStack should have the qualifier const because the stack itself within the function is not being changed.
The function can be defined at least the following way
void printStack( const struct STACK *stack )
{
for ( const struct NODE *trav = stack->head; trav != NULL; trav = trav->next )
{
printf( "%c", trav->word );
}
}
I'm trying to create a temporary 'iterator' struct which is assigned to the beginning of the 'list', and then iterate through that list of structures by checking iterator->next != NULL. I believe the issue is in the iterator = start lines (35 & 70).
The application compiles without any issues, but I'm given a Segmentation Fault (core dumped) when I ./ the application.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct record
{
int accountno;
char name[25];
char address[80];
struct record* next;
};
int addRecord (struct record **, int, char [], char []);
void printAllRecords(struct record *);
int main(int argc, char *argv[]) {
struct record ** start;
start = NULL;
addRecord(start, 1, "Record Name", "Record Address");
printAllRecords(*start);
return 0;
}
void printAllRecords(struct record * start)
{
struct record * recordIterator;
/* Allocate the required memory and return a pointer to it */
recordIterator = malloc(sizeof(struct record));
/* Start at the beginning */
recordIterator = start;
printf("\n\n%10s %20s %20s\n", "accountno", "Name", "Address");
while (recordIterator != NULL)
{
printf("%10d %20s %20s\n", recordIterator->accountno, recordIterator->name, recordIterator->address);
recordIterator = recordIterator->next;
}
}
int addRecord (struct record ** start, int accountno, char name[], char address[])
{
struct record * newRecord;
/* Allocate the required memory and return a pointer to it */
newRecord = malloc(sizeof(struct record));
/* Assign values to the new record */
newRecord->accountno = accountno;
strcpy(newRecord->name, name);
strcpy(newRecord->address, address);
if (start == NULL)
{
start = &newRecord;
}
else
{
struct record * recordIterator;
/* Allocate the required memory and return a pointer to it */
recordIterator = malloc(sizeof(struct record));
/* Start at the beginning */
recordIterator = *start;
while (recordIterator->next != NULL)
{
recordIterator = recordIterator->next;
}
recordIterator->next = newRecord;
}
return 1;
}
You can declare start to be a pointer as in
struct record * start;
And then you can call the method by addRecord(&start, ...).
Inside the method:
int addRecord (struct record ** start, int accountno, char name[], char address[])
{
struct record * newRecord;
/* Allocate the required memory and return a pointer to it */
newRecord = malloc(sizeof(struct record));
/* Assign values to the new record */
newRecord->accountno = accountno;
strcpy(newRecord->name, name);
strcpy(newRecord->address, address);
if (*start == NULL)
{
*start = newRecord;
}
When passing pointers around, within a function, remember that what you can permanently modify is the value that occupies an address, not the address itself. Here in the modified version, the value of start is not changed (which we can not do anyway... the change won't be reflected as the method returns), however we are modifying the value that start points to.
This line
addRecord(start, 1, "Record Name", "Record Address");
won't modify start. Therefore start is still NULL when you call printAllRecords.
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.
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.
I have a struct called warehouse and a generic linked list and each item points to a warehouse struct.
typedef struct linked{
char type;
void * item;
struct linked * next;
struct linked * prev;
}LinkedList;
typedef struct warehouse{
char * name;
float volume;
float (* getPrice) (void * S);
float (* getTotalDollarAmount)(void * S);
}house_t;
When I tried to get the getPrice function pointer point to a function float price (void *S)
void menu (LinkedList *house){
char *c;
float num;
c = (char*)malloc(sizeof(char)*10);
LinkedList *i;
i = (LinkedList*)malloc(sizeof(LinkedList);
house_t *sk;
sk = (house_t *) malloc(sizeof(house_t));
//i->item = (house_t *) malloc(sizeof(house_t));
scanf("%c", c);
((house_t*)i->item)->getPrice = price;
sk=findhouse(house, c);
num = ((house_t*)i->item)->getPrice(sk);
printf("%f",num);
}
I got bad access error. Since every time I got a bad access error it was because I didn't allocate memory for something. But do I need to allocate memory for function pointer? If so, how?
Here's some more code
float price (void *S)
{
return ((house_t*)S)->volume;
}
LinkedList *i;
i = NewLinkedList();
/* ... snip ... */
LinkedList *NewLinkedList()
{
return NULL;
}
According to your definition of NewLinkedList(), the variable i is now NULL. You try and dereference it with i->item = ... but you can't do this if i is NULL. I think what you really want to do is allocate space for your linked list in your NewLinkedList function:
LinkedList * NewLinkedList()
{
LinkedList *result = malloc(sizeof(LinkedList));
result->type = '\0'; // set to suitable initial value
result->item = NULL;
result->next = NULL;
result->prev = NULL;
return result;
}