Reading in a text file in C, separate lines into multiple variables - c

I'm currently working on a program that simulates various CPU scheduling methods. Currently I have the program asking for input:
printf("Enter type of CPU scheduling algorithm (SJF, RR, PR_noPREMP, PR_withPREMP): ");
scanf("%s", typeOf);
printf("Enter number of processes: ");
scanf("%d", &numPro);
struct processStruct structs[numPro];
int burstTimes[numPro];
for (i = 0; i < numPro; i++) {
printf("Enter process number: ");
scanf("%d", &structs[i].pNum);
printf("Enter arrival time: ");
scanf("%d", &structs[i].arTime);
printf("Enter CPU burst time: ");
scanf("%d", &structs[i].cpuBur);
printf("Enter priority: ");
scanf("%d", &structs[i].prio);
}
In addition to the two variables typeOf (an int) and numPro (a char array) I am also using a data structure.
Here is the data structure that is holding the various parameters:
struct processStruct {
int pNum;
int arTime;
int cpuBur;
int prio;
int waitTim;
};
Instead of manual input I could like to use a text file with the same information as input for the program. The text file would look something like this:
SJF
4
1 0 6 1
2 0 8 1
3 0 7 1
4 0 3 1
First line is the name of the scheduling algorithm.
Second line is the number of processes.
The following lines consists of information for each process. So 1 0 6 1 = Process = 1, 0 = Arrival Time, 6 = CPU burst time, 1 = Priority
I unfortunately have little experience using text file input with C. Does anyone have ideas about how I could read in the data from the text file into the variables and data structure?
Thank you
Edit: One of the issues I am having is that the data is not the same for each line. If it was just the rows of 4 numbers then it would be relatively easy. I need the program to read the first line into a char array (string), the second into the numPro variable then the subsequent lines into multiple instances of the data structure (one for each process).

The file can be read fairly simply with fscanf() because everything except the first line identifier is a number. But you do need to check the validity of what is read from the file. I have just used exit(1) on error for illustration, it could be more sophisticated than that (for example an error message).
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
struct processStruct {
int pNum;
int arTime;
int cpuBur;
int prio;
int waitTim;
};
struct processStruct structs[MAX];
int main(int argc, char** args)
{
FILE *fil;
char typeOf[4];
int numPro, i;
if ((fil = fopen("myfile.txt", "rt")) == NULL)
exit(1);
if(fscanf(fil, "%4s", typeOf) != 1)
exit(1);
if(fscanf(fil, "%d", &numPro) != 1)
exit(1);
if(numPro > MAX)
exit(1);
for(i=0; i<numPro; i++) {
if(fscanf(fil, "%d%d%d%d", &structs[i].pNum, &structs[i].arTime,
&structs[i].cpuBur, &structs[i].prio) != 4)
exit(1);
}
fclose(fil);
// test the result
printf("Type: %s\n", typeOf);
printf("Num: %d\n", numPro);
for(i=0; i<numPro; i++) {
printf("%d %d %d %d\n", structs[i].pNum, structs[i].arTime,
structs[i].cpuBur, structs[i].prio);
}
return 0;
}
Program output:
Type: SJF
Num: 4
1 0 6 1
2 0 8 1
3 0 7 1
4 0 3 1

You will want to use fscanf and fprintf instead of scanf and printf to do I/O from/to files instead of standard input/output.
These are widely documented. You will use FILE * variables and fopen & fclose. You can even use stdin, stdout, and stderr as handles for the console.

