String-based linked list in C produces segmentation fault - c

----------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node {
char *val;
struct node *next;
};
void add_to_list(struct node **, char *);
void list_all_elements(struct node *);
int main (int argc, char **argv)
{
char *val;
struct node *head = NULL;
do {
scanf("%s",val);
add_to_list(&head, val);
}
while(val[0] != '\\');
list_all_elements(head);
}
void add_to_list(struct node **head, char *val)
{
//This produces a segfault
struct node *temp = malloc(sizeof *temp);
//EDIT - Fixed as per comments
temp->val = malloc(strlen(val) + 1);
strcpy(temp->val, val);
temp->next = NULL;
if(head!=NULL)
temp->next = *head;
*head = temp;
}
void list_all_elements(struct node *head)
{
while(head!=NULL) {
printf("%s\n",head->val);
head = head->next;
}
}
So this is what I compiled to implement a linked list. Now, for some reason malloc'ing the produces a segmentation fault.
To be sure, I replaced char * with a char [] and the code runs just fine. Is the malloc faulting due to this or is there some trivial error I can't seem to find?

You did not allocate the val in the main
char *val;
...
scanf("%s",val);
but here val is not allocated, when you do the scanf is going to sigsegv

You did not allocate memory that would be pointed to by variable val and where you are going to read a string.
char *val;
//...
do {
scanf("%s",val);
add_to_list(&head, val);
}
Variable val was not initialized so the program has undefined behaviour.
And function add_to_list is invalid. For example sizeof(val) has always the same value that is equal to the size of the pointer to char. It does not yield the size of a string pointed to by this pointer. Instead of the operator sizeof you shall use function strlen
The function could be written like
void add_to_list( struct node **head, const char *val )
{
struct node *temp = malloc( sizeof *temp );
size_t n = strlen( val );
temp->val = malloc( n + 1 );
strcpy( temp->val, val );
temp->next = *head;
*head = temp;
}

temp->val = malloc(sizeof(val));
Change sizeof(val) to strlen(val)+1.

Related

how to remove a node from a linked list

I want to perform a binary operation between two nodes, store the result in one node and eliminate the other. This is what I've written:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
struct n{
double value;
char op;
struct n *next;
};
void delete(struct n *head);
void add_item(struct n **ptr, double *data);
int main(){
struct n *head = NULL;
double result;
add_item(&head, 5);
add_item(&head, 3);
head->op = '*';
result = (head->next)->value * head->value;
(head->next)->value = result;
delete(head);
printf("%lf\n",head->value);
free(head);
return 0;
}
void add_item(struct n **ptr, double *data)
{
struct n *item = malloc(sizeof *item);
item->value = *data;
item->next = *ptr;
item->op = '?';
*ptr = item;
}
void delete(struct n *head)
{
struct n *temp;
temp = head->next;
head->next = temp->next;
free(temp);
}
In this example I have a list like this 3 -> 5 -> NUll. I'd like to get this 15 -> NUll.
When I try to print the value of the node remaining I get 3 instead of 15
The both functions are invalid.
To the function add_item you do not pass data by reference (and it does not make sense to pass data by reference).
add_item(&head, 5);
add_item(&head, 3);
So the function should be declared and defined like
void add_item(struct n **ptr, double data)
{
struct n *item = malloc(sizeof *item);
item->value = data;
item->next = *ptr;
item->op = '?';
*ptr = item;
}
You have to pass the head node to the function delete also by reference.
void delete(struct n **head)
{
if ( *head )
{
struct n *temp = *head;
*head = ( *head )->next;
free( temp );
}
}
and call it like
delete( &head );
When I try to print the value of the node remaining I get 3 instead of
15
It is because you deleted the node after the head instead of deleting the head node though the result of the operation you wrote in the node after the head.
(head->next)->value = result;
Here is your updated program
#include <stdio.h>
#include <stdlib.h>
struct n{
double value;
char op;
struct n *next;
};
void delete(struct n **head);
void add_item(struct n **ptr, double data);
int main(){
struct n *head = NULL;
double result;
add_item(&head, 5);
add_item(&head, 3);
head->op = '*';
result = (head->next)->value * head->value;
(head->next)->value = result;
delete(&head);
printf("%lf\n",head->value);
free(head);
return 0;
}
void add_item(struct n **ptr, double data)
{
struct n *item = malloc(sizeof *item);
item->value = data;
item->next = *ptr;
item->op = '?';
*ptr = item;
}
void delete(struct n **head)
{
if ( *head )
{
struct n *temp = *head;
*head = ( *head )->next;
free( temp );
}
}
Its output is
15.000000
As is in general with C, for a function to have the power to change an object passed to it via the argument list, the address of the object must be passed, not the object itself. ( read more on this here )
In this example, the object, head, if it is to be changed in any way, requires that its address ( &head ) be passed to the function, not the object itself.
So the statement:
delete(head); //passing the object will not allow it to be changed
Should be changed to
delete(&head); //The object's address is passed, allowing the object to be changed
And because the object being passed was created as a pointer: struct n *head = NULL;, the prototype for the delete function needs to accommodate the address of a pointer in its argument. This is done with a pointer to a pointer:
void delete(struct n **head);//accommodates the address of a pointer object
Then, inside the delete function, work on the object itself, (which is now *head) to make the changes.
void delete(struct n **head)
{
if (*head == NULL) return;
struct n *temp = *head;
*head = temp->next;//point head to next node
free(temp);//free old head
}
Conversely, in your void add_item(struct n **ptr, double *data); function, data does not need to be changed, only used within the body. Indeed the way it has been called in your code is the correct way to send the data:
add_item(&head, 5); // 2nd argument passes object directly, i.e. not an address
Therefore, because the function needs the data itself, and not a pointer to the data, change the prototype to accommodate:
void add_item(struct n **ptr, double data);
Change the code in the body of the code accordingly.

