small linked list programme in c, random printf output - c

Im writing a little school programme, I have to use 'void const *content' as a parameter.
I'm having trouble printing the content of the new node. without 'const' the code works and displays everything correct. could someone point out what I'm doing wrong?
terminal output:
�
6
#include <stdio.h>
#include <stdlib.h>
typedef struct s_list
{
void *content;
size_t content_size;
struct s_list *next;
} t_list;
t_list *lstnew(void const *content, size_t content_size)
{
struct s_list *new = (struct s_list*)malloc(sizeof(struct s_list*));
if(new == NULL){
printf("No allocation!");
exit(1);
}
new->content = &content;
new->content_size = content_size;
new->next = NULL;
return(new);
}
int main(void)
{
printf("%s\n", lstnew("Hello", 6)->content);
printf("%zu\n", lstnew("Hello", 6)->content_size);
return(0);
}

You're taking the address of a local variable here:
new->content = &content;
Instead, just take the value:
new->content = content;
Also, you don't allocate enough memory here; you're only allocating enough for the pointer instead of the size of the structure:
struct s_list *new = (struct s_list*)malloc(sizeof(struct s_list*));
The cast on malloc is also unnecessary. I would write it like this:
struct s_list *new = malloc(sizeof(*new));
Instead of using a typedef and t_list, you should just use struct s_list everywhere, because the structure is not intended to be opaque.

In this declaration
struct s_list *new = (struct s_list*)malloc(sizeof(struct s_list*));
instead of allocation memory for an object of the type struct s_list there is being allocated memory for pointer of the type struct s_list *.
You have to write either
struct s_list *new = malloc( sizeof( struct s_list ) );
or
t_list *new = malloc( sizeof( t_list ) );
In this statement
new->content = &content;
the left-side operand has the type void * while the right-hand operand has the type const void **. Moreover you are using a pointer to the local variable content (function parameters are its local variables) that will not be alive after exiting the function.
What you need is to allocate memory and copy the content of the variable content in the allocated memory.
Here is a demonstrative program that shows how the function can be defined.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct s_list
{
void *content;
size_t content_size;
struct s_list *next;
} t_list;
t_list * lstnew( const void *content, size_t content_size )
{
t_list *new = malloc( sizeof( t_list ) );
if ( new != NULL )
{
new->content = malloc( content_size );
if ( new->content == NULL )
{
free( new );
new = NULL;
}
else
{
memcpy( new->content, content, content_size );
new->content_size = content_size;
new->next = NULL;
}
}
return new;
}
int main(void)
{
t_list *head = lstnew( "Hello", 6 );
head->next = lstnew("World!", 7 );
printf( "%s %s\n", ( char * )head->content, ( char * )head->next->content );
return 0;
}
The program output is
Hello World!

Related

struct that holds struct, how to dereference

i have couple of linked lists in my larger program which i now want to keep in a struct (t_holder).
typedef struct s_list
{
int val;
struct t_list *next;
} t_list;
typedef struct s_holder
{
t_list *a_starts;
// more lists...
} t_holder;
now i try to figure out how i dereference this in my program.
void try_out(t_holder *list_holder, int num)
{
//assigning something to a_starts
list_holder->a_starts->val = num;
}
int main(int argc, char *argv[])
{
t_holder *list_holder;
int num;
num = 42;
list_holder = NULL;
try_out(list_holder, num);
return (0);
}
in the function "try_out" i simlpy try to assign a value to a_starts->val but my debugger shows me ACCESS_ERROR if i declare it like this
list_holder->a_starts->val = num;
For starters this typedef declarations
typedef struct s_list
{
int val;
struct t_list *next; // <===
} t_list;
is incorrect. It seems you mean
typedef struct s_list
{
int val;
struct s_list *next; // <===
} t_list;
As for your other code then you declared a null pointer
t_holder *list_holder;
//...
list_holder = NULL;
So dereferencing the null pointer results in undefined behavior.
You need to write something like the following
t_holder list_holder = { .a_starts = NULL };
//...
try_out( &list_holder, num);
and then within the function something like
void try_out(t_holder *list_holder, int num)
{
t_list *node = malloc( sizeof( *node ) );
node->val = num;
node->next = list_holder->a_starts;
list_holder->a_starts = node;
}