The best way to read lines in a file with C is to use the getline() function. It is much more reliable than scanf() and can allocate the needed memory automagically.
Here is the code I suggest:
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char **argv)
{
FILE *inputfile;
if (argc < 2)
{
fprintf (stderr, "error: missing file name in the arguments\n");
exit (EXIT_FAILURE);
}
inputfile = fopen (argv[1], "r");
if (!inputfile)
{
perror ("myprogram");
exit (EXIT_FAILURE);
}
/* Getting first line */
char *line = NULL;
size_t line_size = 0;
if (!getline(&line, &line_size, inputfile))
{
fprintf (stderr, "error: failed to read first line\n");
exit (EXIT_FAILURE);
}
/* Getting the size of the matrix */
unsigned int size; /* Size of the matrix */
if (sscanf (line, "%zd", &size) != 1)
{
fprintf (stderr, "error: first line has wrong format\n");
exit (EXIT_FAILURE);
}
/* Getting the content of the matrix */
int matrix[size][size];
for (unsigned int i = 0; i < size; i++)
{
if (!getline (&line, &line_size, inputfile))
{
fprintf (stderr, "error: input file has wrong format\n");
exit (EXIT_FAILURE);
}
/* Copying the items of the line to the matrix */
char *ptr = line;
for (unsigned j = 0; j < size; j++)
{
matrix[i][j] = atoi(strtok(ptr, " "));
ptr = NULL;
}
}
free(line);
return EXIT_SUCCESS;
}
Beware, I didn't tried this code... So, if something is not working properly, I'll fix it.

Related

fscanf returns 3 instead of -1 (EOF) at the end of the file

So there's a file I'm using fscanf() in. I've set a condition in my code that when (fscanf(...) == EOF, the program needs to break out of the function I'm currently in. The thing is, this condition is never satisfied in any of the cases where there's no more lines of text in the file. EOF is always -1, whereas fscanf(...) returns 4 each time there's a line of code, and 3 when there's nothing left for it to search through (instead of -1). If I add a line of code similar to the other ones, I will simply get one more instance of fscanf() returning 4, and then again, it'll give me a 3.
What could possibly be the issue? Thank you in advance!
Sample text file content:
CHRISTOU GIORGOS,140,VAS. OLGAS 112
MALAKOU MALAKOS,150,DRAS. BAGAS 12
TSIKOU GIJRAN,140,JABS. DRALGAS 1
TSIKOU BIRBAN,140,JABS. DRALGAS 1
DELHDHMHTRIOU SPYROS,50,SPEED. BAGAS 62
FOX SIN,40,BAN. NINJA 1
Code:
#include <stdio.h>
#define M 100
typedef struct {
char name[30];
int apousies;
} studentT;
void readInput (FILE* infile, studentT students[], int *pApousies, int *pStudents);
int main()
{
char inputfilename[30];
FILE* infile;
while (1) {
printf("Input file name :");
gets(inputfilename);
infile = fopen(inputfilename, "r");
if (infile != NULL) break;
printf("Cannot open input file %s. Try again.\n", inputfilename);
}
studentT students[M];
int numberOfStudents = 0, numberOfApousies = 0;
readInput(infile, students, &numberOfApousies, &numberOfStudents);
fclose(infile);
return 0;
}
void readInput (FILE* infile, studentT students[], int *pApousies, int *pStudents)
{
int nscan, apousies, studcount, apouscount, line;
char name[30], comments[68], termch;
line = 0;
while (1)
{
nscan = fscanf(infile, "%30[^,], %d, %68[^\n]%c", name, &apousies, comments, &termch);
/* printf("onoma: %s apousies: %d sxolia: %s terma: %c\n", name, apousies, comments, termch);
printf("%d\n", nscan);
printf("%d\n", EOF);*/
if (nscan == EOF) break;
line++;
if (nscan != 4 || termch != '\n')
{
printf("Error in line %d. Program termination\n", line);
exit(1);
}
}
}
fscanf returns 3 instead of -1 (EOF) at the end of the file
Because the last line lacks a '\n'.
OP's code "works" with the "tmp.txt" the below code makes.
fscanf() is hard to use right. Easier to code and debug with fgets(). Discussion follows.
"%30[^,]" allows too much for char name[30]. Use char name[30+1] or "%29[^,]"
OP's approach can readily fail with seemingly minor parsing problems such as a missing '\n' on the last line. After such a failure, recovery is extraordinary difficult with fscanf()
Debug: Importantly, the below print should not be attempted until code insures nscan >= 4
if (nscan >= 4) // add
printf("onoma: %s apousies: %d sxolia: %s terma: %c\n", name, apousies, comments, termch);
Instead, use fgets(). With line orientated data, this really is the best first step.
fscanf() is challenging to use and cope with errors. Far simpler to read a line with fgets() and then parse.
Using " %n" is a nice way to detect if all the line parsed.
#include <stdio.h>
#include <stdlib.h>
#define M 100
typedef struct {
char name[30];
int apousies;
} studentT;
void readInput(FILE* infile, studentT students[], int *pApousies,
int *pStudents) {
(void) students;
(void) pApousies;
(void) pStudents;
int line = 0;
char buf[200];
while (fgets(buf, sizeof buf, infile)) {
int apousies;
char name[30], comments[68];
int n = 0;
line++;
sscanf(buf, " %29[^,],%d , %67[^\n] %n", name, &apousies, comments, &n);
if (n == 0 || buf[n]) {
fprintf(stderr, "Error in line %d <%s>. Program termination\n", line, buf);
exit(1);
}
printf("Success %d <%s> %d <%s>\n", line, name, apousies, comments);
}
}
Sample use
int main() {
FILE *f = fopen("tmp.txt", "w");
fputs("CHRISTOU GIORGOS,140,VAS. OLGAS 112\n"
"MALAKOU MALAKOS,150,DRAS. BAGAS 12\n"
"TSIKOU GIJRAN,140,JABS. DRALGAS 1\n"
"TSIKOU BIRBAN,140,JABS. DRALGAS 1\n"
"DELHDHMHTRIOU SPYROS,50,SPEED. BAGAS 62\n"
"FOX SIN,40,BAN. NINJA 1\n", f);
fclose(f);
f = fopen("tmp.txt", "r");
studentT st[M];
readInput(f, st, NULL, NULL);
fclose(f);
}
Output
Success 1 <CHRISTOU GIORGOS> 140 <VAS. OLGAS 112>
Success 2 <MALAKOU MALAKOS> 150 <DRAS. BAGAS 12>
Success 3 <TSIKOU GIJRAN> 140 <JABS. DRALGAS 1>
Success 4 <TSIKOU BIRBAN> 140 <JABS. DRALGAS 1>
Success 5 <DELHDHMHTRIOU SPYROS> 50 <SPEED. BAGAS 62>
Success 6 <FOX SIN> 40 <BAN. NINJA 1>