Segmentation Fault 11: 10

I have a problem with solving a problem. I get continue the segmentation fault: 11 error, while I try this code. And every time I change the code the error pops up, and I don't know where the flaw is, so I would be greatfull if anyone sees the flaw.
I thank you in advance.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "dbg.h"
typedef struct node{
char *data;
struct node *next;
} node_t;
node_t **push(node_t **head, char *data){
node_t *new_node;
new_node = malloc(sizeof(node_t));
new_node->data = data;
new_node->next = *head;
*head = new_node;
free(new_node);
return head;
}
int main(int argc, char *argv[])
{
node_t **head;
char *data = "hoi";
char *data2 = "hallo";
head = malloc(20 * sizeof(node_t));
head = push(head, data);
head = push(head, data2);
printf("%s\n",(*head)[1].data);
free(head);
return 0;
}
Flaws:
Your push() function assigns the value of new_node to *head, making it accessible to the invoker of push(), but at the end of the function you free new_node, making it a dangling pointer. That's a good ground for segmentation faults.
head is a pointer to a pointer but is assigned the result of a malloc() invokation that seems to indicate that it should be a pointer to a node.
Your design is confusing: do you want to allocate the memory in push() or in main(). Certainly, both is not a good choice.
You are pointing to constant strings with non constant pointers. This is dangerous. Writing to the constant strings through these pointers could lead to segmentation faults too.
Here is a version of your program that works:
#include <stdio.h>
#include <stdlib.h>
struct node {
const char *data;
struct node *next;
};
static struct node *push(struct node *head, const char *data) {
struct node *node;
node = malloc(sizeof *node);
node->data = data;
node->next = head;
return node;
}
int main(int argc, char *argv[])
{
struct node *head = NULL;
const char *data = "hoi";
const char *data2 = "hallo";
head = push(head, data);
head = push(head, data2);
struct node *node = head;
while (node) {
printf("%s\n", node->data);
node = node->next;
}
return 0;
}
Note that I implemented a LIFO structure, aka. a stack, because a push() function usually applies to a stack.
A logical next step for you would be to implement the pop() function. Typically, I would recommend that pop() frees the node and returns the data. That would provide a nice symmetry for your API.

Simple malloc function in c

