C Read until end of file - c

I currently have code that reads 4 lines and I want to be able to change that until EOF or my MAX const int value. I can not get the !EOF to work right and was wondering how would I change my code to accomplish this?
Thanks in advance
#include <stdio.h>
struct record{
char name[2];
int arrival_time;
int job_length;
int job_priority;
};
const int MAX = 40;
int main(void)
{
struct record jobs[MAX];
int i = 0;
int j;
FILE *f = fopen("data.dat","rb");
while (fscanf(f, "%s %d %d %d", &jobs[i].name, &jobs[i].arrival_time,
&jobs[i].job_length, &jobs[i].job_priority) == 4 && i < MAX)
i++;
for (j = 0; j < i; j++)
printf("%s %d %d %d\n", jobs[j].name, jobs[j].arrival_time,
jobs[j].job_length, jobs[j].job_priority);
fclose(f);
return(0);
}

Something like
while (fscanf(f, " %s ", &etc) != EOF) {
}
Then use feof(f) to check if it was a fscanf error or actually EOF.

Your code seems to do what you want, except:
char name[2];
Names will probably be longer than 1 character.
FILE *f = fopen("data.dat","rb");
You seem to be reading text ("r") file, not binary ("rb").
&jobs[i].name should be jobs[i].name

You need to change the order of the tests in your while() loop - you must test i < MAX before calling fscanf(), or else you'll potentially call it one too many times (you should also be passing jobs[i].name without the & to fscanf):
while (i < MAX && fscanf(f, "%s %d %d %d", jobs[i].name, &jobs[i].arrival_time,
&jobs[i].job_length, &jobs[i].job_priority) == 4)

Personnaly, I would code like this:
for(i=0 ; i<MAX ; ++i) {
fscanf(f, "%s %d %d %d", &jobs[i].name, &jobs[i].arrival_time,
&jobs[i].job_length, &jobs[i].job_priority);
if(ferror(f) || feof(f)) break;
}
The key point is that, at the best of my knowledge, you cannot know that a file is come to end without trying to read it. That is the reason why I check feof() and ferror() after having read data.
At the end of the loop, the variable i contains the number of read data

Related

Using fscanf *after* fgetc issue

In C, there are many posts concerning using fgetc after fscanf, dealing with an additional \n, but I am seeing another issue when using them in the reverse order; fscanf after fgetc.
When using fscanf after fgetc, I get a different fscanf-result to if I just omit fgetc (in the example script, just hard-coding num=1000 and commenting-out the block using fgetc).
I can replicate this correct fscanf-result while still using fgetc if I rewrite the file contents to the myFile variable, as in the below script. Removing this line produces the different incorrect fscanf-result.
What is causing the difference in the fscanf-result when using fgetc first, and how can I address the issue?
/* First read tab-delimited 4-digit int data from a text file,
* parsing into an array of the correct size num, then compute
* the mean of the array while avoiding overflow. */
#include <stdio.h>
#include <stdlib.h>
int main(){
FILE *myFile;
myFile = fopen("int_values.txt", "r");
int c=0, i=0;
float mean = 0.0;
// Identifying there are 1000 values in the tab-delimited file.
// Using fgetc
int num = 1;
while ((c=fgetc(myFile)) != EOF ){
if (c == '\t')
++num;
}
int arr[num]; // Array of correct size for all values from file.
// Redeclaring since fgetc seems to break fscanf
myFile = fopen("int_values.txt", "r");
// Read and store each value from file to array.
for (i=0; i<num; i++){
fscanf(myFile, "%d ", &arr[i]);
}
// Compute average cumulatively to avoid overflow.
mean = arr[0]
for (i=1; i<num; i++){
//printf("In the %dth place, arr has value %d.\n", i, arr[i]);
mean *= (float)i / (float)(i+1);
mean += arr[i] / (float)(i+1);
}
fclose(myFile);
printf("The overall mean of the %d values in the file is %f.\n\n", num, mean);
return 0;
}
Identifying there are 1000 values in the tab-delimited file.
Do not count tabs. Instead, read the ints. It's far too easy for the number of tabs to not relate correctly to the number of int.
Sum the int into a long long to avoid overflow. Use double for generic floating-point math.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *myFile = fopen("seal_weights.txt", "r");
if (myFile) {
int num = 0;
long long sum = 0;
int value;
// return 1 on success, EOF on end-of-file, else 0 on non-numeric input
while (fscanf(myFile, "%d", &value) == 1) {
sum += value;
num++;
}
double mean = num ? (double) sum / num : 0.0;
printf("The overall mean of the %d values in the file is %f.\n\n", num,
mean);
// read in again and save values if truly desired.
// This step not needed to compute average.
rewind(myFile);
int i;
int arr[num];
for (i = 0; i < num; i++) {
if (fscanf(myFile, "%d", &arr[i]) != 1) {
break;
}
}
// Use arr[] in some way.
fclose(myFile);
}
return 0;
}