Strings and array of structures

***UPDATED WITH NEW CODE
I'm trying to load a file data with an unknown amount of lines of data.
The data is organized as last, first:score1:score2:score3:score5:lettergrade
I'm getting the file to (sort of) load into an array and print.
When the data prints, it doesn't print the first name, just the first. It's printing the same integer for evert data element except for the last one, that comes out at 0 for all. Also, it's not flushing the data that doesn't return 8 elements.
PLEASE help!
Thanks in advance.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define FFLUSH while(fgetsc(fp) != '\n')
#define MAX_STUDENTS 45
typedef struct aStudent
{
char name[26];
int id[7];
int test1[4];
int test2[4];
int proj1[4];
int proj2[4];
int proj3[4];
char grade[4];
} aStudent;
int main(void)
{
char file_name[FILENAME_MAX];
FILE* fp;
int i;
int rc;
int dc;
aStudent studentArray[MAX_STUDENTS];
printf("Enter File Name: ");
rc = scanf("%s", &file_name);
if (rc == 0)
{
printf("\n\nError: No file name entered.");
exit(0);
}
fp = fopen(file_name, "r");
if (fp == NULL)
{
printf("Error: Could not open file %s for read", file_name);
exit(0);
}
for(int i=0; i< 45; i++)
{
dc = (fscanf(fp, "%s[^:]%d[^:]%d[^:]%d[^:]%d[^:]%d[^:]%d[^:]%f[^:]%c[^:\n]", studentArray[i].name, studentArray[i].id, studentArray[i].test1, studentArray[i].test2, studentArray[i].proj1, studentArray[i].proj2, studentArray[i].proj3, studentArray[i].grade));
if (dc != 8)
{
FFLUSH;
}
printf("%s %d %d %d %d %d %d %.2f %c", studentArray[i].name, studentArray[i].id, studentArray[i].test1, studentArray[i].test2, studentArray[i].proj1, studentArray[i].proj2, studentArray[i].proj3, studentArray[i].grade);
}
return 0;
}
STUDENT is a type. You cannot fgets into a type. There is no array STUDENT. Try this;
typedef struct aStudent
{
char name[26];
int id[7];
int test1[4];
int test2[4];
int proj1[4];
int proj2[4];
int proj3[4];
int ave[4];
char grade[4];
} aStudent;
and;
aStudent studentArray[MAX_STUDENTS];
and replace gGets with fscanf.
It appears you have your struct set up incorrectly to handle the data you want to read from your file. Your data was:
name:score1:score2:score3:score5:lettergrade
A struct that makes sense (given the multiple scores) would be:
typedef struct {
char name[MAXNM];
int id;
int scores[NGRDS];
float ave;
char grade;
} student;
(you have never accounted for where the id comes from and I'll leave it to use to split name into first, last, as your original question specified name and your recent edits added first, last)
What is clear is you want to read your datafile into a struct and compute the ave (average) from the grades read (which should be a floating-point type instead of int). Given your file format, reading each line of data with the scanf family functions is probably a bit more sensible than reading/tokenizing each line with fgets/strtok.
Your mixing of fgets and fscanf syntax will not work and exemplifies the difficulty in trying to shoehorn mixed data into a scanf type format string. You must take care in crafting the string to handle whitepace and any trailing newlines left in the input buffer. For your set of data, the following will work as well as anything else:
char *fmt = " %[^:]:%d:%d:%d:%d:%c";
Another way to account for the trailing newline is to use the assignment suppression operator to read and discard the trailing newline. When used, the discarded conversion is not added to the returned match count. e.g.
char *fmt = "%[^:]:%d:%d:%d:%d:%c%*c";
There is no need for macros to flush the input buffer if you craft your format string correctly.
Putting the pieces together, and leaving your belated change from name to last, first to you, you could do something like the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* constants for:
NGRDS - max number of grades per student.
MAXNM - max length of student name.
MAXSTD - max number of students in array.
MAXFN - max filename length.
*/
enum { NGRDS = 4, MAXNM = 26, MAXSTD = 45, MAXFN = 128 };
typedef struct {
char name[MAXNM];
int id;
int scores[NGRDS];
float ave;
char grade;
} student;
int main (void) {
char filename[MAXFN]; /* initialize variables */
char *fmt = " %[^:]:%d:%d:%d:%d:%c";
FILE* fp = NULL;
size_t i = 0, nstudents = 0;
student students[MAXSTD] = {{ {""}, 0, {0}, 0.0, 0 }};
printf ("\nEnter File Name: ");
if (scanf("%s", filename) != 1) { /* validate filename read */
fprintf (stderr, "error: invalid file name entered.\n");
return 1;
}
if (!(fp = fopen (filename, "r"))) { /* validate file open */
fprintf (stderr, "error: file open failed '%s'\n.", filename);
return 1;
}
/* read each line in file */
while (fscanf (fp, fmt, students[i].name, &students[i].scores[0],
&students[i].scores[1],&students[i].scores[2],
&students[i].scores[3], &students[i].grade) == 6) {
int j; /* compute sum/average */
for (j = 0; j < NGRDS; j++) students[i].ave += students[i].scores[j];
students[i].ave /= (float)NGRDS;
if (++i == MAXSTD) { /* check against max */
fprintf (stderr, "warning: students array full.\n");
break;
}
}
fclose (fp); /* close file */
nstudents = i; /* save number of students */
for (i = 0; i < nstudents; i++) { /* output student data */
size_t j;
printf ("\n Student[%2zu]\n name : %s\n scores :",
i, students[i].name);
for (j = 0; j < NGRDS; j++) printf (" %d", students[i].scores[j]);
printf ("\n average: %.2f\n grade : %c\n",
students[i].ave, students[i].grade);
}
return 0;
}
Example Data
$cat dat/studentgrades.txt
Joe Cool:80:77:63:88:c
Nancy Smart:96:93:97:99:a
Dwane Dumb:61:60:67:50:f
Al Smith:75:77:78:73:c
Example Use/Output
$ ./bin/studentstruct
Enter File Name: dat/studentgrades.txt
Student[ 0]
name : Joe Cool
scores : 80 77 63 88
average: 77.00
grade : c
Student[ 1]
name : Nancy Smart
scores : 96 93 97 99
average: 96.25
grade : a
Student[ 2]
name : Dwane Dumb
scores : 61 60 67 50
average: 59.50
grade : f
Student[ 3]
name : Al Smith
scores : 75 77 78 73
average: 75.75
grade : c
(note: your letter grade should be computed based on the average, not simply read from the file -- what if the grades change? Also note that your input file format is fixed and inflexible. If the number of fields or their format changes in any way, you must account for the change in your fmt format string.)
Look it over and let me know if you have any questions.

Reading tab delimited ints into a struct in C [duplicate]

I'm currently working on a program that simulates various CPU scheduling methods. Currently I have the program asking for input:
printf("Enter type of CPU scheduling algorithm (SJF, RR, PR_noPREMP, PR_withPREMP): ");
scanf("%s", typeOf);
printf("Enter number of processes: ");
scanf("%d", &numPro);
struct processStruct structs[numPro];
int burstTimes[numPro];
for (i = 0; i < numPro; i++) {
printf("Enter process number: ");
scanf("%d", &structs[i].pNum);
printf("Enter arrival time: ");
scanf("%d", &structs[i].arTime);
printf("Enter CPU burst time: ");
scanf("%d", &structs[i].cpuBur);
printf("Enter priority: ");
scanf("%d", &structs[i].prio);
}
In addition to the two variables typeOf (an int) and numPro (a char array) I am also using a data structure.
Here is the data structure that is holding the various parameters:
struct processStruct {
int pNum;
int arTime;
int cpuBur;
int prio;
int waitTim;
};
Instead of manual input I could like to use a text file with the same information as input for the program. The text file would look something like this:
SJF
4
1 0 6 1
2 0 8 1
3 0 7 1
4 0 3 1
First line is the name of the scheduling algorithm.
Second line is the number of processes.
The following lines consists of information for each process. So 1 0 6 1 = Process = 1, 0 = Arrival Time, 6 = CPU burst time, 1 = Priority
I unfortunately have little experience using text file input with C. Does anyone have ideas about how I could read in the data from the text file into the variables and data structure?
Thank you
Edit: One of the issues I am having is that the data is not the same for each line. If it was just the rows of 4 numbers then it would be relatively easy. I need the program to read the first line into a char array (string), the second into the numPro variable then the subsequent lines into multiple instances of the data structure (one for each process).
The file can be read fairly simply with fscanf() because everything except the first line identifier is a number. But you do need to check the validity of what is read from the file. I have just used exit(1) on error for illustration, it could be more sophisticated than that (for example an error message).
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
struct processStruct {
int pNum;
int arTime;
int cpuBur;
int prio;
int waitTim;
};
struct processStruct structs[MAX];
int main(int argc, char** args)
{
FILE *fil;
char typeOf[4];
int numPro, i;
if ((fil = fopen("myfile.txt", "rt")) == NULL)
exit(1);
if(fscanf(fil, "%4s", typeOf) != 1)
exit(1);
if(fscanf(fil, "%d", &numPro) != 1)
exit(1);
if(numPro > MAX)
exit(1);
for(i=0; i<numPro; i++) {
if(fscanf(fil, "%d%d%d%d", &structs[i].pNum, &structs[i].arTime,
&structs[i].cpuBur, &structs[i].prio) != 4)
exit(1);
}
fclose(fil);
// test the result
printf("Type: %s\n", typeOf);
printf("Num: %d\n", numPro);
for(i=0; i<numPro; i++) {
printf("%d %d %d %d\n", structs[i].pNum, structs[i].arTime,
structs[i].cpuBur, structs[i].prio);
}
return 0;
}
Program output:
Type: SJF
Num: 4
1 0 6 1
2 0 8 1
3 0 7 1
4 0 3 1
You will want to use fscanf and fprintf instead of scanf and printf to do I/O from/to files instead of standard input/output.
These are widely documented. You will use FILE * variables and fopen & fclose. You can even use stdin, stdout, and stderr as handles for the console.
The best way to read lines in a file with C is to use the getline() function. It is much more reliable than scanf() and can allocate the needed memory automagically.
Here is the code I suggest:
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char **argv)
{
FILE *inputfile;
if (argc < 2)
{
fprintf (stderr, "error: missing file name in the arguments\n");
exit (EXIT_FAILURE);
}
inputfile = fopen (argv[1], "r");
if (!inputfile)
{
perror ("myprogram");
exit (EXIT_FAILURE);
}
/* Getting first line */
char *line = NULL;
size_t line_size = 0;
if (!getline(&line, &line_size, inputfile))
{
fprintf (stderr, "error: failed to read first line\n");
exit (EXIT_FAILURE);
}
/* Getting the size of the matrix */
unsigned int size; /* Size of the matrix */
if (sscanf (line, "%zd", &size) != 1)
{
fprintf (stderr, "error: first line has wrong format\n");
exit (EXIT_FAILURE);
}
/* Getting the content of the matrix */
int matrix[size][size];
for (unsigned int i = 0; i < size; i++)
{
if (!getline (&line, &line_size, inputfile))
{
fprintf (stderr, "error: input file has wrong format\n");
exit (EXIT_FAILURE);
}
/* Copying the items of the line to the matrix */
char *ptr = line;
for (unsigned j = 0; j < size; j++)
{
matrix[i][j] = atoi(strtok(ptr, " "));
ptr = NULL;
}
}
free(line);
return EXIT_SUCCESS;
}
Beware, I didn't tried this code... So, if something is not working properly, I'll fix it.

