简体   繁体   中英

Linked list shows segmentation fault error

I'm pretty new to C and pointers.

Following codes are for implementing a linked list in which each node contains a data of record.

However, when I compile and run this program, it shows an error "segmentation fault", and I guess the following part from my code makes an error.
head->next = NULL in functions in list.c
I doubt the segmentation fault error happens due to dereferencing a null pointer but have no idea what's wrong with my code.

list.h

#ifndef LIST_H
#define LIST_H
#include <stddef.h>
#include "record.h"

typedef struct node node;

struct node {         
  record  data;           
  node   *next;             
};

typedef node *record_list;  /* a record list is represented by its "head"
                               pointer */

void list_init(record_list *plist);

int list_insert(record_list *plist, const record *prec);

void list_clear(record_list *plist);

void list_print(const record_list *plist);
#endif

io.h

#ifndef IO_H
#define IO_H
#include "record.h"

void print_record(const record *p);

int read_record(record *p);

/* reads a string from stdin */
int get_word(const char prompt[], char word[]);

/* reads an int from stdin */
int get_int(const char prompt[], int *p);
#endif

record.h

#ifndef RECORD_H
#define RECORD_H

#define IDSIZE    10
#define NAMESIZE  20

typedef struct {          
  char   last[NAMESIZE];   
  char   first[NAMESIZE];  
} name;

typedef struct {   
  char  id[IDSIZE]; 
  name  name;      
  int   score;  
} record;
#endif

list.c

#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "record.h"
#include "list.h"
#include "io.h"

/* initializes a record list (specified via plist) to an empty list */
void list_init(record_list *plist) {
  node *head;
  head = *plist;
  head = NULL;
  head->next = NULL;
  printf("%s", "segmentation???\n");
}

/*
 * inserts a record (specified via prec) into a record list
 */
int list_insert(record_list *plist, const record *prec) {
  node *current, *temp;
  printf("%s", "list insert\n");
  current = *plist;
  while (current->next != NULL) {
    current = current->next;
  }
  temp = (node *)malloc(sizeof(node));
  if (temp == NULL) {
    fprintf(stderr, "memory allocate failed");
    return 0;
  }
  current->next = temp;
  current->next->data = *prec;
  current->next->next = NULL;

  printf("%s", "list insert done\n");
  return 1;
}

/*
 * deallocates all dynamic memory associated with a record list (specified
 * via plist) & resets the record list to an empty list
 */
void list_clear(record_list *plist) {
  printf("%s", "list clear\n");
  free((*plist)->next);
  plist = NULL;
  (*plist)->next = NULL;
}

/* prints all records in a record list (specified via plist) */
void list_print(const record_list *plist) {
  node *current;
  current = *plist;
  printf("%s", "list print\n");
  while (current->next != NULL) {
    print_record(&(current->data));
    current = current->next;
  }
}

io.c

#include <stdio.h>
#include <string.h>
#include "record.h"
#include "io.h"
#define LINESIZE 1024

/*
 * prints a record (specified via p);
 */
void print_record(const record *p) {
  printf("%d %s %s %s\n", p->score, p->name.last, p->name.first, p->id);
}

/*
 * reads a record from stadard input & stores it via p;
 */
int read_record(record *p) {
  return (
        get_word("Enter id: ", p->id)
    &&  get_word("Enter last name: ", p->name.last)
    &&  get_word("Enter first name: ", p->name.first)
    &&  get_int("Enter score: ", &(p->score))
  );
}

/* reads a string from stdin */
int get_word(const char prompt[], char word[]){
  char line[LINESIZE];
  char temp[LINESIZE];
  while (1) {
    printf("%s", prompt);
    if(!fgets(line, LINESIZE, stdin)){
      clearerr(stdin);
      return 0;
    }
    if (sscanf(line, "%s", temp) == 1){
      strcpy(word, temp);
      return 1;
    }
  }
}

/* reads an int from stdin */
int get_int(const char prompt[], int *p) {
  char line[LINESIZE];
  while (1) {
    printf("%s", prompt);
    if (!fgets(line, LINESIZE, stdin)) {
      clearerr(stdin);
      return 0;
    }
    if (sscanf(line, "%d", p) == 1) {
      return 1;
    } else {
      printf("%s", "Error: The input is not given in integer.\n");
    }
  }
}

main.c

#include <stdio.h>
#include "record.h"
#include "list.h"
#include "io.h"


int main(void) {
  record_list  list;
  record       r;

  printf("address of list: %ld\n", &list);
  printf("address of list: %ld\n", &(list->next));
  list_init(&list);

  while (read_record(&r)) {
    printf("%s\n", "read success");
    if (!list_insert(&list, &r))
      break;
  }

  list_print(&list);
  return 0;
}

If your goal is to create an empty list and plist is the pointer to the head of the list you have to set the variable pointed by plist to NULL with *plist = NULL; , you can get rid of the code is causing the segmentation fault

Ok I think I find the next error:

current = *plist;
while (current->next != NULL) {
    current = current->next;
}

Will cause errors because the first time you call list_insert you have *plist equals to NULL because the list is empty and so current->next != NULL will cause the error (current is also equals to NULL)

I suggest the following:

printf("%s", "list insert\n");

if (*plist == NULL) {
    temp = (node * )malloc(sizeof(node));
    if (temp == NULL) {
        fprintf(stderr, "memory allocate failed");
        return 0;
    }
    plist = temp;
    (*plist) ->data = *prec;
    (*plist) ->next = NULL;
    return 1;
}

current = *plist;
while (current->next != NULL) {
    current = current->next;
}

And the rest of the code as it was, I added an if for the case *pilist is equals to NULL, in that case temp is going to point at the first element and has to be assigned to plist

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM