Pointer trouble creating binary trees - c

I am creating a binary tree from a bitstring in c. ie 1100100 creates a tree:
1
/ \
1 1
I decided to use a recursive function to build this tree however i keep getting the error
Debug assertion failed...
Expression : CrtIsValidHeapPointer(pUserData)
here is a fragment of my code
typedef
struct Node {
char key;
struct Node *left;
struct Node *right;
} Node;
char string[1000];
int i = 0;
void insertRecursivePreorder(Node **node)
{
Node* parent = *node;
if(string[i] == '0')
{
parent = NULL;
i++;
}
else
{
Node *newn = (Node*)malloc(sizeof(Node));
newn->key = string[i];
parent = newn;
i++;
insertRecursivePreorder(&newn->left); //errors occur here
insertRecursivePreorder(&newn->right); //errors occur here
free(newn);
free(parent);
}
}
int main(void)
{
void printTree(Node* node);
Node* root = NULL;
scanf("%s", string);
insertRecursivePreorder(&root);
//... do other junk
}
i was wondering why this error comes about and what i can do to fix it.

The immediate problem is likely to be calling free on a pointer twice. In insertRecursivePreorder, you set parent to newn, and then call free on both. As an example of this, the following program fails (but works if you comment out one of the free(..)s):
#include <stdlib.h>
int main() {
int *a = malloc(sizeof(int)),
*b = a;
free(a);
free(b);
return 0;
}
However, there are several problems with your logic here. You should only call free when you have completely finished with the pointer, so if you are using your tree later you can't free it as you construct it. You should create a second function, recursiveDestroyTree, that goes through and calls free on the tree (from the bottom up!).
And, you probably want *node = newn rather than parent = newn, since the latter is the only one that actually modifies node.
(You could also change your function to return a Node * pointer, and then just go:
root = insertRecursivePreorder();
and
newn->left = insertRecursivePreorder();
newn->right = insertRecursivePreorder();
instead of trying to keep track of pointers to pointers etc.)
(Furthermore, on a stylistic point, using global variables is often bad practice, so you could have your insertRecursivePreorder take int i and char * string parameters and use them instead of global variables.)

The problem was: you were never assigning to the double pointer in 'insertRecursivePreorder', so root always stayed NULL.
#include <stdio.h>
#include <stdlib.h>
typedef
struct Node {
char key;
struct Node *left;
struct Node *right;
} Node;
/* slightly changed the syntax for the str
** ; now '.' indicates a NULL pointer, values represent themselves.
*/
char *string = "12..3.." ;
/* Removed the global index 'i' */
void printTree(Node* node, int level);
unsigned insertRecursivePreorder(Node **pp, char *str);
unsigned insertRecursivePreorder(Node **pp, char *str)
{
unsigned pos =1;
if (!*str) { *pp = NULL; return 0; } /* safeguard for end of string */
if (*str == '.') { *pp = NULL; return pos; }
*pp = malloc(sizeof **pp);
(*pp)->key = *str;
pos += insertRecursivePreorder(&(*pp)->left, str+pos);
pos += insertRecursivePreorder(&(*pp)->right, str+pos);
return pos;
}
void printTree(Node* node, int level)
{
unsigned pos,len;
len = level> 0 ? level : -level;
for (pos =0; pos < len; pos++) putchar (' ');
if (!level) printf ("Root=");
else if (level<0) printf ("Left=");
else printf ("Right=");
if (!node) { printf( "Null\n" ); return; }
printf("Key=%c\n", node->key );
printTree(node->left, -(len+1) ) ;
printTree(node->right, len+1) ;
}
int main(void)
{
Node *root = NULL;
unsigned result = 0;
result = insertRecursivePreorder(&root, string);
printf( "Result=%u\n", result);
printTree(root, 0);
return 0; printTree(root, 0);
}
Output:
Result=7
Root=Key=1
Left=Key=2
Left=Null
Right=Null
Right=Key=3
Left=Null
Right=Null

Related

Add a list on a trie node in C