How do you properly use the fstat() function and what are its limits?

So I am very new to C. I have done a lot of programming in Java and am finding it very difficult to learn C.
Currently I am assigned to read in a file from our terminal window, which will contain a list of integers. From this list we must read the values and calculate the average, I believe I have done this correctly.
My only problem is I do not understand how to use the fstat() correctly, I read the man page but am still having a hard time understanding. In my code below, I am wanting to use fstat() to find the size of the file being read so I can then allocate the correct amount of space for my array where I store the values read off the input file. I just need to know the proper usage and syntax of fstat() and from there I believe I can make significant progress. Thanks in advance!
char *infile;
int fileSize;
int fd;
int i;
int j;
int temp;
int sum = 0;
int average;
/* enforce proper number of arguments
*/
if (argc != 1)
{
fprintf(stderr, "Too many arguments.\n");
exit(1);
}
infile = argv[1];
//open file
fd = open(infile, O_RDONLY);
//exit if open fails
assert (fd > -1);
//find size of file
fileSize = fstat(fd, blksize_t st_blksize);
//fine perfect size for array
temp = malloc(temp * sizeof(int));
//create file of perfect size
int intArray[temp];
//scan integers into our array
for (i = 0; i < fileSize; i++)
{
fscanf(infile, "%d", intArray[i]);
}
fclose(fd);
//add all integers into the array up
for (j = 0; j < fileSize; j++);
{
sum = sum + intArray[j];
}
//calculat average
average = (sum)/fileSize;
printf("Number of numbers averaged: %d\n Average of numbers: %d\n", fileSize, average);
if ( close(fd) == -1 )
{
fprintf(stderr, "error closing file -- quitting");
exit(1);
}
return 0;
}
The library function fstat() does not return the size of the file, it returns 0 if successful. It informs the file size by filling in the struct passed as an argument.
if (fstat( fd, &buf))
printf("Bad call\n");
else
printf("File size : %ld\n", buf.st_size);
But as #chux (deleted post) answered, it tells you the file size in bytes, not in integers. The function fscanf() inputs the data from text, so there is no direct correlation between file size, and number of fields.
So unfortunately, in answer to your titled question, using fstat() to determine the file size is of no practical use to you. Your secondary implied question is how to allocate enough memory for the array. I posted an answer to that, in a different context where at the outset the array size is unknown. C reading a text file separated by spaces with unbounded word size
But here I use a simpler technique - parse the file twice to find out how many textual integers it contains. It then rewinds the file and allocates memory for the array, although, in this example, the array isn't necessary to calculate the sum and average of the values, and the double file parse isn't necessary either, unless you plan to do more with the values.
#include <stdio.h>
#include <stdlib.h>
void fatal(char *msg) {
printf("%s\n", msg);
exit (1);
}
int main(int argc, char *argv[])
{
FILE *fil;
int *array;
int items = 0;
int sum = 0;
int avg;
int value;
int i;
if (argc < 2) // check args
fatal ("No file name supplied");
if ((fil = fopen (argv[1], "rt")) == NULL) // open file
fatal ("Cannot open file");
while (fscanf(fil, "%d", &value) == 1) // count ints
items++;
printf ("Found %d items\n", items);
if (items == 0)
fatal ("No integers found");
if ((array = malloc(items * sizeof (int))) == NULL) // allocate array
fatal ("Cannot allocate memory");
if (fseek (fil, 0, SEEK_SET)) // rewind file
fatal ("Cannot rewind file");
for (i=0; i<items; i++) {
if (fscanf(fil, "%d", &value) != 1) // check int read
fatal ("Cannot read integer");
array[i] = value;
sum += value;
}
fclose(fil);
printf ("Sum = %d\n", sum);
printf ("Avg = %d\n", (sum+items/2) / items); // allow rounding
free(array);
return 0;
}
Input file:
1 2 3
4 5
6
-1 -2
Program output:
Found 8 items
Sum = 18
Avg = 2
You claim to have read the manpage for fstat(), which seems at odds with:fileSize = fstat(fd, blksize_t st_blksize);
You need to declare a struct stat in the function scope, and pass a pointer to it to fstat():
struct stat finfo;
fstat(fd, &finfo);
Then you can read the file size from the struct stat:
off_t filesize = finfo.st_size;
I'd also recommend using size_t instead of int for everything to do with object sizes.

