get segmentation fault error when use strcpy function - c

I am implementing the doubly linked list, in functions create_head_node, insert_head, insert_tail i have to copy the array name to node. Then I use function strcpy to copy it but I got segmentation fault error. I reimplement function strcpy by cpystr then I got segmentation fault error at dest[i]=source[i];. Can anybody explain to me why it is wrong and how to fix it. thanks for yor help.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct linked_list
{
char name[30];
float point;
struct linked_list *p_node;
struct linked_list *n_node;
}node;
node *create_head_node(node *,char *, float);
node *insert_head(node *, char*, float);
void insert_tail(node *, char*, float);
node *insert_after(node *, char*, float, int);
int count_node(node *);
void print_list(node *);
void cpystr(char*, char*);
int main(){
node *head=(node*)malloc(sizeof(node));
head=create_head_node(head, "asd fgh", 10);
head=insert_head(head, "abc def", 9.8);
insert_tail(head, "qwe rty", 8.98);
head=insert_after(head, "ui op", 8.7568, 1);
print_list(head);
free(head);
return 0;
}
node *create_head_node(node *head, char name[30], float point){
cpystr(head->name, name);
head->point=point;
head->p_node=NULL;
head->n_node=NULL;
return head;
}
node *insert_head(node *head, char name[30], float point){
node *temp=(node*)malloc(sizeof(node));
cpystr(temp->name, name);
temp->point=point;
temp->p_node=NULL;
temp->n_node=head;
head->p_node=temp;
head=temp;
return head;
}
void insert_tail(node *head, char name[30], float point){
node *p=head;
node *temp=(node*)malloc(sizeof(node));
cpystr(temp->name, name);
temp->point=point;
temp->n_node=NULL;
while (p!=NULL)
{
p=p->n_node;
}
p->n_node=temp;
temp->p_node=p;
}
node *insert_after(node *head, char name[30], float point, int index){
int count=count_node(head);
while (index>count)
{
printf("choose %d positions to add. choose again: ", count); scanf("%d", index);
}
if(index==0) head=insert_head(head, name, point);
else if(index==count) insert_tail(head, name, point);
else{
node *p=head;
for (int i = 0; i < index-1; i++)
{
p=p->n_node;
}
node *temp=(node*)malloc(sizeof(node));
temp->n_node=p->n_node;
p->n_node->p_node=temp;
p->n_node=temp;
temp->p_node=p;
}
return head;
}
int count_node(node *head){
node *p=head;
int count=0;
while (p!=NULL)
{
count++;
p=p->n_node;
}
free(p);
return count;
}
void print_list(node *head){
node *p=head;
while (p!=NULL)
{
printf("%s%10f", p->name, p->point);
p=p->n_node;
}
}
void cpystr(char* dest, char* source){
int i=0;
while (source[i]!='\0')
{
dest[i]=source[i];
i++;
}
*dest='\0';
}

Let's think about how pointers work in general. Pointers are variables whose value contain address of another variable. Thus, pointer must be initialized aka "assigned address of variable it should point to", before you can work with them. Now, when you do node* head. head has not been initialized yet, you must allocate memory for head and associate it's address with head, like this:
node *head = (node*)malloc( sizeof(node) );
Now you can access members of head like this:
head->point = 0.01;
Similarly, strcpy will work like this:
const char *dummy = "Sample";
strcpy(head->name , dummy);
Please note that strcpy doesn't check for destination's size. Thus, if destination pointer is not large enough to receive the "copy", Undefined behavior may happen and often but not always result in Segmentation fault.

