Segmentation Fault 11: 10 - c

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.

Related

Failed to use strcpy() in stack

this is a code about push strings and pop strings from a stack, the string name must be fixed (not input by user). But the code is unable to run (it cannot display anything). And the point is because strcpy(temp->id,val);, if i get rid of strcpy(temp->id,val);, then the code can be run properly (but printf unreadable characters). Can I know whats is the problem with my strcpy?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct LLNode
{
char id[4];
struct LLNode *next;
};
struct LLNode * createNode(char val[])
{
struct LLNode *temp;
temp=(struct LLNode *)malloc(sizeof(struct LLNode));
strcpy(temp->id,val);
temp-> id[4] = val;
temp-> next = NULL;
return (temp);
};
char push(char val[], struct LLNode *head)
{
struct LLNode *temp;
temp = createNode(val);
temp->next = head->next;
head->next = temp;
};
char pop(struct LLNode *head)
{
struct LLNode *temp;
char val;
val = head->next->id;
temp = head->next;
head->next = head->next->next;
free(temp);
return(val);
};
int main()
{
char value;
struct LLNode *head = NULL;
struct LLNode *tail = NULL;
struct LLNode *curr;
head = createNode('\0');
tail = createNode('\0');
char id[6][4] = {"A123","B234","C345","D456","E567","F678"};
int n;
for (int i=0;i<6;i++)
{
push(id[i],&head->id);
printf("%s\n",&head->id);
}
};
char id[4];
char id[6][4] = {"A123","B234","C345","D456","E567","F678"};
A string is a nul-terminated sequence of non-nul elements including the terminator.
You are always forgetting that small but significant terminator.
And while that works fine when initializing an array with explicit length with a string-literal, as in you may drop the implicit terminator that way, remember that you thereafter don't have a string.
Anyway, your nodes arrays don't take advantage of that rule, and are also too short.
struct LLNode * createNode(char val[]);
head = createNode('\0');
A function that expects a string should not be fed a single character. Worse still, '\0' is a legitimate null-pointer-literal. Even though that's not what you wanted.
temp-> id[4] = val;
Assigning a pointer to past-the-end of a character array is beyond the pale. Are you requesting warnings from the compiler, and adherence to a specific standard? For gcc / clang, I suggest at least -Wextra -std=c99 -pedantic.

why the Push() function in my Linked List implementation shows this behaviour?

I wrote a Push() function to push an element inside a linked list.
Below is the code, I wrote first :
struct node {
int data;
struct node *next;
};
void Push(struct node*, int);
int main(int argc, char** argv) {
struct node *list = NULL;
Push(list, 23);
return 0;
}
void Push(struct node *list, int data) {
struct node *newNode;
newNode = (struct node*)malloc(sizeof(struct node));
newNode->data = data;
newNode->next = list;
list = newNode;
}
The code compiles well and executes as well but then no matter how many numbers I push on the List, the changes doesn't reflect and the list remains empty.
Then I created the function the other way and used double pointer like this:
struct node {
int data;
struct node *next;
};
void Push(struct node**, int);
int main(int argc, char** argv) {
struct node *list = NULL;
Push(&list, 23);
return 0;
}
void Push(struct node **list, int data) {
struct node *newNode;
newNode = (struct node*)malloc(sizeof(struct node));
newNode->data = data;
newNode->next = *list;
*list = newNode;
}
Here the code worked well and pushed the element on the list and the change reflected as well.
so, Why does it show such a different behaviour, even though I did a small test and found that both
*list
and
list
contains the same address. Here is what I did for the test:
struct node {
int data;
struct node *next;
};
void CheckAddress1(struct node *list) {
printf("Address1 is: %p\n", list);
}
void CheckAddress2(struct node **list) {
printf("Address3 is: %p\n", *list);
}
int main(int argc, char** argv) {
struct node *list = NULL;
CheckAddress1(list);
CheckAddress2(&list);
return 0;
}
and the output was
Address1 is: (nil)
Address3 is: (nil)
This is because both are pointing towards same location.
So it means both should work. Then why the different working.Can you guys elaborate? Thanks
list in main() has the address of the first element of the list. *list gives the content in the memory location pointed to by list.
In your first program, you are passing list to Push() by value. That means the list in Push() is merely a copy of list in main() and any modifications made to list of Push() is not reflected back to the one in main().
In the second program, you are passing a pointer to list in main() as argument to Push() and in Push() you manipulate the value at the memory location pointed to by this pointer so that you are effectively modifying the list in main().
Hence the changes you make in Push() are reflected back to main() for program 2 but not for program 1.

can't use a function with a 'pointer to pointer' input in another function. In C language