Error in stack with linked list implementation

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 );
}
}

Node deletion in linked list from beginning

I want to delete the first node and return the value of the deleted node. But I an getting this warning:
warning: assignment from incompatible pointer type [-Wincompatible-pointer-types]
example=(**example).next;
So, my code does not work. Can anyone help me to fix this? Thanks.
struct myStruct {
int data;
struct myStruct next;
}
int deleteNode(struct myStruct **example) {
struct myStruct *temporary;
if (temporary == NULL) {
emptyNode(temporary); // this function only returns NULL
}
temporary = *example;
example = (**example).next;
free(temporary);
return (**example).data;
}
This structure declaration contains at least two typos.
struct myStruct
{
int data;
struct myStruct next;
}
The first one is that there is no semicolon after the closing brace. And the second one is that the data member next must have pointer type.
It seems you mean
struct myStruct
{
int data;
struct myStruct *next;
};
As for the error message then in this assignment
example=(**example).next;
the left side hand operand has the type struct myStruct ** while the right hand side operand has the type struct myStruct * and these pointer types are not compatible. So the compiler issues an error.
Nevertheless the function in any case is invalid because you are using uninitialized variables like
struct myStruct *temporary;
if(temporary==NULL)
//...
The function interface is bad.because it is unclear what the function returns in case when it is called for an empty list.
The function can be declared and defined the following way.
int deleteNode( struct myStruct **example, int *data )
{
int success = *example != NULL;
if ( success )
{
struct myStruct *temporary = *example;
*example = ( *example )->next;
*data = temporary->data;
free( temporary );
}
return success;
}
And it can be called as it is shown below
#include <stdio.h>
#include <stdlib.h>
struct myStruct
{
int data;
struct myStruct *next;
};
int deleteNode( struct myStruct **example, int *data )
{
int success = *example != NULL;
if ( success )
{
struct myStruct *temporary = *example;
*example = ( *example )->next;
*data = temporary->data;
free( temporary );
}
return success;
}
int main(void)
{
struct myStruct *head = 0;
// fill the list
int data;
if ( deleteNode( &head, &data ) )
{
printf( "The deleted value is %d\n", data );
}
else
{
puts( "The list is empty." );
}
return 0;
}

Print void pointer in a Linked List

I have an array of structs called arrayOfElements , the structs are called Elements which have a void pointer
typedef struct {
void* data;
} Element;
Ive malloc'd arrayOfElements
Element* arrayOfElements;
arrayOfElements= malloc(4 * sizeof(Element));
and have stored ints and strings in the strucs
arrayOfElements[3].data = malloc( sizeof(int) );
ptr = arrayOfElements[3].data;
*ptr = 65;
strcpy(arrayOfElements[1].data, token );
Then I have created a Linked List
typedef struct LinkedList {
void* arrayOfStruct;
struct LinkedList* next;
} LinkedList;
And have created a function to import a instance of arrayOfELements and make void* arrayOfStruct point to it
LinkedList* insert(LinkedList* head, Element* inArrayOfElements) {
LinkedList* insertNode = malloc(sizeof(LinkedList));
insertNode->next = head;
insertNode->arrayOfStruct = (void*)inArrayOfElements;
return insertNode;
}
Question
My question is after I have pointed void* arrayOfStruc to an instance of arrayOfELements, how do I print void* data of arrayOfElements[3] which I know from before is an int and its value is 65
Current Node in LinkedList ---> arrayOfElements[3] --> data member in Element struct (should equal 65)
I have a feeling I should point a int pointer to it and then print that, but Im not sure the syntax to do it
You need some way of knowing what kind of data the data member points to. An additional element denoting the type would work.
typedef enum {
STR_TYPE,
INT_TYPE,
...
} data_type;
typedef struct {
data_type type;
void* data;
} Element;
Then you can set the element like this:
arrayOfElements[3].type = INT_TYPE;
arrayOfElements[3].data = malloc( sizeof(int) );
int *ptr = arrayOfElements[3].data;
*ptr = 65;
arrayOfElements[1].type = STR_TYPE;
strcpy(arrayOfElements[1].data, token );
and read it like this:
Element *curr = &list_node->arrayOfStruct[3];
if (curr->type == INT_TYPE) {
int *pint = curr->data;
printf("int data = %d\n", *pint);
}

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