regarding:
node *temp=(node*)malloc(sizeof(node));
cpystr(temp->name, name);
and
node *create_head_node(node *head, char name[30], float point){
cpystr(head->name, name);
and similar statements:
best to check (via strlen( name ) that the length is <= 29.
Then use: strncpy( head->name, name, sizeof( node.name )); To assure the name field in the struct is not overrun

Related

What is wrong with my linked list, and why won't it properly set my head to NULL in C?

This is my program I have written in C, I created a structure and a head and I am trying to make a linked list, but I keep getting read access violations and it seems I am not passing in my head pointer properly and it keeps having problems when it is trying to add to my list.
#define _CRT_SECURE_NO_WARNINGS // Since I want to strictly use ANSI C and not Microsoft C without getting the warning message, I'm adding this line of code before I include header files.
#include <stdio.h> // "#include" includes the contents of another file, commonly called header file, into the source code file.
#include <string.h> // This library contains a variety of functions to manipulate strings.
#include <stdlib.h> // Header file which has the necessary information to include the input/output related functions in our program.
#define MAX 100
typedef struct node {
char model[MAX];
float price;
int miles;
struct node *next;
} *NODEPTR;
NODEPTR getNode();
void freeNode(NODEPTR p);
void printTotalMiles(NODEPTR);
void addLast(NODEPTR *list, char c[], float pri, int num);
int main(void) { //It is the first function of every C program that is responsible for starting the execution and termination of the program.
int i = 0;
NODEPTR head = NULL;
if (head == NULL) {
printf("NULL");
}
//head = (NODEPTR) malloc(sizeof(struct node));
//head->next = NULL;
//addFront(head, 2600.00, 48000);
//addFront(head, 1400.00, 22000);
//printf("first, %d", head->price);
addLast(head, "64 Impala", 1800.00, 12000);
addLast(head, "56 Ford", 500.00, 23000);
//printTotalMiles(head);
//printArray(p);
return 0; // This statement indicates "main()" is returning the value 0 upon completion.
} // Curly brace marks the end of the function.
NODEPTR getNode(void) {
NODEPTR p;
p = (NODEPTR)malloc(sizeof(struct node));
if (p == NULL) {
printf("List Overflow.");
}
return (p);
}
void freeNode(NODEPTR p) {
free(p);
}
void addFront(NODEPTR *list, float pri, int num) {
NODEPTR p, q;
p = getNode();
//strcpy(p->model, c);
// memset(p->model, '\0', sizeof(c))
//printf("%s\n", p->model);
p->price = pri;
p->miles = num;
p->next = *list;
*list = p;
q = *list;
printf("hey %.2f hey\n", q->price);
}
void printTotalMiles(NODEPTR *list) {
int total = 0;
NODEPTR p;
while (*list) {
p = *list;
printf(" Car: \tPrice: %.2f\tI drove it: %d\n", p->price, p->miles);
total += p->miles;
list = p->next;
}
printf("The Total Miles: %d", total);
}
void addLast(NODEPTR *list, char c[], float pri, int num) {
NODEPTR p, q;
p = getNode();
memset(p->model, '\0', sizeof(c));
strcpy(p->model, c);
p->price = pri;
p->miles = num;
p->next = NULL;
if (*list == NULL) {
*list = p;
} else {
q = *list;
while (q->next) {
q = q->next;
}
q->next = p;
}
}
//void printArray(struct node cars[]) { //function definition
// break;
//}
How can I get it so I can properly add nodes to this list?
I just want it to add nodes to the list with the character, float and int. I tried messing with the pointers, I tried setting head first and setting head->next to null as well but nothing seems to work. It keeps having errors every time it tries to deal with the null.
void addLast(NODEPTR* list, char c[], float pri, int num);
addLast wants a pointer to pointer (read Is it a good idea to typedef pointers?), but you pass a single pointer here:
addLast(head, "64 Impala", 1800.00, 12000);
addLast(head, "56 Ford", 500.00, 23000);
switch to
addLast(&head, "64 Impala", 1800.00, 12000);
addLast(&head, "56 Ford", 500.00, 23000);
And here:
void addLast(NODEPTR* list, char c[], float pri, int num) {
NODEPTR p, q;
p = getNode();
memset(p->model, '\0', sizeof(c));
strcpy(p->model, c);
sizeof(c) is the size of a pointer (read What is ‘array decaying’ in C?).
Use the size of the member, in this case MAX:
memset(p->model, '\0', MAX);
or better yet: delete the whole line, you don't need it if you call strcpy on the next line.
One more:
void printTotalMiles(NODEPTR* list) {
differs from the propotype:
void printTotalMiles(NODEPTR);
Compile with warnings.

Ask data from user and store them inside a struct in C

In the code below I tried to use printf and scanf to get data from user and store them inside a struct i defined called node.
The programme works fine for the first prompt, but as soon as the user input name, the programme ends with printing Age:salary:
Can anyone help me with this?
On a side note, can anyone also help me to understand how to create a loop to store data in various nodes and store them together? (Not hard-code it one by one)
Thank you very much!!
typedef struct node
{
char *name;
int age;
int salary;
struct node * next;
}node;
int main(void)
{
node *tmp = malloc(sizeof(node));
printf("Name:");
scanf("%s", tmp->name);
printf("Age:");
scanf("%i", &(tmp->age));
printf("salary:");
scanf("%i", &(tmp->salary));
tmp->next = NULL;
free(tmp);
}
Use a char[] for name,
for example:
#include <stdlib.h>
#include <stdio.h>
typedef struct node
{
char name[128];
int age;
int salary;
struct node * next;
}node;
int main(void)
{
node *tmp = malloc(sizeof(node));
printf("Name:");
scanf("%s", tmp->name);
printf("Age:");
scanf("%i", &(tmp->age));
printf("salary:");
scanf("%i", &(tmp->salary));
tmp->next = NULL;
free(tmp);
}
If you want to get several users, loop for ever and ask if the user wants to add more data.
I have create a function to print the list
Console:
Name:Foo
Age:12
salary:12
Continue Y/N
Y
Name:Bar
Age:14
salary:14
Continue Y/N
Y
Name:John
Age:30
salary:45
Continue Y/N
N
John, 30, 45
Bar, 14, 14
Foo, 12, 12
#include <stdlib.h>
#include <stdio.h>
typedef struct node
{
char name[128];
int age;
int salary;
struct node * next;
}node;
static void printList(node *n)
{
while (n) {
printf("%s, %d, %d\n", n->name, n->age, n->salary);
n = n->next;
}
}
static node *get_nodes(void) {
node *list = NULL;
while (42) {
char c;
node *tmp = malloc(sizeof(node));
printf("Name:");
scanf("%s", tmp->name);
printf("Age:");
scanf("%i", &(tmp->age));
printf("salary:");
scanf("%i", &(tmp->salary));
tmp->next = list;
list = tmp;
printf("Continue Y/N\n");
scanf(" %c", &c);
if (c == 'N')
break;
}
return list;
}
static void clearList(node *node) {
if (node->next) {
clearList(node->next);
}
free(node);
}
int main(void)
{
node *list = get_nodes();
printList(list);
clearList(list);
return 0;
}
You are trying to write to Uninitialized memory
This is a very common problem beginners face.
You are trying to store the name using char *name declaration.
Here name does not point to a valid memory location, that's why You program is not running as expected.
Even if name points to a valid memory address, you must have enough memory allocated to store the data.
You can use
#define BUFFER_SIZE 50
char name[BUFFER_SIZE];
You can use any buffer size as you like, and then store a string of that length - 1 in the name array. -1 is for the null termination character \0.
Using this declaration you are allocating memory of BUFFER_SIZE bytes and the name points to the first byte in that array.
This allocation happens on the stack not in the HEAP
For fix your bug, you should allocate memory of your char *.
First Way, when you create your struct.
typedef struct node
{
char name[200]; // You specify that your char * can save 200 char
int age;
int salary;
struct node * next;
}node;
or you can create init struct function
node *init_node()
{
node *test = null;
test->name = malloc(sizeof(char) * 200);
test->age = 0;
test->salary = 0;
test->node = null;
return test
}

Segmentation Fault (singal 11 sigsegv) with linked list

Was writing a program to practice before with linked lists and pointers before pset5 and am left with two memory errors that i have not been able to remedy.
#include <stdio.h>
#include <stdlib.h>
//define struct for Nodes
typedef struct list
{
int data;
int key;
struct list* next;
}Node;
//function declarations
Node* create(int a, int *counter);
void insert(int a, int *counter);
void delete_list();
void printlist();
//global pointers
Node* Head = NULL;
Node* Current = NULL;
int main()
{
int *keycounter =(int*)malloc(sizeof(int));
int value = 20;
keycounter = 0;
Head=create(value, keycounter);
value = 30;
insert(value, keycounter);
value = 40;
insert(value, keycounter);
printlist();
delete_list();
free(keycounter);
return 0;
}
// VV functions VV
void delete_list()
{
free(Head);
free(Current);
}
Node* create(int a, int *counter)
{
Node* ptr=malloc(sizeof(Node));
if(!ptr)
{
printf("ERROR-NOT ENOUGH MEMORY\n");
free(ptr);
return 0;
}
ptr->data=a;
ptr->key=*counter;
counter++;
return ptr;
}
void insert(int a, int *counter)
{
Node* ptr=malloc(sizeof(Node));
if(!ptr) {
printf("ERROR-NOT ENOUGH MEMORY\n");
free(ptr);
}
ptr->data=a;
ptr->key=*counter;
//point next field to old head
ptr->next=Head;
//assign current node as head of singly linked list
Head=ptr;
counter++;
}
//Thank you guys over at tutorialspoint for this neat idea for testing this.
//https://www.tutorialspoint.com/data_structures_algorithms/linked_list_program_in_c.htm
void printlist()
{
Node* ptr=Head;
printf("TESTING\n");
while(ptr != NULL) {
printf("%p*NODE* KEY:%i VALUE:%i PTR NEXT:%p\n \n", ptr, ptr->key, ptr->data, ptr->next);
ptr=ptr->next;
}
}
Here is my valgrind output:
Still learning so alot of the valgrind output is pretty arcane to me and threads on stack exchange regarding the "signal 11 (SIGSEGV)" error are difficult to comprehend as well.
Also, any tips or advice on my code would be appreciated.
There is a problem in your code. See the below lines:
int main()
{
int *keycounter =(int*)malloc(sizeof(int));
int value = 20;
keycounter = 0; ===> You are setting the pointer to NULL effectively nullifying the effect of your malloc call above
So, in your create function, when you try to access counter, it is leading to NULL pointer dereference
Node* create(int a, int *counter)
{
Node* ptr=malloc(sizeof(Node));
if(!ptr)
{
printf("ERROR-NOT ENOUGH MEMORY\n");
free(ptr);
return 0;
}
ptr->data=a;
ptr->key=*counter; ==> Here it will lead to NULL pointer dereference
If your key member in the struct is just an integer, then no need to pass a pointer (counter is a pointer), you can as well pass an integer and set it.

Transfer char arrays into linked list

I have been hesitant to post a question about this because I'm worried about asking a stupid question, but here it goes:
I am currently trying to create a program that will take whole strings, put them into char arrays and transfer those char arrays to a linked list. I have everything working up to the point of actually putting the arrays into the linked list.
I initially tried to just create each node with the array itself, which was just giving me the first element of the array. Then I found that I need to use strcpy().
I'm not sure what is wrong at this point, but I think it's down to memory allocation because it's giving me a segfault. That is confusing however, because the memory allocation for rach node is already taken care of.
Thank you for any help, this part has been driving me crazy for a few hours now.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 100
struct node {
char info;
struct node *link;
} *start;
void create(char[]);
void display();
void insert_end(char[]);
int main() {
int i;
start=NULL;
char data[SIZE];
printf("Please enter a word: ");
fgets(data, SIZE, stdin);
create(data);
for(i=0; i<5; i++)
{
printf("Please enter a word: ");
fgets(data, SIZE, stdin);
insert_end(data);
}
display();
return 0;
}
void create(char data[])
{
struct node *temp;
temp = (struct node *)malloc(sizeof(struct node));
if (start == NULL)
{
strcpy(temp->info,data);
temp->link=NULL;
start=temp;
}
}
void display()
{
struct node *ptr;
ptr = start;
while (ptr!=NULL)
{
printf("%c", ptr->info);
ptr=ptr->link;
}
}
void insert_end(char data[])
{
struct node *ptr, *tempnode;
ptr = start;
while(1)
{
if(ptr->link != NULL)
{
ptr=ptr->link;
}
else
break;
}
tempnode=(struct node *)malloc(sizeof(struct node));
strcpy(tempnode->info,data);
tempnode->link=NULL;
ptr->link=tempnode;
}
As you stated you are using arrays, space needs to be reserved in the info member of the linked list structure. char type will only hold one character.
struct node {
char info[SIZE];
struct node *link;
} *start;
If info is an array, printf requires %s format modifier.
printf("%s\n", ptr->info);
info is a char not a char *.
Compile with -W -Wall, you'll see most of your mistakes.

pointers and values

I have written the following code, and it prints the root value correctly, but not the ret value. Here a memory address is potentially printed (1707388). I believe that ret could now be modified and the result would be seen in main. Any help is appreciated.
#include <stdlib.h>
struct node{
int value;
int order;
struct node *left;
struct node *right;
};
typedef struct node node_t;
node_t array[10];
void createTree(node_t *p, int order){
p->value = rand()%10;
p->order = order;
printf("%i", p->value);
printf(" ");
printf("%i\n", p->order);
if (!order){
p->left = NULL;
p->right = NULL;
return;
}
order--;
createTree(&p->left, order);
createTree(&p->right, order);
}
void traverse(node_t *current, node_t *ret, int size){
printf("%i\n", current->value);
if (current->value > size){
ret = current;
traverse(&current->left, &ret, size);
traverse(&current->right, &ret, size);
}
return;
}
int main(void){
node_t *root = &array[0];
node_t *ret;
srand(time(NULL));
createTree(root, 4);
int i = 3;
printf("%s", "root-value: ");
printf("%i\n", root->value);
traverse(root, ret, i);
printf("%s", "root-value: ");
printf("%i\n", root->value);
printf("%i\n", ret->value);
return 1;
}
This:
void createTree(node_t *p, int order)
Should be
void createTree(node_t **p, int order)
Otherwise you are modifying a local node_t pointer, instead of the one outside the function. Your tree isn't being built properly either.
You are passing ret by value to
void traverse(node_t *current, node_t *ret, int size){
When the function changes ret, the changes do not propagate back to the caller.
This means that ret in main() remains uninitialized, and the behaviour of your code is undefined.
To fix this, make traverse either return ret, or take it as node_t**.
There are few issues with the code.
First, you don't correctly allocate the memory for nodes. In your code, you are passing wrong pointer type, futhermore, pointer to uninitialized area.
Here, how it can be used differently:
node_t *createTree(int order)
{
node_t *result = malloc(sizeof(*result));
result->value = rand() % 10;
result->order = order;
if (order)
{
result->left = createTree(order - 1);
result->right = createTree(order - 1);
}
else
{
result->left = result->right = 0;
}
return result;
}
Then, your traverse function need some block to restrict agains failed search:
node_t *traverse(node_t *current, int size)
{
node_t *ret = NULL;
if (current->value > size)
{
// assuming current node fit - stops the search
ret = current;
}
if (!ret && current->left)
{
// try left node
ret = traverse(current->left, size);
}
if (!ret && current->right)
{
// try right node
ret = traverse(current->right, size);
}
return ret;
}
In case you need (usually you do), here is a destroyTree:
void destroyTree(node_t *node)
{
if (!node) return; // we treat NULL as a valid pointer for simplicity
destroyTree(node->left);
destroyTree(node->right);
free(node);
}
And here is a usage example:
node_t *root, *found;
root = createTree(4);
found = traverse(root, 3);
if (found)
{
printf("Found!");
}
destroyTree(root);
In traverse(node_t *current, node_t *ret, int size), ret is a stack variable. In other words, you are passing the pointer by value, instead of passing it by reference.
What have you done at the moment is essentially the same as:
int f(int i) {
...
i = <any value>;
...
}
In this case you are modifying only a copy of the value.
In your program, you are also modifying a copy of the pointer. Outside of the function the pointer stays not modified.
If you want to modify it, you need to pass a pointer to it:
void traverse(node_t *current, node_t **ret, int size){
...
*ret = current;
...
return;
}
The same for createTree().

Resources