So I'm working on a program in C where I take input from a file and put it in an array of Structs ... however never having gotten input from a file in C before, I'm a bit confused. I've tried multiple ways of doing it, and all of them came with a pretty similar result: The first variable is fine, the second variable is fine (except only half of the name is copied), the third and fourth variable are random gibberish. How big the gibberish is depends on how I write the program, but it is always random characters.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct student {
int student_ID;
char name[26];
char degree[26];
char campus[26];
};
void main() {
FILE* fileToOpen = fopen("student database.txt", "r");
if (fileToOpen == NULL) {
printf("File cannot be opened!...\n...");
exit(0);
}
struct student studentList[12];
char buffer[200];
fgets(buffer, 200, fileToOpen);
int counter = 0;
int value;
while (!feof(fileToOpen)) {
value = sscanf(buffer, "%d,%s,%s,%s", &studentList[counter].student_ID, &studentList[counter].name, &studentList[counter].degree, &studentList[counter].campus);
printf("Read point: %d %s\n", studentList[counter].student_ID, studentList[counter].name);
fgets(buffer, 200, fileToOpen);
counter ;
}
printf("\n\n\n");
printf("First point: % d % s % s % s\n", studentList[0].student_ID, studentList[0].name, studentList[0].degree, studentList[0].campus);
printf("Second point: % d % s % s % s\n", studentList[1].student_ID, studentList[1].name, studentList[1].degree, studentList[1].campus);
printf("\nvalue: %d", value);
fclose(fileToOpen);
}
I don't get what's going on here. I've tried other input methods (ones that iddn't involve that char buffer array, fgets, etc), followed guides step by step, yet the print statements always revealed that only part of the data is input correctly is the first variable, and half of the second variable (first name). You can see that in the final two print statements. What's the problem?
Here is the text file for reference:
895329,Tom Elder,Computer Science,Downtown Campus
564123,Elissa Honk,Interior Design,East Campus
963474,Alfonso Dobra,Civil Engineering,West Campus
127485,Paolo Morisa,Accounting,West Campus
330021,Lisa Bali,Accounting,Downtown Campus
844112,Eli Dovian,Computer Science,East Campus
745112,Rola Etrania,Civil Engineering,East Campus
541247,Pamela Dotti,Interior Design,East Campus
745930,Paul Sabrini,Accounting,Downtown Campus
500124,Gabriella Alma,Accounting,Downtown Campus
741206,Joe Damian,Computer Science,West Campus
963100,Perla Kino,Interior Design,East Campus
Thanks for any help and advice. This is all the program is so far.
CodePudding user response:
Test the return value of
fgets()
, notfeof()
. Why is “while ( !feof (file) )” always wrong?. Avoid magic numbers like 200. Use the size ofbuffer
.// fgets(buffer, 200, fileToOpen); // while (!feof(fileToOpen)) { ... // fgets(buffer, 200, fileToOpen); while (fgets(buffer, sizeof buffer, fileToOpen)) {
Do not try to use more than 12
studentList[counter]
.
Test counter < 12
someplace.
To scan characters except for a
','
, do not use"%s"
, use" %[^,]"
. Use a width to prevent buffer overrun."%s"
skips leading white-space and then scans in all non-white-space. A','
is not special.// sscanf(buffer, "%d,%s,%s,%s" sscanf(buffer, "%d, [^,], [^,], [^,\n]"
Check the return value from
sscanf()
. Do not usestudentList[counter]
unless scan was successful.value = sscanf(buffer, "%d, [^,], [^,], [^,\n]" ... if (value != 4) { puts("Failed to scan <%s>\n", buffer); } else { ; // use studentList[counter] }
CodePudding user response:
Here is a way to do what you want without the use of a char
array as a buffer. The contents of "blankpaper.txt"
are the same as that provided at the end of your post. fscanf()
is used to read the integer at the beginning of a line and getc()
is used for the rest. As we use getc()
, for those members of the student
structure that refer to char
arrays, we make sure that we do not attempt to store more than NAME_LEN
(a macro representing 25) characters. These arrays have length NAME_LEN 1
so that they can be properly null-terminated. Finding a comma signals we need to start storing characters in another char
array. Let me know if there are any questions!
Program
#include <stdio.h>
#include <stdlib.h>
#define NUM_STUD 12 /* number of students */
#define NAME_LEN 25 /* max 'name' length for name, degree, or campus */
#define FILE_NAME "blankpaper.txt"
struct student {
int id;
char name[NAME_LEN 1];
char degree[NAME_LEN 1];
char campus[NAME_LEN 1];
};
int main(void) {
struct student a[NUM_STUD];
char *b[3]; /* pointers to 'name' strings */
size_t i, j, k; /* loop variables */
int ch; /* reads characters */
FILE *fp = fopen(FILE_NAME, "r"); /* open file for reading */
/* if cannot open file */
if (fp == NULL) {
printf("Cannot open %s\n", FILE_NAME);
exit(EXIT_FAILURE);
}
for (k = 0; k < NUM_STUD; k ) {
/* read and store the integer, also read comma (should return 1) */
if (fscanf(fp, "%d,", &a[k].id) != 1) {
fclose(fp);
exit(EXIT_FAILURE);
}
b[0] = a[k].name, b[1] = a[k].degree, b[2] = a[k].campus;
for (j = 0; j < 3; j ) {
i = 0;
while ((ch = getc(fp)) != '\n' && ch != EOF) {
if (ch == ',')
break;
if (i < NAME_LEN)
b[j][i ] = ch;
}
b[j][i] = '\0'; /* terminate string */
}
}
fclose(fp); /* close file */
/* print values of structure members */
for (i = 0; i < NUM_STUD; i ) {
printf("ID : %d\n", a[i].id);
printf("Name : %s\n", a[i].name);
printf("Degree: %s\n", a[i].degree);
printf("Campus: %s\n\n", a[i].campus);
}
return 0;
}
Output
ID : 895329
Name : Tom Elder
Degree: Computer Science
Campus: Downtown Campus
ID : 564123
Name : Elissa Honk
Degree: Interior Design
Campus: East Campus
ID : 963474
Name : Alfonso Dobra
Degree: Civil Engineering
Campus: West Campus
ID : 127485
Name : Paolo Morisa
Degree: Accounting
Campus: West Campus
ID : 330021
Name : Lisa Bali
Degree: Accounting
Campus: Downtown Campus
ID : 844112
Name : Eli Dovian
Degree: Computer Science
Campus: East Campus
ID : 745112
Name : Rola Etrania
Degree: Civil Engineering
Campus: East Campus
ID : 541247
Name : Pamela Dotti
Degree: Interior Design
Campus: East Campus
ID : 745930
Name : Paul Sabrini
Degree: Accounting
Campus: Downtown Campus
ID : 500124
Name : Gabriella Alma
Degree: Accounting
Campus: Downtown Campus
ID : 741206
Name : Joe Damian
Degree: Computer Science
Campus: West Campus
ID : 963100
Name : Perla Kino
Degree: Interior Design
Campus: East Campus