Reading Rows and Columns from File in C

I am trying to read this input txt file with my C code:
4 3
1.4 4.6 1
1.6 6.65 1
7.8 1.45 0
7 -2 2
and separate them into rows and columns so that I can sort. I tried doing that but I kept getting weird numbers.
So I tried printing out the rows and columns after I read them from the file and the output was zero. I realized then that my code is not reading the numbers from my text file properly. I have tried different means to fix to no avail. Any help or pointers will be highly appreciated.
#include <stdio.h>
#include <string.h>
#include <stdbool.h> //for bool
int main(){
setvbuf(stdout, NULL,_IONBF, 0);
int c;
FILE *file;
FILE *infile;
char filename[99];
char choice;
int rows, columns;
//while(choice == 'y' || choice == 'Y'){
printf("%s", "Enter file name: ");
fgets(filename, 99, stdin);
char *p = strchr(filename, '\n'); // p will point to the newline in filename
if(p) *p = 0;
file = fopen(filename, "r");
if (file) {
while ((c = getc(file)) != EOF)
putchar(c);
fclose(file);
}
else{
puts("FILE NOT FOUND");
}
//read rows and columns from file
printf("%s","\n");
fscanf(file, "%d", &rows);
fscanf(file, "%d", &columns);
printf("%d", rows);
printf("%d", columns);
}
Problem 1
int rows = 0;
int columns = 0;
float matrix[rows][columns];
float sumOfRows[rows];
is not right.
After that, the number of elements in matrix and sumOfRows is fixed. They won't change if you change the values of rows and columns later in your program.
You need to read the values of rows and columns first before you define matrix and sumOfRows.
Problem 2
fscanf(file, "%d", &matrix[rows][columns]);
printf("%f",matrix[rows][columns]);
are not right either. Given the defition of matrix, use of matrix[rows][columns] is not right. They access the array using out of bounds indices.
Remember that given an array of size N, the valid indices are 0 to N-1.
Here's one way to proceed to resolve your problems:
fscanf(file, "%d", &rows); // Use %d, not %f
fscanf(file, "%d", &columns); // Use %d, not %f
// Now define the arrays.
float matrix[rows][columns];
float sumOfRows[rows];
// Read the data of matrix
for (int i = 0; i < rows; ++i )
{
for (int j = 0; j < columns; ++j )
{
fscanf(file, "%f", &matrix[i][j]); // Use %f, not %d
}
}
Your problem (actually, two problems) are in the if (file) {... block. First, you use a loop to read all characters from the file. Because of that, at the end of the loop you are also at the end of the file. Any further calls to fscanf result in undefined behavior.
Second, if the file did not open, you print a message (to the wrong output) and still continue to the fscanf part, which definitely leads to undefined behavior.
Solution: Remove the while loop and fix the error handling code:
if(file) {
// Nothing!
} else {
perror(filename);
return 1; // or return EXIT_FAILURE;
}

Reading array of integers from the first line of a text file and raising error if it exceeds 10

I've looked around and haven't seen this question answered yet. Basically I am trying to create an array of integers from text files that have sequences of integers e.g, 2 5 2 9 1 0 3 53 7 . I want to print an error message if line in the text file exceed 10 integers. There is only one line in the text file.
Here is my code so far:
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *file = fopen("somenumbers.txt", "r");
int integers[10];
int i=0;
int num;
if (file == NULL)
{
printf("Error Reading File\n");
exit (0);
}
while(fscanf(file, "%d", &num) > 0) {
integers[i] = num;
i++;
}
for (i = 0; i < 16; i++)
{
printf("Number is: %d\n\n", integers[i]);
}
fclose(file);
return 0;
}
Should I check the check the contents of the array after it is finished being created or during the initial iteration through the line? Are there any functions that would make it easy to determine if the line in the text file is larger than the limit(10)?
You must check in while loop as below;
while(fscanf(file, "%d", &num) > 0) {
if (i >= 10) {
printf("error\n");
break;
}
integers[i++] = num;
}
You should ensure that you never access integers[10], otherwise it's array out-of-bounds error which results in undefined behavior (i.e. literally anything can happen after that). So if you succeeded in reading 11-th number (which should go into integers[10]), you should stop the loop immediately.
The reason you are getting the error is the size of integers array being 10. Due to that size, if you read more than 10 integers, you will have a segment violation problem.
To find out that you have more than 10 integers, all you need to understand you should give an error is to read the 11th integer. So instead of declaring the array with size 10, switch it to 11. Then, when you read the 11th integer you may print an error message and exit properly.
Also, you may want to bound the loop printing the numbers by the amount of integers you have read.
Below is a sample code, based on yours, that implements the fixes I mentioned.
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *file = fopen("somenumbers.txt", "r");
int integers[11];
int i=0, k=0;
int num;
if (file == NULL)
{
printf("Error Reading File\n");
exit (0);
}
while(fscanf(file, "%d", &num) > 0) {
integers[i] = num;
if(k++ == 10) {
{
printf("Too many integers!!!\n"); /* or any other error message you'd like */
exit (0);
}
}
/* loop iterates until k integers are printed. k contains the # of integers read. */
for (i = 0; i < k; i++)
{
printf("Number is: %d\n\n", integers[i]);
}
fclose(file);
return 0;
}
Check before:
...
while (fscanf(file, "%d", &num) > 0) {
if (i >= 10) {
/* handle error */
break; /* or return */
}
...
to prevent trying to access an array element that does not exist
You have two errors:
1) When reading, you may write the input value outside the array boundary
2) When printing, you for sure acces outside array boundary.
Try this instead:
while(fscanf(file, "%d", &num) > 0) {
integers[i] = num;
i++;
if (i == 10)
{
break; // Can't store more value so stop the loop using break
}
}
// Save the number of values read
int total = i;
for (i = 0; i < total; i++)
// ^^^^ notice
{
printf("Number is: %d\n\n", integers[i]);
}
As an alternative to break you can put the check of i into the while condition like:
while(i < 10 && fscanf(file, "%d", &num) > 0) {
//^^^^^^ notice
integers[i] = num;
i++;
}
You have some issues with your code:
The code posted is prone to buffer overflow, as you are not checking if more than 10 integers have been found. This means you will be accessing outside the bounds of integers[10], which only causes undefined behavour.
Since you want to read one integer at a time with fscanf(), you should use:
while (fscanf(file, "%d", &num) == 1)
Instead of:
while(fscanf(file, "%d", &num) > 0)
fscanf() returns the number of values read, and using 1 instead of > 0 would make more sense in this case.
This segment here:
for (i = 0; i < 16; i++)
{
printf("Number is: %d\n\n", integers[i]);
}
is accessing beyond bounds of integers[10]. You need to change the guard so you don't exceed the limit of 10 integers.
Your code can look like this:
#include <stdio.h>
#include <stdlib.h>
#define MAXINT 10
int main(void) {
FILE *file;
int integers[MAXINT], num;
size_t count = 0;
file = fopen("somenumbers.txt", "r");
if (!file) {
fprintf(stderr, "%s\n", "Error reading file");
exit(EXIT_FAILURE);
}
while (fscanf(file, "%d", &num) == 1) {
if (count == MAXINT) {
printf("More than %d integers found!\n", MAXINT);
exit(EXIT_FAILURE);
}
integers[count++] = num;
}
printf("Success! No more than %d integers found:\n", MAXINT);
for (size_t i = 0; i < count; i++) {
printf("integers[%zu] = %d\n", i, integers[i]);
}
fclose(file);
return 0;
}

