I am having trouble with linked lists in C, I have only done data structures such as this in c++.
Gdb is giving me a
Program received signal SIGSEGV, Segmentation fault.
0x0804a23c in addArg (base=0x1, argument=0x804e410 "is") at myshell.c:42
42 while ( (curr != NULL) && (curr->n != NULL) )
I am familiar with segmentation faults having to do with memory, however I thought I have allocated memory correctly. What am I doing wrong?
addArg is being called as addArg(currentCmd->args, lexeme);and currentCmd is a pointer to a node struct
struct lnode {
char *x;
struct lnode *n;
};
struct node
{
char *command;
struct lnode *args;
int input;
int output;
int error;
char *in;
char *out;
char *err;
struct node *next;
struct node *prev;
};
void addArg(struct lnode *base, char *argument)
{
struct lnode *curr = base;
//this is line 42
while ( (curr != NULL) && (curr->n != NULL) )
curr = curr->n;
curr -> n = malloc(sizeof(struct lnode));
curr = curr->n;
curr->x = strdup(argument);
curr->n = NULL;
}
struct node* createNode(char *command_, int input_, int output_, int error_, char *in_, char *out_, char *err_, struct node *prev_)
{
struct node *n;
n = malloc(sizeof (struct node));
n->command = strdup(command_);
n->prev = prev_;
n->next = NULL;
n->input = input_;
n->output = output_;
n->error = error_;
n->in = in_;
n->out = out_;
n->err = err_;
n->args=malloc(sizeof(struct lnode));
return n;
}
It looks like currentCmd->args is an invalid pointer. Perhaps a pointer to free()d memory. Or an uninitialized pointer, or a pointer to a local variable that's gone out of scope (though these latter two don't appear to be the case here).
Or perhaps you've accidentally overwritten out-of-bounds memory somewhere else in your program. Pointer issues aren't always at the point of failure; sometimes they're in earlier code, unrelated code even.
I solved this issue by making the lnode *args into lnode args and making the required changes to memory managment.
What i can see from your gdb output, the problem with while ( (curr != NULL) && (curr->n != NULL) ) is that if curr == NULL you are still trying to access curr->n to compare, so you should change that condition to only compare curr, and handle curr->n only if curr is not null, maybe breaking the cicle inmediatly if curr->n == NULL.
Related
Im trying to create a simple programme to add a value to a linked list.
the code does compile with out errors.
Im getting a segmentation fault when trying to execute the file.
I tried to debug using printf statements, but I don't get any output anywhere.
could someone point out what im doing wrong.
typedef struct in separate .h file, include files also in separate .h file
typedef struct s_list
{
struct s_list *next;
void *data;
} t_list;
void list_push_front(t_list **begin_list, void *data)
{
t_list *l;
l = (t_list*)malloc(sizeof(t_list));
if(l == NULL){
printf("No allocation");
}
printf("%s\n", l->data);
l->data = data;
l->next = *begin_list;
*begin_list = l;
printf("%s\n", l->data);
}
int main(void)
{
t_list *k;
k = (t_list*)malloc(sizeof(t_list));
if(k == NULL){
printf("No allocation");
}
printf("allocation");
char s[] = "Woow!";
k->data = "Hello";
k->next->data = NULL;
// k->next->next->data = NULL;
list_push_front(&k, s);
return(0);
}
In the printf call
l = (t_list*)malloc(sizeof(t_list));
if(l == NULL){
printf("No allocation");
}
printf("%s\n", l->data);
you are trying to output non-initialized memory pointed to by the pointer l->data. So the function invokes undefined behavior. Remove this call of printf. It does not make sense.
Also in main this statement
k->next->data = NULL;
is incorrect and also invokes undefined behavior. It seems you mean
k->next = NULL;
As a general point, always compile with the -Wall -Werror flags and run your code frequently (every couple of lines). This should help avoid a lot of the problems here. Use valgrind, asan or gdb to detect and diagnose memory issues like the ones in this program.
k->next->data = NULL; is illegal because k->next is uninitialized.
printf("%s\n", l->data);, same problem. You must initialize a value before use.
Functions should not produce side effects like printing. It's OK for temporary debugging, but beyond that it makes for noisy programs and essentially unusable functions. If you want errors, print to stderr and exit or use return values such as an enum or NULL to indicate errors.
Always free allocated memory.
No need to cast the result of malloc.
Use consistent indentation and formatting.
A possible rewrite:
#include <stdio.h>
#include <stdlib.h>
typedef struct ListNode {
struct ListNode *next;
void *data;
} ListNode;
ListNode *list_create(void *data) {
ListNode *node = malloc(sizeof(*node));
if (!node) {
fprintf(stderr, "%s %d: malloc failed\n", __FILE__, __LINE__);
exit(1);
}
node->data = data;
node->next = NULL;
return node;
}
void list_push_front(ListNode **head, void *data) {
ListNode *node = list_create(data);
node->next = *head;
*head = node;
}
void list_free(ListNode *head) {
while (head) {
ListNode *dead = head;
head = head->next;
free(dead);
}
}
int main(void) {
ListNode *list = list_create("a");
list_push_front(&list, "b");
list_push_front(&list, "c");
for (ListNode *curr = list; curr; curr = curr->next) {
printf("%s\n", (char *)curr->data);
}
list_free(list);
return 0;
}
I was trying to allocate memory using malloc, I am not able to understand why I am getting a different result for these two malloc calls.
The line below gives me wrong result even though with gdb I see the
data is getting the correct value assigned.
nodeptr n = malloc(sizeof(nodeptr));
Value head->data: '!'
Value head->eq->data: ''
And when I do this get the correct result:
nodeptr n = malloc(sizeof(struct Node));
Value head->data: 'w'
Value head->eq->data: 'X'
I followed this post, I think I am doing it correctly.
In both ways, while allocation I get the same amount of memory, just I see the different results in the end.
typedef struct Node
{
struct Node *left, *right, *eq;
char data;
bool isEnd;
} *nodeptr;
nodeptr newNode(const char c) {
nodeptr n = malloc(sizeof(nodeptr));
// nodeptr n = malloc(sizeof(struct Node));
n->data = c;
n->left = NULL;
n->right = NULL;
n->left = NULL;
n->isEnd = false;
return n;
}
void insert(nodeptr *node, const char *str) {
if (*node == NULL) {
*node = newNode(*str);
}
nodeptr pCrawl = *node;
if(pCrawl->data < *str) {
insert(&pCrawl->right, str);
} else if (pCrawl->data > *str) {
insert(&pCrawl->left, str);
} else {
if(*(str+1)) {
insert(&pCrawl->eq, str + 1);
} else {
pCrawl->isEnd = true;
}
}
}
int main(int argc, char const *argv[])
{
const char* const strs[5]= {
"w.",
};
nodeptr head = NULL;
for(int i = 0; i<1; i++) {
insert(&head, strs[i]);
}
return 0;
printf("Value head->data: \'%c\'\n", head->data);
printf("Value head->eq->data: \'%c\'\n", head->eq->data);
}
sizeof(nodeptr) == sizeof(struct Node*) != sizeof(struct Node) == sizeof(*nodeptr)
sizeof(nodeptr) will always be the size of a pointer (like 8 bytes on a 64-bit CPU)
sizeof(struct Node) refers to the struct contents
sizeof(*nodeptr) is equivalent to sizeof(struct Node) with the extra dereference operator in there.
The reason it may appear to "work" (not segfault) is that malloc suballocates from a larger block of heap memory. However, the code is writing out-of-bounds of the requested allocation, which can eventually lead to heap corruption or segfaults at some point.
The two different versions aren't allocating the same amount of memory. sizeof(nodeptr) is the size of a pointer and sizeof(struct Node) is the size of your struct. These are not the same things and they're not the same size. On my computer these values are 8 and 32.
You want to use:
nodeptr n = malloc(sizeof(struct Node));
or perhaps:
nodeptr n = malloc(sizeof(*n)); // size of the type that n points too
When working with a basic example like this, I am getting a segmentation fault. I believe it's due to the size of the data not being fixed. How can I have variable length data attached to a struct?
struct Node {
char * data;
struct Node* next;
};
void compareWord(struct Node** head_ref, char * new_data) {
if (strcmp((*head_ref)->data, new_data) > 0) {
head_ref->data = new_data;
}
}
int main(int argc, char* argv[]) {
struct Node* head = NULL;
head->data = "abc";
char buf[] = "hello";
compareWord(&head, buf);
return 0;
}
How can I have variable length data attached to a struct?
Answer is - No, you cannot. The reason is the size of the struct should be known at compile time.
The reason for segmentation fault is, your program is accessing head pointer before allocating memory to it:
struct Node* head = NULL;
head->data = "abc";
Allocate memory before using head:
struct Node* head = NULL;
head = malloc (sizeof(struct Node));
if (NULL == head)
exit(EXIT_FAILURE);
head->data = "abc";
Make sure to free allocated memory once you have done with it.
There is something known as Flexible Array Member(FAM) introduced in C99 standard. It may be of your interest.
I have two linked lists that I track using inputFront, inputRear, outputFront & outputRear. My problem arises when I enqueue the data from input into output. Printf prints only the first item from the input. Ex: my input is "a b c", it will only return "a". I'd appreciate the help. Thanks.
struct linked_list{
char *operand;
struct linked_list *next;
};
void enqueue(struct linked_list** queueFront, struct linked_list** queueRear,
char* token);
char* dequeue(struct linked_list** queueFront, struct linked_list** queueRear);
int main(int argc, char *argv[]){
struct linked_list *inputFront = NULL, *inputRear = NULL;
struct linked_list *outputFront = NULL, *outputRear = NULL;
for (int i = 1; i < argc; i++)
enqueue(&inputFront, &inputRear, argv[i]);
for (struct linked_list *p = inputFront; p != NULL; p = p->next)
enqueue(&outputFront, &outputRear, dequeue(&inputFront, &inputRear));
for (struct linked_list *p = outputFront; p != NULL; p = p->next)
printf("%s \n", dequeue(&outputFront, &outputRear));
}
void enqueue(struct linked_list** queueFront, struct linked_list** queueRear,
char* token){
struct linked_list* newNode = (struct linked_list*) malloc(
sizeof(struct linked_list));
newNode->operand = token;
newNode->next = NULL;
if (*queueRear == NULL && *queueFront == NULL){
*queueFront = *queueRear = newNode;
return;
}
(*queueRear)->next = newNode;
*queueRear = newNode;
}
char* dequeue(struct linked_list** queueFront, struct linked_list** queueRear){
if (*queueFront != NULL){
struct linked_list *remv = *queueFront;
char *remOperand = (*queueFront)->operand;
*queueFront = remv->next;
if (remv == (*queueRear))
*queueRear = NULL;
free(remv);
return remOperand;
}
else
return NULL;
}
There are 2 issues with your code. See.
for (struct linked_list *p = inputFront; p != NULL; p = p->next)
enqueue(&outputFront, &outputRear, dequeue(&inputFront, &inputRear));
You are using a pointer p to run through the list, but this pointer is not used inside the loop. The inputFront in the statement must be replaced by this pointer p. This will allow it to run through every element of the loop.
In the dequeue function, you are moving the pointer inputFront (now p). So, if you do p = p-> next in the loop, it will be done twice. This has to be removed.
Fixed code is
for (struct linked_list *p = inputFront; p != NULL; )
enqueue(&outputFront, &outputRear, dequeue(&p, &inputRear));
for (struct linked_list *p = outputFront; p != NULL; )
printf("%s \n", dequeue(&p, &outputRear));
The problem seems to be in your print loop. You let p advance until the end of the list, and you let dequeue retrieve the next (first) item in the list. But dequeue also removes the front from the list. Following the return, the for-loop now also advances p, whose next member has jus been advanced already. Given input a b c, I would expect the output now to be a c. If you take a debugger, you can get some more clues.
I have a struct that I use to build a linked list as below;
struct my_struct{
char a[16];
struct my_struct *next;
}
I free that linked list by below function;
void free_my_list(struct my_struct* recv) {
if (recv->next != NULL)
free_my_list(recv->next);
free(recv);
recv = NULL;
}
In my program, I use a struct _my_list over and over but free and malloc it every time as below:
struct my_struct *_my_list;
free_my_list(_my_list);
_my_list = (my_list *) malloc(sizeof(my_list));
_my_list->next = NULL;
Every time I fill the list, I print char arrays and then reset _my_struct by above code.
Above code works fine on Ubuntu pc, but on Cent OS after printing first list(after first malloc _my_struct) correctly, following list are printed as corrupted data.
When I don't free and malloc memory during whole program execution it works fine in Cent OS too but I should reset list _my_list between printf() calls.
_my_list is filled and printed via below functions;
/*prints every item in my_list*/
void print_my_list(struct my_struct *recv, FILE *fd) {
my_list *tmp;
tmp = recv;
while (tmp != NULL) {
if (fwrite(tmp->a, 1, strlen(tmp->a), fd) == -1) {
pritnf("error\n");
}
tmp = tmp->next;
}
}
/*Add 'a' string to _my_list*/
void add_recv_to_list(struct my_struct **recv_list, char *recv) {
struct my_struct *tmp;
tmp = *recv_list;
if (*recv_list == NULL) {
*recv_list = (struct my_struct *) malloc(sizeof(struct my_struct));
tmp = *recv_list;
} else {
while ((tmp->next) != NULL) {
tmp = tmp->next;
}
tmp->next = (struct my_struct *) malloc(sizeof(struct my_struct));
tmp = tmp->next;
}
strncpy(tmp->a, recv, MAX_NAME_LEN);
tmp->next = NULL;
}
What can be the reason, any ideas?
I think that your problem may start here:
struct my_struct *_my_list;
free_my_list(_my_list);
_my_list = (my_list *) malloc(sizeof(my_list));
_my_list->next = NULL;
When you initialize the struc: struct my_struct *_my_list; you don't assign it any value, so it holds whatever garbage data was in memory beforehand. When you free() that in free_my_list, the behavior is undefined (you are freeing something that you never malloc()ed - so the result may very well be corruption of something or other later on. Try changing your declaration to: struct my_struct *_my_list = NULL; (always a good practice to initialize pointers to NULL, anyway) and changing your free_my_list function to:
void free_my_list(struct my_struct* recv) {
if (recv == NULL)
return;
if (recv->next != NULL)
free_my_list(recv->next);
free(recv);
recv = NULL;
}