fscanf, structs, and using the struct c programming

/*Project 1
Student records
1. Read the file with the records
2. store them
3. sort them
4. output them
ex. input and output (SORTED by student ID
2040003 AAAA BBBBBBBBB ComputerScience 3.45
2040002 AAA CCC ElectricalEngineering 3.01
2040005 AAAAAAAAAAAAAAAAA BBB ComputerScience 3.60
2040002,AAA,CCC,ElectricalEngineering,3.01
2040003,AAAA,BBBBBBBBB,ComputerScience,3.45
2040005,AAAAAAAAAAAAAAAAA,BBB,ComputerScience,3.60
char* name = malloc(256*sizeof(char));
*/
int main()
{
typedef struct StudentRecords
{
int StudentID; //must be of size 7 between 1000000 and 9999999
char *Firstname; //= MALLOC(256*sizeof(char)); // must be any length and allocate memory dynamically.
char *Lastname; //= MALLOC(256*sizeof(char));
char *Department; //= MALLOC(256*sizeof(char));
float GPA; // must be between 0 and 4
} STUDENTRECORDS;
/*
First job is read the file
*/
//set variables
int i=0;
char filecontent, file_name[100];
FILE *fp;
STUDENTRECORDS StudentRecords[300];
STUDENTRECORDS a[300];
int size =0;
printf("Enter directory of file\n"); // instructs user to enter directory of file
gets(file_name); //prompt use
fp = fopen(file_name,"r"); //opens the file "r" is read mode for fopen()
// here is a check to see if fp is empty and throw an error if so
if (fp == NULL)
{
perror("Could not open file\n");
exit(EXIT_FAILURE);
}
printf("The contents of %s file are :\n", file_name); // just prints the file name (file_name) you are prompted for
// here is where the printing of contents actually occurs
while ((filecontent = fgetc(fp)) != EOF) // I think EOF is end of feed here, not 100%
{
printf("%c",filecontent);
}
//I thought this line was to figure out how many lines are in the text, but it isnt working.
while (!feof(fp))
{
read(StudentRecords, i, fp);
i++;
}
//because the while statement isnt working, Ive elected to setting size to 3 in order to continue coding.
size = i = 3;
printf("Size = %d\n", size);
//I thought this essentially put the files contents into
for (i = 0; i < size; ++i)
fscanf(fp, "%d %s %s %s %f\n", &StudentRecords[i].StudentID, &StudentRecords[i].Firstname, &StudentRecords[i].Lastname, &StudentRecords[i].Department, &StudentRecords[i].GPA);
for (i = 0; i < size; ++i)
printf("%s", StudentRecords[i]);
//printf("%d %s %s %s %f/n", &StudentRecords[i].StudentID, &StudentRecords[i].Firstname, &StudentRecords[i].Lastname, &StudentRecords[i].Department, &StudentRecords[i].GPA);
for (i = 0; i < size; ++i)
fscanf(fp, "%d %s %s %s %f\n", &a[i].StudentID, &a[i].Firstname, &a[i].Lastname, &a[i].Department, &a[i].GPA);
for (i = 0; i < size; ++i)
printf("%s", a[i]);
//printf("%d %s %s %s %f/n", &a[i].StudentID, &a[i].Firstname, &a[i].Lastname, &a[i].Department, &a[i].GPA);
// fclose() must follow an fopen()
fclose(fp);
//printf("%g", &StudentRecords);
// return code
return 0;
}
How do I add information into a struct and print it or use it? This is what
i have so far. I've tried many different things and to no avail. I think the problem is with my initializing my struct for use. I can't get it right. I've tried searching for a solution, but each one is different and don't explain much.
Thanks for any suggestions.
Please find example code for reading content from file and storing it in structure also for this example have only take 5 student data entry(you can change as you wish) And on which criteria you want to do sorting? So i leave sorting on you.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_ENTRY 5
typedef struct StudentRecords
{
int StudentID; //must be of size 7 between 1000000 and 9999999
char *Firstname; //= MALLOC(256*sizeof(char)); // must be any length and allocate memory dynamically.
char *Lastname; //= MALLOC(256*sizeof(char));
char *Department; //= MALLOC(256*sizeof(char));
float GPA; // must be between 0 and 4
} STUDENTRECORDS;
int main()
{
/*
First job is read the file
*/
//set variables
int i=0;
char filecontent, file_name[100];
FILE *fp;
STUDENTRECORDS StudentRecords[MAX_ENTRY];
for(i=0;i<MAX_ENTRY;i++)
{
StudentRecords[i].Firstname = malloc(sizeof(char)*256);
StudentRecords[i].Lastname = malloc(sizeof(char)*256);
StudentRecords[i].Department = malloc(sizeof(char)*256);
}
printf("Enter directory of file\n"); // instructs user to enter directory of file
gets(file_name); //prompt use
fp = fopen(file_name,"r"); //opens the file "r" is read mode for fopen()
// here is a check to see if fp is empty and throw an error if so
if (fp == NULL)
{
perror("Could not open file\n");
//exit(EXIT_FAILURE);
}
i=0;
while(EOF!=fscanf(fp, "%d %s %s %s %f\n", &StudentRecords[i].StudentID, StudentRecords[i].Firstname, StudentRecords[i].Lastname, StudentRecords[i].Department, &StudentRecords[i].GPA))
{
printf("%d %s %s %s %f\n", StudentRecords[i].StudentID, StudentRecords[i].Firstname, StudentRecords[i].Lastname, StudentRecords[i].Department, StudentRecords[i].GPA);
i++;
}
// fclose() must follow an fopen()
fclose(fp);
return 0;
}
Note: never forgot to free string which allocated by malloc after it's use.
A few comments, and some suggestions:
Was it your lecturer who said to use a linked-list? If so.. you really should do that otherwise you'll lose marks for failing to meet the spec.
EOF is 'End Of File'. feof() tells you if the stream pointer passed to it has hit EOF already.
Your while loop to print the contents is inefficient. Rather than reading every. single. character. in. the. file., you should read the entire file (or at least, large chunks thereof, let's not assume infinite memory), fclose() the stream and then operate on the read-in file.
Also, this sort of exercise lends itself very well to fixed-size record
Omitting error handling, variable declarations, structures and
using some pseudocode:
stat("/path/to/file", &statbuf)
inputfd = fopen("/path/to/file", r);
/* assuming that we only have a small file... */
contents = calloc(statbuf.st_size * sizeof(char));
/* read it all in, in one big chunk */
fread(contents, statbuf.st_size, 1, inputfd);
fclose(inputfd);
/* Now you can operate on it however you like */
bytesleft = statbuf.st_size;
/*
* this might need to go at the top of your block, depends on if you
* have enabled C99
*/
char eachline[MAXLINELENGTH];
int n = 0;
while (bytesleft > 0) {
add_new_list_element(mylist);
bzero(eachline, MAXLINELENTH);
memccpy(&eachline, contents[n], '\n', MAXLINELENGTH);
bytesleft -= sizeof(eachline);
nread = sscanf(start, "USE YOUR FORMAT STRING HERE", [variable list]);
if (nread < 0)
/* handle EOF, remember to make use of errno */
}
call_my_sort_function(mylist);
for (; thiselement != NULL; thiselement = thiselement->next)
print_salient_field_values(thiselement);

Resources