read a file and save as a matrix

i have a file like that :
1 100
2 200
3 300
4 400
1
i want to save it as a matrix and i want to save NULL if there is no second number !
i tried to write the program but it does not work correctly !
#include<stdio.h>
int main() {
int k=0 ,i,j , arr[100][100];
FILE *in= fopen("file.txt","r");
char line[1000];
while(fgets(line,1000,in) !=NULL) k++;
fgets(line,1000,in);
for (i=0;i<k;i++){
for (j=0;j<2;j++){
int tmp ;
fscanf(in ,"%d", &tmp) ;
arr[i][j] = tmp ;
}
}
fclose(in);
return 0; }
Two major problems:
The first is that the first loop will read all lines, even the one with the single number on the line. That means the lonely fgets call will not do anything, and more importantly that the value of k will be wrong.
The second problem is that once you read all data from the file, you don't go back to the beginning of the file, instead you continue to try and read from beyond the end of the file.
The first problem can be solve by skipping the second fgets call, and decreasing k by one.
The second problem can be solved by calling rewind after you counted the number of lines.
Also when you actually read the numbers, you don't need the inner loop, just do e.g.
scanf("%d %d", &arr[i][0], &arr[i][1]);
Actually, you don't need the first line-counting loop at all, you can do it all in a single loop, by using fgets and sscanf and then checking the return value of sscanf. So your program could look something like
#include <stdio.h>
int main(void)
{
int values[100][2];
FILE *input = fopen("file.txt", "r");
size_t entries = 0;
if (input != NULL)
{
char buffer[40];
while (fgets(buffer, sizeof(buffer), input) != NULL && entries < 100)
{
int res = sscanf(buffer, "%d %d", &values[entries][0], &values[entries][1]);
if (res <= 1 || res == EOF)
{
// Read the last line with only one number, or an error happened
values[entries][0] = 0;
values[entries][1] = 0;
break;
}
++entries;
}
if (ferror(input))
{
printf("Error reading file\n");
}
fclose(input);
}
// All done, the number of "records" or "entries" is in the variable entries
// Example code: print the values
for (size_t i = 0; i < entries; ++i)
printf("Line %d: %d %d\n", i + 1, values[i][0], values[i][1]);
return 0;
}