#define SIZE 7000
static char buf[SIZE];
static char *bufptr = buf;
struct node
{
int reg_num;
int val;
char var_name[30];
char var_str[100];
struct node *memroy;
struct node *next;
};
struct node* add(struct node *head, int i)
{
struct node *temp;
if (head == NULL)
{
temp = (struct node *)malloc(sizeof(struct node));
temp->next = NULL;
temp->reg_num = i;
head = temp;
}
else
{
head->next = add(head->next, i);
}
return head;
}
void* malloc(int n)
{
if (buf + SIZE - bufptr >= n)
{
bufptr += n;
return bufptr - n;
}
else
{
return NULL;
}
}
When I run my programm it crashes during the assignment temp->next = NULL.
I think the problem is in my malloc function. I tested it with malloc in libraries and it worked correctly, but I not allowed to use libraries and must write a new malloc function.
You never check the return of your malloc yet you know it can return NULL;.
Check if temp is NULL before doing temp->next = NULL;
My problem don't has relation with kind of pointer and returned value from malloc().I have problem with size of buf[] and by increment of size my problem solved.Tnx from every one.

making a pointer that stores an element of a char array

I've been struggling trying to figure out why I am getting the following warning:
initialization makes pointer from integer without a cast
The highlighted warnings are where I mentioned below. The code I am currently using is just the beginning of creating tree of elements in a linked list fashion. This code seems to be working fine however I get docked points for warnings.
typedef struct Node {
struct Node *leftChild;
struct Node *rightChild;
char data;
} Node;
Node *TreeCreate(int level, const char *data) {
struct Node *ptr = (struct Node*) malloc(sizeof (Node));
if (ptr == NULL) {
// malloc failed
return 0;
}
ptr->data = data; // WARNING
ptr->leftChild = NULL;
ptr->rightChild = NULL;
return ptr;
}
// TEST CODE IN MAIN
char list[6] = {'A', 'B', 'C','\0'};
// Determines the element
const char *tree = list[0]; // WARNING
ptr = TreeCreate(1, tree);
if (ptr != NULL) {
sprintf(string, "TreeData: %c\n", ptr->data);
OledDrawString(string);
OledUpdate();
}
Your fundamental mistake is that you are assigning a poitner to a char which is wrong
const char *tree = list[0]; // WARNING
this will not yield the result you expect.
The * in this case is not dereferencing the pointe, you are declaring a poitner and pointeing to a char with it, then when you try to access the pointer, your program tries to read at an invalid memory address causing undefined behavior.
Then you do the opposite thing in
ptr->data = data;
you should enable compiler warnings to avoid this mistakes.
To handle the data you apparently want to handle, first you need to redefine the struct like this
typedef struct Node {
struct Node *leftChild;
struct Node *rightChild;
char *data;
/* ^ this should be a char pointer */
} Node;
then in the TreeCreate() function, copy the data by first allocating space and then using memcpy() like this
Node *TreeCreate(int level, const char *data) {
size_t length;
struct Node *ptr;
ptr = malloc(sizeof (Node));
if (ptr == NULL) {
return NULL;
}
if (data != NULL)
{
length = strlen(data);
ptr->data = malloc(1 + length);
if (ptr->data != NULL)
memcpy(ptr->data, data, 1 + length);
}
else
ptr->data = NULL;
ptr->leftChild = NULL;
ptr->rightChild = NULL;
return ptr;
}
I think I understand. The following fixed my warnings. Thanks for the fast response!
const char *tree = &list[0];
ptr->data = *data;
the following, a complete program,
that cleanly compiles
and has the warnings fixed
and eliminates the clutter and unnecessary typedef statements.
#include<stdio.h>
#include<stdlib.h>
struct Node
{
struct Node *leftChild;
struct Node *rightChild;
char data;
};
struct Node *TreeCreate(int level, const char *data)
{
struct Node *ptr = malloc(sizeof (struct Node));
if (ptr == NULL)
{
// malloc failed
return NULL ;
}
// implied else, malloc successful
ptr->data = *data; // WARNING
ptr->leftChild = NULL;
ptr->rightChild = NULL;
return ptr;
}
int main()
{
struct Node *ptr = NULL;
char string[120] = {'\0'};
// TEST CODE IN MAIN
char list[6] = {'A', 'B', 'C','\0'};
// Determines the element
const char *tree = &list[0]; // WARNING
ptr = TreeCreate(1, tree);
if (ptr != NULL)
{
sprintf(string, "TreeData: %c\n", ptr->data);
//OledDrawString(string);
//OledUpdate();
}
return 0;
}