this code supposed to print : 'tree two one'
but it doesn't work. (the new_nod isn't added to the front of mylist)
anybody knows why? (actually in this code i wanted to use a function with a pointer to pointer input in another function but it didn't work(no changes applied to the mylist).
but it works when i'm using add_front function straightly in main.
#include <stdio.h>
#include <stdlib.h>
struct node{
char *word;
struct node *next;
};
struct node* create_node(char *str){
struct node *s;
s = (struct node *)malloc(sizeof(struct node));
if(s==NULL){
printf("couldn't malloc :(\n");
exit(-1);
}
s->word = str;
s->next = NULL;
return s;
}
void print_node(struct node *list){
struct node *current;
for(current = list; current !=NULL; current = current->next)
printf("%s ", current->word);
}
void add_front(struct node **list, struct node *new_node){
new_node->next= *list;
*list = new_node;}
void func(struct node*list, struct node*new_node){
add_front(&list, new_node);
}
int main()
{
struct node* mylist = create_node("one");
mylist->next = create_node("two");
struct node *new_node = create_node("tree");
func(mylist, new_node);
print_node(mylist);
}
Your add_front accepts a pointer to a pointer and other than missing a check for NULL is pretty much okay. But let's take a look at this:
void func(struct node*list, struct node*new_node){
add_front(&list, new_node);
}
What is add_front modifying here? The local pointer list. Which is just a copy of mylist in main.
So you haven't changed what mylist is pointing to.

why do we use pointer to a pointer

#include <stdio.h>
#include <stdlib.h>
struct llnode {
int data;
struct llnode *next;
};
void insert (struct llnode **head, int data);
int
main () {
struct llnode *head;
head = NULL;
printf("starting\n");
insert(&head, 4);
return 0;
}
void
insert (**struct llnode **head**, int data) {--> why do we use a pointer to a pointer
printf("insert %0d\n", data);
struct llnode *l = malloc(sizeof(struct llnode));
l->data = data;
l->next = NULL;
if (*head == NULL) {
*head = l;
} else {
struct llnode *tmp = *head;
while (tmp->next != NULL) {
tmp = tmp->next;
}
tmp->next = l;
}
}
1)Why do we use a pointer to pointer. Can it be explained with an example.
2)How to do insertion into a doubly linked list?
HElp me and please explain how to print
Often a pointer to pointer is used when you want to pass to a function a pointer that the function can change.
Pointer to pointer or double pointer are variables whose possible values ​​are memory addresses of other pointer variables.
You have a good answer here, I think he can explain it better than me.
Also you can check this link.

Double linked list; newbie attempt

I've just started out learning C, and (seemingly) so far most stuff is clicking. However, I'm having some trouble tracking down an issue with an attempt at a double linked list. I keep getting a seg-fault when I attempt to build/run this code. I'm compiling with the Cygwin supplied gcc via NetBeans.
I hate to just dump a block of code and say "help", but I don't know what other details are pertinent at this time, so feel free to ask for details if necessary:
#include <stdio.h>
#include <stdlib.h>
struct node_t{
struct node_t *prev;
struct node_t *next;
};
struct list_t{
struct node_t *head;
struct node_t *tail;
int length;
};
struct node_t *new_node(void);
struct list_t *new_list(void);
int append_list_node(struct list_t *list, struct node_t *node);
int main(void) {
int i = 0, length = 0;
struct node_t *node;
struct list_t *list = new_list();
for(i = 0; i < 10; i++){
length = append_list_node(list, new_node());
printf("%d", length);
}
return 0;
}
struct node_t *new_node(void){
struct node_t *node = malloc(sizeof(struct node_t));
return node;
}
struct list_t *new_list(void){
struct list_t *list = malloc(sizeof(struct list_t));
list->length = 0;
return list;
}
int append_list_node(struct list_t *list, struct node_t *new_node){
if(list->head == NULL){
list->head = new_node; // edited
new_node->prev = NULL;
}else{
list->tail->next = new_node;
new_node->prev = list->tail;
}
return (++list->length);
}
Thanks for the super quick responses everyone, all the answers are correct. As I was briefly looking over the code between F5-ing, I realized I wasn't setting the tail, so I resolved to change the line marked edited as follows:
list->head = list->tail = new_node;
I'll also resolve to use calloc() however, I've read that frequent use of it can cause considerable costs to execution time since it's clearing and allocating. Thoughts?
Use calloc() to allocate memory. The malloc() function does not initialize the memory to zeros (so the pointers will be set to NULL). You are making the assumption that the pointers are NULL by default.
C doesn't do any initialization for you. So when you do:
struct list_t *new_list(void){
struct list_t *list = malloc(sizeof(struct list_t));
list->length = 0;
return list;
}
list->head can be anything.. and probably won't be NULL.
One issue is that you never set list->tail to anything, and then attempt to access list->tail->next if list->head isn't NULL (which, as other have pointed out, isn't guaranteed anyway.)

Resources