Home > Enterprise >  How can I solve this segmentation fault in linear search with C?
How can I solve this segmentation fault in linear search with C?

Time:10-06

I have to linear search with student list file.

This file is sorted by year. There are 10 years from 2009 to 2018. I have to receive the year, student name, and gender from the file. If the name is the same, I have to add frequency to freq[]. If it is a different name, you can add a student name structure at the end of the array. When I run gdb in Ubuntu, I can compile it, but I keep getting errors when I add frequency.

void load_names_lsearch(FILE *fp, int start_year, tNames *names) {
    int year = 0;
    int i, a;
    int num = 0;
    tName buff;
    int count = 0;
    int year_duration = 0;
    int rs;
    fscanf(fp, "%d %s %c %d %*c", &year, buff.name, &(buff.sex), &count);

    while (year == start_year) {
        memset((names->data[names->len]).freq, 0 , sizeof(int) * MAX_YEAR_DURATION);
        strcpy((names->data[names->len]).name, buff.name);
        (names->data[names->len]).sex = buff.sex;
        (names->data[names->len]).freq[year_duration] = 1;
        (names->len)  = 1;
        fscanf(fp, "%d %s %c %d %*c", &year, buff.name, &(buff.sex), &count);
    }
    start_year  = 1;
    year_duration  = 1;
    while (1) {
        for (i = 0; i < (names->len)-num; i  ) //names->len - num
        {
            if( strcmp((names->data[i]).name,buff.name) == 0 && (names->data[i]).sex == buff.sex) {
                (names->data[i]).freq[year_duration]  = 1;
                break;
            }
        }
        if (i == (names->len)-num) //names->len - num
        {
            memset((names->data[names->len]).freq, 0 , sizeof(int)*MAX_YEAR_DURATION);
            strcpy((names->data[names->len]).name, buff.name);
            (names->data[names->len]).sex= buff.sex;
            (names->data[names->len]).freq[year_duration] = 1;
            (names->len)  = 1;
            num  = 1;
        }
        
        if ((names->len) % 1000 == 0) {
            names->capacity  = 1000;
            names->data = (tName *)realloc(names->data, (names->capacity) * sizeof(tName));
        }
        
        rs = fscanf(fp, "%d %s %c %d %*c", &year, buff.name, &(buff.sex), &count);
        if (rs == EOF) break;
        
        if (year != start_year) {
            start_year  = 1;
            year_duration  = 1;
            num = 0;
        }
    }
}
(names->data[i]).freq[year_duration]  = 1;

In particular, this part produces a segmentation fault. If I annotated this line, there is no segmentation fault, but the execution does not stop. Structure is here.

typedef struct {
    char    name[20];
    char    sex;
    int     freq[MAX_YEAR_DURATION];
} tName;

typedef struct {
    int     len;    
    int     capacity;
    tName   *data;
} tNames;

Please help me

CodePudding user response:

There are multiple problems in your function:

  • you do not test the return value of fscanf(). Conversion failure will go undetected and you may even have an infinite loop when skipping initial records.

  • you should check for realloc failure to reallocate the array.

  • reading buff.name with " %s" is risky: you should specify the maximum number of characters to store into the destination array with " s" but be aware that this conversion does not allow for multiple names.

  • the last conversion " %*c" is bizarre: do you intend to skip the newline this way? It will not work because the space will have consumed it already and you will instead consume the first character of the next line. You should not use fscanf(), but use fgets() to read a full line and sscanf() to parse it.

  • it is unclear what is the purpose of the count variable.

  • does freq mean frequentation or frequency?

Here is a simplified version:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_YEAR_DURATION 10

typedef struct {
    char name[20];
    char sex;
    int freq[MAX_YEAR_DURATION];
} tName;

typedef struct {
    int len;
    int capacity;
    tName *data;
} tNames;

int load_names_lsearch(FILE *fp, int start_year, tNames *names) {
    char buf[200];
    tName buff;
    int num = 0;    /* number of records added */
    int year, i, count, year_duration;

    while (fgets(buf, sizeof buf, fp)) {
        if (fscanf(fp, "%d s %c %d", &year, buff.name, &buff.sex, &count) != 4) {
            fprintf(stderr, "invalid record: %s", buf);
            continue;
        }
        if (year < start_year || year >= start_year   MAX_YEAR_DURATION) {
            /* ignore record */
            continue;
        }
        year_duration = year - start_year;

        /* try and locate same student and update freq */
        for (i = 0; i < names->len; i  ) {
            if (strcmp(names->data[i].name, buff.name) == 0 && names->data[i].sex == buff.sex) {
                names->data[i].freq[year_duration]  = 1;
                break;
            }
        }

        if (i == names->len) {
            /* student was not found: add new record */
            /* check for available space */
            if (names->len >= names->capacity) {
                int new_capacity = names->len   1000;
                tName *new_data = realloc(names->data, new_capacity * sizeof(*names->data));
                if (new_data == NULL) {
                    fprintf(stderr, "cannot reallocate data for %d capacity\n", new_capacity);
                    return -1;
                }
                names->capacity = new_capacity;
                names->data = new_data;
            }
            /* append new record */
            memset(buff.freq, 0, sizeof buff.freq);
            buff.freq[year_duration] = 1;
            names->data[names->len  ] = buff;
            num  ;
        }
    }
    return num;
}
  • Related