Segmentation error for linked list

My execution's name is test4.
Input:
$ ./test4 cccc zz abcdef0123456789 aaabbbcccddd
I expect to create a linked list of type char* as follow:
---> 12:aaabbbcccddd ---> 12:abcdef0123456789 ---> 2:zz ---> 4:cccc
each node has the form of "n:a" (n is the length of string a, n <= 12, if the length of a is more than 12 then n = 12)
Below is my code:
struct Node *prepend(struct Node *list, char *s)
{
struct Node *node = (struct Node *)malloc(sizeof(struct Node));
if (node == NULL)
return NULL;
int length_s = strlen(s);
if (length_s > 12)
length_s = 12;
char* temp = NULL;
sprintf(temp,"%d:%s", length_s, s);
strcpy(node->data, temp);
node->next = list;
return node;
}
prepend function links a new node to list
struct Node {
struct Node *next;
char *data;
};
int main(int argc, char **argv)
{
struct Node *list = NULL;
argv++;
while (*argv)
{
list = prepend(list,*argv);
argv++;
}
return 0;
}
Assume all necessary libraries and struct are included, I keep getting a segmentation error when running the code. How do I fix it? I believe the problem is in sprintf but can't figure out why.
You don't allocate memory for temp here:
char* temp = NULL;
sprintf(temp,"%d:%s", length_s, s);
You could use either a static array of chars or dynamically allocate the memory for it.
In order to copy what you want, you should so this:
If data of Node is a char*,
node->data = malloc((length_s + 1) + 1 + digits_of_length);
sprintf(node->data,"%d:%s", length_s, s);
If data of Node is an array of chars, you should do this:
sprintf(node->data,"%d:%s", ((length_s + 1) + 1 + digits_of_length), s);
As you see this gets a bit nasty, because you have to find the digits of the length too, in order to allocate memory.
Why not augmenting your Node with an extra field called str_length, which will keep track of the length of the string the current node holds. That way, you could modify your function to this:
struct Node *prepend(struct Node *list, char *s)
{
struct Node *node = (struct Node *)malloc(sizeof(struct Node));
if (node == NULL)
return NULL;
int length_s = strlen(s);
node->data = malloc(length_s + 1);
strcpy(node->data, temp);
node->str_length = length_s + 1;
node->next = list;
return node;
}
When you go trhough this, don't forget to write a free_list(), which will de-allocates the whole list.
Also, don't cast what malloc returns. Why?
The problem is in these statements
char* temp = NULL;
sprintf(temp,"%d:%s", length_s, s);
You did not allocate memory that will be pointed to by poointer temp. Sp the program has undefined begaviour.
You could make your life simpler if instead of the pointer in your structure you would use an array of size 12 + 1 because the length of copied strings is limited by 12 characters.
For example
enum { size = 13 };
struct Node
{
char data[size];
Node *next;
};
//...
struct Node *prepend( struct Node *list, const char *s )
{
struct Node *node = ( struct Node * )malloc( sizeof( struct Node ) );
if ( node == NULL ) return list;
strnspy( node->data, s, size );
node->data[size - 1] = '\0';
node->next = list;
return node;
}
If you need to use a pointer instead of a character array and sprintft instead of strncpy hen you can write
struct Node *prepend( struct Node *list, const char *s )
{
const size_t N = 12;
struct Node *node = ( struct Node * )malloc( sizeof( struct Node ) );
if ( node == NULL ) return list;
node->data = malloc( ( N + 1 ) * sizeof( char ) );
sprintf( node->data, "%*.*s", N, N, s );
node->next = list;
return node;
}
When the list will not be needed any more you have to delete it. For example
void delete( struct Node *list )
{
while ( list )
{
Node *tmp = list;
list = list->next;
free( tmp->data );
free( tmp );
}
}

Resources