fscanf can't read the first integer of my file input in C but reads the rest

My program needs to read input from a file. The file has a format "int int int" and then some asterisks to indicate that you need to stop reading there. I want to store them in an array of struct and I did. But it seems like my program can't read the very first integer of the input file. I checked it with printf and I can't do anything about it. Help please. Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct points{
int i;
int x;
int y;
};
int main(){
int lines = 0;
char c, e;
int i, j, x ,y, a, b, temp ;
FILE *fp;
fp = fopen("input.txt", "r");
if (fp != NULL){
while ((e = fgetc(fp)) != '*'){
if (c == '\n'){
lines++;
}
fscanf(fp, "%d%d%d", &i, &x, &y);
struct points pt[lines];
for (j = 0; j <= lines; j++){
pt[j].i = i;
pt[j].x = x;
pt[j].y = y;
printf("%d ", pt[j].i);
}
for (a = 0; a<=lines; a++){
for (b = a + 1; b <= lines; b++){
if (pt[a].x > pt[b].x){
temp = pt[a].x;
pt[a].x = pt[b].x;
pt[b].x = temp;
}
}
}
}
}
else{
printf("Cannot open File!\n");
}
printf("lines = %d\n", lines);
return 0;
}
Your code:
while ((e = fgetc(fp)) != '*') {
if (c == '\n'){
lines++;
}
fscanf(fp, "%d%d%d", &i, &x, &y);
will read the first character and throw it away if it is NOT an asterisk, and will then attempt to read 3 integers AFTER that first character it threw away. If that first character was a digit, then it will look like you 'lost' (part of) the first number.
You also have the problem that you seem to be trying to read the values into a block-local array pt that exists for a single iteration of the while loop (so its recreated with no (garbage) contents each iteration), and then you want to use it after the loop where it is out of scope (so this code won't compile).
What you want is probably something more like:
#define MAX_POINTS 100
struct points pt[MAX_POINTS];
int i = 0;
while (i < MAX_POINTS && 3 == fscanf(fp, "%d%d%d", &pt[i].i, &pt[i].x, &pt[i].y)) {
printf("%d ", pt[i].i);
i++;
}
for (int a = 0; a <= i; a++) {
for (int b = a+1; b <= i; b++) {
:
Note that this reads integers up until it finds something that doesn't look like an integer (such as an asterisk, but could be anything else, including an end-of-file), rather than reading until it finds an asterisk. If you want to read until you see an asterisk, you need to decide what to do with anything that is neither an asterisk or an integer.
Edit
for your alternate question of how to read numbers up to *** and then read more numbers after them (and possibly more stars), you could use something like:
int val;
char buffer[20];
do {
/* start of a group */
while (1 == fscanf(fp, "%d", &val)) {
/* read an integer within a group */
}
/* fp is at EOF or something not an integer. */
/* so read it and loop if its '***' */
} while (1 == fscanf(" %19[*]", &buf) && !strcmp(buf, "***"));
Have you tried using the format string "%d %d %d" instead of "%d%d%d" (i.e. with spaces)?
Also, there are several other problems I see:
You use a while loop to find the first '*' in the line, but then you ask fscanf to parse 3 ints starting at that location. It may not be able to find an int by looking at a '*'...
You also declare the variable struct points pt[lines]; in the middle of a block; that is not valid C syntax.
Once you fix these things, the problem may be fixed.

Resources