I'm adding words (character per node) on a trie data structure - that happens correctly based on a implementantion I found on the web -
http://www.techiedelight.com/trie-implementation-insert-search-delete/
Although I want to extend this and add a list containing some data based on the words, such term frequency etc.
Right now I'm facing an issue with the pointer of the list when adding the first element on a trie node - in the method append_posting_list - and getting a segmetation fault.
Here is the code so far.
main.h
#ifndef TRIE_H
#define TRIE_H
#define CHAR_SIZE 26
typedef struct posting_list {
int doc_id;
int tf;
int df;
struct posting_list *next;
} posting_list_node ;
struct Trie
{
posting_list_node *p_node; // this will be the head of the posting list for every word;
int isLeaf; // 1 when node is a leaf node
struct Trie* character[CHAR_SIZE];
};
struct Trie* getNewTrieNode();
void insert(struct Trie* *head, char* str, int doc_id);
int search(struct Trie* head, char* str);
#endif //TRIE_H
main.c
#include <stdio.h>
#include <stdlib.h>
#include "main.h"
int main(){
struct Trie* head = getNewTrieNode();
insert(&head, "hello", 1);
return 0;
}
// Function that returns a new Trie node
struct Trie* getNewTrieNode()
{
struct Trie* node = (struct Trie*)malloc(sizeof(struct Trie));
node->isLeaf = 0;
for (int i = 0; i < CHAR_SIZE; i++)
node->character[i] = NULL;
return node;
}
posting_list_node* get_mem(){
posting_list_node* p;
p = (posting_list_node *)malloc(sizeof(posting_list_node));
if (p == NULL){
printf("Memory allocation failed\n");
exit(EXIT_FAILURE);
}
return p;
}
void append_posting_list(int doc_id, posting_list_node **n){
posting_list_node *new, *q;
new = get_mem();
new->doc_id = doc_id;
new->tf = 1;
new->next = NULL;
// if new is the first element of the list
if(n == NULL) {
*n = new;
} else {
q = *n;
while( q->next!=NULL) {
q = q->next;
}
q->next = new;
}
}
// Iterative function to insert a string in Trie.
void insert(struct Trie* *head, char* str, int doc_id)
{
// start from root node
struct Trie* curr = *head;
while (*str)
{
// create a new node if path doesn't exists
if (curr->character[*str - 'a'] == NULL)
curr->character[*str - 'a'] = getNewTrieNode();
// go to next node
curr = curr->character[*str - 'a'];
// move to next character
str++;
}
// already found this word, increase frequency
if(curr->isLeaf) {
curr->p_node->tf += 1;
} else {
append_posting_list(doc_id, curr->p_node);
// mark current node as leaf
curr->isLeaf = 1;
}
}
// Iterative function to search a string in Trie. It returns 1
// if the string is found in the Trie, else it returns 0
int search(struct Trie* head, char* str)
{
// return 0 if Trie is empty
if (head == NULL)
return 0;
struct Trie* curr = head;
while (*str)
{
// go to next node
curr = curr->character[*str - 'a'];
// if string is invalid (reached end of path in Trie)
if (curr == NULL)
return 0;
// move to next character
str++;
}
// if current node is a leaf and we have reached the
// end of the string, return 1
return curr->isLeaf;
}
I'm really stuck here.
Any suggestions would be really appreciated.
I found a couple things that when fixed, got rid of your segmentation fault.
In getNewTrieNode() I think you need to set p_node to NULL
struct Trie* getNewTrieNode() {
struct Trie* node = (struct Trie*)malloc(sizeof(struct Trie));
node->isLeaf = 0;
for (int i = 0; i < CHAR_SIZE; i++)
node->character[i] = NULL;
node->p_node = NULL;
return node;
}
append_posting_list() takes post_list_node **, but in insert(), you are passing just post_list_node *
void append_posting_list(int doc_id, posting_list_node **n)
append_posting_list(doc_id, curr->p_node);
looks like it should be
append_posting_list(doc_id, &(curr->p_node));
In append_posting_list()
if (n == NULL) {
should be
if (*n == NULL) {
in order to see if a pointer to an empty list is being passed in.
You should really have some functions to print out your data structure while you are working on it, so you can test each piece as you develop it. Simply compiling and running code and not getting any errors is no gurantee the code is working correctly with complex data structures like this. Making sure that each piece works perfectly before going on to the next piece will save you hours in trying to track down segmentation faults and other errors like this.

Array of linked lists added to from directory

I've been trying to create an array of linked lists. The array being size 26 each part corresponding to a letter of the alphabet. The user inputs a directory of the PC and the name of any folders or files in that directory are then added to the a linked list in the array based on what letter they start with.
How i've been trying to do it->
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
My node and its declaration:
struct node{
char data[50];
struct node *next;
};
struct node* nodeArray[26];
My alphabet:
const char* basis[26] = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"};
A string comparing function to check which linkedlist in the array my word goes(compares to alphabet)
int StartsWith(const char *a, const char *b)
{
if(strncasecmp(a, b, strlen(b)) == 0) return 1;
return 0;
}
Where I add the node and also where the problem is(the printf("1") is there to stop my computer from basically crashing):
void addNode(struct node **q,const char *d){
if(((*q)->data)==NULL){
*q = malloc(sizeof(struct node));
strncpy((*q)->data,d,50);
(*q)->next = NULL;
} else {
(*q)->next = malloc(sizeof(struct node));
*q = (*q)->next;
printf("1");
addNode(q,d);
}
}
The function that calls addNode, directory is a computer directory that's already been checked to exist:
void returner(char* directory){
int i;
DIR *dp;
struct dirent *ep;
char* tempD;
dp = opendir (directory);
struct node **z;
while ((ep = readdir(dp))){
tempD = (char*)malloc(50);
if ( !strcmp(ep->d_name, ".") || !strcmp(ep->d_name, "..") ){
} else {
strncpy(tempD, ep->d_name, 50);
for(i=0; i<26 ; i++){
if(StartsWith(tempD, basis[i])){
z = &nodeArray[i];
addNode(z,tempD);
print();
}
}
}
free(tempD);
}
closedir (dp);
}
Print function:
void print(){
int i;
struct node *temp;
for(i=0 ; i < 26; i++){
temp = malloc(sizeof(struct node));
temp = nodeArray[i];
while(temp != NULL){
printf("%s\n",temp->data);
temp = temp->next;
}
}
}
The program seems fine when adding the first node to a spot on the array such as "aaa.txt" "bbb.txt" "ccc.txt" "ddd.txt", but once a second is attempted to be added like a "ccd.txt" after a "ccc.txt" exists when it keeps going forever or until the pc crashes
You're not checking the right value in your addNode for finding the list insertion point.
Pointer-to-pointer enumeration through a linked list is frequently used to walk from the head pointer to the last next pointer in the list, each time holding the address of the said-pointer. When you reach one that is NULL (which will be head in the case of an empty list), you stop, and you can use your pointer-to-pointer via dereference to assign your new node address.
If you want to insert on the tail, the way to do it would be something like this:
#define DATA_MAX_LEN 50
void addNode(struct node **q,const char *d)
{
// assumes a null-terminated linked list
while (*q)
q = &(*q)->next;
*q = malloc( sizeof **q );
// ensures truncation and termination
strncpy((*q)->data,d,DATA_MAX_LEN-1);
(*q)->data[ DATA_MAX_LEN-1] = 0;
// make sure we terminate the list at our new node
(*q)->next = NULL;
}
Invoked from your updated returner function like this:
void returner(char* directory)
{
DIR *dp = opendir (directory);
if (dp)
{
struct dirent *ep;
while ((ep = readdir(dp)))
{
// skip parent and self symbolic links
if (ep->d_name[0] == '.' && (ep->d_name[1] == 0 || (ep->d_name[1] == '.' && ep->d_name[2] == 0)))
continue;
for(int i=0; i<26 ; i++)
{
if(StartsWith(ep->d_name, basis[i]))
addNode(nodeArray+i, ep->d_name);
}
}
closedir (dp);
}
}

Creating Dynamically Allocated Strings from a file in C

I am having some issues with dynamically allocating a string for a node in a tree. I have included my node structure below for reference.
struct node
{
char *string;
struct node *left;
struct node *right;
};
typedef struct node node;
I am supposed to read words from a text file and then store those words into a tree. I am able to store char arrays that have been defined, such as char string[20] without problems, but not strings that are supposed to be dynamically allocated.
I am only going to post the code I am using to read my file and try to create the dynamically allocated array. I have already created the file pointer and checked that it is not NULL. Every time I try to run the program, it simply crashes, do I need to try and read the words character by character?
//IN MAIN
node *p, *root ;
int i;
int u;
root = NULL;
char input[100];
while(fscanf(fp, "%s", &input) != EOF)
{
//Create the node to insert into the tree
p = (node *)malloc(sizeof(node));
p->left = p->right = NULL;
int p = strlen(input); //get the length of the read string
char *temp = (char*) malloc(sizeof(char)*p);
//malloc a dynamic string of only the length needed
strcpy(local, input);
strcpy(p->word,local);
insert(&root, p);
}
To be completely clear, I only want advice regarding the logic of my code, and only would like someone to help point me in the right direction.
You are invoking many undefined behaviors by
passing pointer to object having wrong type to scanf(). i.e. In fscanf(ifp, "%s", &input), char(*)[100] is passed where char* is expected
accessing out-of-range of allocated buffer when storeing terminating null-character in strcpy(local, input);
using value of buffer allocated via malloc() and not initialized in strcpy(curr->word,local);
Your code should be like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
typedef struct node_t {
struct node_t* left, *right;
int count;
char* word;
} node;
void insert(node ** tree, node * item);
int main(void) {
FILE* ifp = stdin;
node * curr, * root;
int i;
int u;
root = NULL;
char input[100];
/* you should specify the maximum length to read in order to avoid buffer overrun */
while(fscanf(ifp, "%99s", input) != EOF)
{
//Create the node to insert into the tree
curr = malloc(sizeof(node));
if(curr == NULL) /* add error check */
{
perror("malloc 1");
return 1;
}
curr->left = curr->right = NULL;
curr->count = 1;
int p = strlen(input); //get the length of the read string
char *local = malloc(sizeof(char)*(p + 1)); /* make room for terminating null-character */
if (local == NULL) /* add error check again */
{
perror("malloc 2");
return 1;
}
//malloc a dynamic string of only the length needed
//To lowercase, so Job and job is considered the same word
/* using strlen() in loop condition is not a good idea.
* you have already calculated it, so use it. */
for(u = 0; u < p; u++)
{
/* cast to unsigned char in order to avoid undefined behavior
* for passing out-of-range value */
input[u] = tolower((unsigned char)input[u]);
}
strcpy(local, input);
curr->word = local; /* do not use strcpy, just assign */
insert(&root, curr);
}
/* code to free what is allocated will be here */
return 0;
}
//Separate insert function
void insert(node ** tree, node * item)
{
if(!(*tree))
{
*tree = item;
return;
}
if(strcmp(item->word,(*tree)->word) < 0)
insert(&(*tree)->left, item);
else if(strcmp(item->word,(*tree)->word) > 0)
insert(&(*tree)->right, item);
/* note: memory leak may occur if the word read is same as what is previously read */
}

Segmentation error while inserting into binary tree

I cannot figure out how to run this correctly, gives segmentation error. A piece of code is below. Can you look at head too , i am not sure if it is right way of initialising head to null in another file , it is run as follows :
Table tb ;
tb= initialise_table (table_size);
tb = insert(text_words,tb);
//these 3 typedef declarations are in a "some.h" file
typedef struct node * tree_ptr;
typedef char* Key_Type;
typedef struct table* Table;
struct node {
Key_Type element;
tree_ptr left;
tree_ptr right;
};
struct table {
tree_ptr head;
};
Table init_table() {
Table head = NULL;
}
Table insert(Key_Type key ,Table temp ) {
tree_ptr t = (tree_ptr)malloc(sizeof(tree_ptr));
t->element = key;
// t->left = t->right = NULL;
if (temp->head==NULL) {
temp = (Table)malloc (sizeof (Table));
temp->head = t;
printf("empty tree ");
}
else {
temp = insert(t->element,temp);
printf("inserted into ");
}
return temp;
printf("wowo!");
}
The primary issue is in the code which, you say, is used to invoke the functions:
Table tb;
tb = insert(text_words, tb);
You have an uninitialized pointer, tb, which you pass to the function. Inside the function, you have:
Table insert(Key_Type key, Table temp)
{
tree_ptr t = (tree_ptr)malloc(sizeof(*t)); // Fixed size
t->element = key;
// t->left = t->right = NULL;
if (temp->head==NULL)
{
You're therefore accessing (dereferencing) the undefined pointer, and your program is crashing.
You should, I assume, be initializing your table with table_init(), but that function is actually no help whatsoever. It defines and initializes a local variable, but doesn't return anything even though it promises to do so.
Please see Is it a good idea to typedef pointers? The short answer is 'No, it usually isn't a good idea'.
You still have problems even if you fix the calling code like this (a necessary but not sufficient step):
Table tb = NULL;
tb = insert(text_words, tb);
or maybe:
Table tb = init_table();
tb = insert(text_words, tb);
but you need a seriously upgraded version of init_table(), such as:
Table init_table(void)
{
Table root = malloc(sizeof(*head));
root->head = NULL;
return root;
}
Your code in insert() needs to ensure that it does not dereference a null pointer (instead of an indeterminate pointer).
Table insert(Key_Type key, Table root)
{
tree_ptr t = (tree_ptr)malloc(sizeof(*t)); // Fixed size
t->element = key;
t->left = t->right = NULL;
if (root == NULL)
{
root = init_table();
root->head = t;
}
else
{
…
}
return root;
}
Given the Key_Type is a char * in disguise, you may need to review how you save the keys in the tree structure; you may need to use strdup() to copy the data. It is impossible to say for sure without seeing how you are managing the strings that you pass to the insert() function. It could be OK to just save the pointer if the calling code ensures that a new pointer is passed each time. OTOH, if the same pointer is passed each time, you definitely need to copy the data, and using strdup() is a sensible way of doing that. Note that strdup() is standard on POSIX; it is not part of standard C.
Here's one major problem:
tree_ptr t = (tree_ptr) malloc(sizeof(tree_ptr));
should be:
tree_ptr t = (tree_ptr) malloc(sizeof(struct node));
Your code doesn't actually do any binary search. Indeed, it just infinitely recurses creating new nodes. Try something more like this:
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct Node
{
char *element;
struct Node *left;
struct Node *right;
} Node;
typedef struct
{
Node *root;
size_t size;
} Tree;
void Tree_init(Tree *t);
Node *Tree_insert(Tree *t, const char *key);
void Tree_insert_r(Node *subtree, Node *n, size_t size);
void Tree_pre_order_r(Node *subtree);
void Tree_init(Tree *t)
{
t->root = NULL;
t->size = 0;
}
Node *Tree_insert(Tree *t, const char *key)
{
Node *ret = (Node*) malloc(sizeof(Node));
if (ret)
{
ret->left = ret->right = NULL;
if ((ret->element = strdup(key))) /* make a copy of key */
{
if (NULL != t->root)
Tree_insert_r(t->root, ret, t->size);
else
t->root = ret;
++t->size;
}
else
{
free(ret);
ret = NULL;
}
}
return ret;
}
void Tree_insert_r(Node *subtree, Node *n, size_t size)
{
int cmp = strcmp(n->element, subtree->element);
if (cmp < 0 || (cmp == 0 && size % 2 == 0))
{
if (NULL != subtree->left)
subtree = subtree->left;
else
{
subtree->left = n;
return;
}
}
else
{
if (NULL != subtree->right)
subtree = subtree->right;
else
{
subtree->right = n;
return;
}
}
Tree_insert_r(subtree, n, size);
}
void Tree_pre_order_r(Node *subtree)
{
if (NULL == subtree)
return;
fprintf(stdout, "'%s'\n", subtree->element);
Tree_pre_order_r(subtree->left);
Tree_pre_order_r(subtree->right);
}
int main()
{
Tree t;
Tree_init(&t);
Tree_insert(&t, "Hello");
Tree_insert(&t, "World!");
Tree_insert(&t, "etc.");
Tree_pre_order(t.root);
return 0;
}

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