Reputation: 5
I am trying to access and read my file using fread() in a menu-driven program. I have no idea which part of the code that causes segmentation fault. All I got from invoking a reading function are segmentation fault (core dumped) and literally exiting the interface.
The source code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 100
struct student {
char registration[MAX_SIZE], location[MAX_SIZE], faculty[MAX_SIZE];
int yearOfBirth, monthOfBirth, dayOfBirth, layerArch1, layerArch2, levelOfStudy, graduatingYear;
};
int writeInfo(FILE **resident, FILE **transient, const char *file1, const char *file2, struct student *res, struct student *tra);
int readTransient(FILE **transient, const char *file2, struct student *tra);
int display(FILE **resident, const char *file1, struct student *res);
/**************************************************************/
int main (int argc, char **argv) {
char file1[MAX_SIZE], file2[MAX_SIZE];
FILE *resident = (FILE*) malloc(sizeof(FILE));
FILE *transient = (FILE*) malloc(sizeof(FILE));
struct student *res = (struct student *) malloc(sizeof(struct student));
struct student *tra = (struct student *) malloc(sizeof(struct student));
int choice = 0;
while (choice >= 0 && choice <= 3) {
printf("\n\tPlease enter the following choice\n\n");
printf("*****************************************************\n");
printf("\t\t1: Add Information\n");
printf("\t\t2: Read Information\n");
printf("\t\t3: Display Information\n");
printf("\t\t0: Exit\n");
printf("*****************************************************\n");
printf("\nEnter a number: ");
scanf("%d", &choice);
switch (choice) {
case 0:
exit(1);
case 1:
printf("\nEnter name of the first file\n");
scanf("%s", file1);
printf("\nEnter name of the second file\n");
scanf("%s", file2);
writeInfo(&resident, &transient, file1, file2, res, tra);
break;
case 2:
printf("\nEnter name of the file\n");
scanf("%s", file2);
readTransient(&transient, file2, tra);
break;
case 3:
printf("\nEnter name of the file\n");
scanf("%s", file1);
display(&resident, file1, res);
break;
default:
printf("Wrong choice. Enter again!\n\n");
break;
}
}
return 0;
}
int writeInfo(FILE **resident, FILE **transient, const char *file1, const char *file2, struct student *res, struct student *tra) {
*resident = fopen(file1, "w");
*transient = fopen(file2, "w");
if (*resident == NULL) {
fprintf(stderr, "\nError open file\n");
exit(1);
}
if (*transient == NULL) {
fprintf(stderr, "\nError open file\n");
exit(1);
}
printf("Enter a registration number [7 digits]: ");
scanf("%s", res->registration);
printf("Enter location (location in currency, AUS CND SIN): ");
scanf("%s", res->location);
strcpy(tra->location, res->location);
printf("Enter faculty (ENG BUS SCI MED): ");
scanf("%s", res->faculty);
strcpy(tra->faculty, res->faculty);
printf("Enter birth of year (19XX 200X): ");
scanf("%d", &res->yearOfBirth);
printf("Enter birth of month (XX): ");
scanf("%d", &res->monthOfBirth);
tra->monthOfBirth = res->monthOfBirth;
printf("Enter birth of date (XX): ");
scanf("%d", &res->dayOfBirth);
tra->dayOfBirth = res->dayOfBirth;
printf("Enter level of study (1 -first, 2- second, 3- third, 4-fourth, 5 - other): ");
scanf("%d", &res->levelOfStudy);
tra->levelOfStudy = res->levelOfStudy;
printf("Enter graduating year (XXXX): ");
scanf("%d",&res->graduatingYear);
tra->graduatingYear = res->graduatingYear;
printf("Enter layer of Architecture 1 (0-sensing, 1-network, 2-smart(hidden), 3-devices): ");
scanf("%d",&res->layerArch1);
printf("Enter layer of Architecture 2 (0-sensing, 1-network, 2-smart(hidden), 3-devices): ");
scanf("%d", &res->layerArch2);
tra->layerArch2 = res->layerArch2;
//write entire sturcture to Student file
fwrite(&res, sizeof(struct student), 1, *resident);
fwrite(&tra, sizeof(struct student), 1, *transient);
fclose(*resident);
fclose(*transient);
}
int display(FILE **resident, const char *file1, struct student *res) {
*resident = fopen(file1, "r");
if (*resident == NULL) {
fprintf(stderr, "\nError opening file!\n\n");
exit(1);
}
while(fread(&res, sizeof(struct student), 1, *resident) != EOF) {
printf("%d%s%d%d%d%d%d%s%d%s%d%d\n\n", res->yearOfBirth, res->registration, res->monthOfBirth, res->dayOfBirth, res->layerArch1, res->layerArch2, res->levelOfStudy, res->location, res->graduatingYear, res->faculty, res->dayOfBirth, res->monthOfBirth);
}
fclose(*resident);
}
int readTransient(FILE **transient, const char *file2, struct student *tra) {
*transient = fopen(file2, "r");
if (*transient == NULL) {
fprintf(stderr, "\nError opening file!\n\n");
exit(1);
}
while(fread(&tra, sizeof(struct student), 1, *transient) != EOF) {
printf("%d%d%s%d%s%d%d\n\n", tra->layerArch2, tra->levelOfStudy, tra->location, tra->graduatingYear, tra->faculty, tra->dayOfBirth, tra->monthOfBirth);
}
fclose(*transient);
}
You could try the above program, though it only works perfectly fine for adding information, not both reading and displaying.
The output:
Enter name of the file
l.txt
Segmentation fault (core dumped)
Thank you for your kind help and clarification. Greatly appreciated.
Upvotes: 0
Views: 719
Reputation: 799
Any time you're debugging a memory issue (or really just any time you're making a debug build), you should compile with -g -fsanitize=address
if you're using GCC or clang. The address sanitizer will print exactly where your code accesses memory it shouldn't, whether that memory was recently freed or is after the end of an allocated block or is just a wild pointer, etc.
You're doing FILE *f = malloc(sizeof(FILE))
- that's unnecessay. fopen
will return a FILE*
, so when you do f = fopen(...)
, your program just ignores the existing value in f
and overwrites it with the pointer returned by fopen
. That doesn't cause your segfault though.
In the loops where you're reading the files, you're doing while (fread(...) != EOF)
. fread doesn't return EOF when it has reached the end of the file; it will just return a number that's lower than the one you asked for, and then you can check if that was due to an error or due to an EOF with the functions ferror
and feof
. In fact, fread couldn't return EOF even if it wanted to; EOF is usually -1, and fread returns a size_t which is unsigned. This also shouldn't cause your segfault though, it should just end up printing the last item in an infinite loop because fread will just not touch your struct and return 0 forever when it has reached the end of the file.
Your segfault: You do fread(&res, sizeof(struct student), 1, *resident)
. res
already a pointer (struct student *res
), so when you do &res
, you're getting a pointer to your pointer. fread
fills whatever it's pointed to, meaning it will fill your pointer to student, it won't fill your student. A pointer is way smaller than your big student struct, so it will end up writing past the end and start writing to random stack memory, which is not good. If you replace that &res
with just res
it should no longer segfault.
Upvotes: 1