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 usefscanf()
, but usefgets()
to read a full line andsscanf()
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;
}