0

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';
}
Becker
  • 147
  • 7
  • 1
    `node *head; head=create_head_node(head, "viet anh", 10);` The `head` variable is uninitialised but it is dereferenced inside `create_head_node`. That is undefined behaviour and often (but not always) results in seg faults. – kaylum Jan 01 '20 at 05:43
  • where does the `head` be dereferenced inside `create_head_node`. – Becker Jan 01 '20 at 05:51
  • and why debugger says seg faults in cpystr function? @kaylum – Becker Jan 01 '20 at 05:52
  • 1
    `head->name`, `head->point`, `head->p_node`, `head->n_node`. Anything with `head->` is a dereference of that pointer. – kaylum Jan 01 '20 at 05:52
  • 1
    As soon as undefined behaviour is triggered we can't have any expectation of what the behaviour will be. So a seg fault (or any other behaviour) may happen at any point from where the undefined behaviour first occurs. – kaylum Jan 01 '20 at 05:55
  • I have just allocated memory to `head`, see my reedit. then it print out some thing wrong. can you please show me where I am wrong? – Becker Jan 01 '20 at 06:03
  • We can't debug everything for you. Please run your program in a debugger and trace the execution of your program. At least try that first rather than immediately posting on Stackoverflow. This may also be helpful: [How to debug small programs](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). It is much better for you to learn to debug yourself. If you still have problems after actually trying to debug then please post a new question with all the details. – kaylum Jan 01 '20 at 06:07
  • regarding: `head=insert_head(head, "abc def", 9.8);` The literal `9.8` is a `double`, but the function: `insert_head()` is expecting a `float`. Suggest using: `head=insert_head(head, "abc def", 9.8f);` Note the trailing `f` on the literal, which says it is a `float` – user3629249 Jan 02 '20 at 04:51
  • OT: regarding: `printf("choose %d positions to add. choose again: ", count); scanf("%d", index);` 1) please follow the axiom: *only one statement per line and (at most) one variable declaration per statement.* 2) the second parameter is expected to be a `int*` but is actually an `int`. This (probably) will result in a seg fault event when executed. 3) when compiling, always enable the warnings, then fix those warnings. ( for `gcc`, at a minimum use: `-Wall -Wextra -Wconversion -pedantic -std=gnu11` ) Note: other compilers use different options to produce the same things – user3629249 Jan 02 '20 at 04:56
  • OT: regarding: `scanf("%d", index);` always check the returned value (not the parameter values) to assure the operation was successful. Note: the `scanf()` family of functions returns the number of `successful input format conversions (or EOF)` Suggest: `if( scanf("%d", index) != 1 ) { // handle error }` – user3629249 Jan 02 '20 at 05:00
  • OT: regarding: `node *temp=(node*)malloc(sizeof(node));` 1) in C, the returned type is `void*` which can be assigned to any pointer. Casting just clutters the code. Suggest removing the cast. 2) always check (!=NULL) the returned value to assure the operation was successful. If not successful, call `perror( "malloc failed" );` to output both your error message and the text reason the system thinks the error occurred to `stderr`, then call `exit( EXIT_FAILURE );` – user3629249 Jan 02 '20 at 05:03

2 Answers2

1

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.

H S
  • 1,211
  • 6
  • 11
0

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

user3629249
  • 16,402
  • 1
  • 16
  • 17