Using fscanf *after* fgetc issue - c

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;
}

Related

I want to read data from a file which contains integers and floats

I want to read in data from a file (using C) which contains integers and floats, but I only want to put the floats into an array. I am having trouble with figuring out how to avoid the integers.
This is an example of a data set:
2019 001 3.55 4.63 3.14 4.56 4.21 2.33
2019 002 4.58 5.94 6.16 7.28 8.61 9.91
I hope that your question distinguishes between an int and float as whether or not the number should contain a decimal point. Otherwise, all ints can be floats as well. Therefore, I assume that 123 is not a float and neither is 123.000.
Having said that, a clever solution would be to read all the numbers as floats. While reading the data from the file, assign the number to an int variable. Then you can add that number to your array if that number cannot be contained by an int.
For example,
float input = 123.45;
int n = input; // n is 123
// If input cannot be shaped to an int
if (n != input)
addToArray(input);
Now, it's just a matter of implementing this logic:
#include <stdio.h>
#include <stdlib.h>
// Change this according to your requirements
#define INPUT_FILE "data_set.txt"
#define ARRAY_SIZE 100
int main()
{
float arr[ARRAY_SIZE];
float data;
int n;
int i = 0;
FILE* input_file = fopen("data_set.txt", "r");
if (!input_file)
{
printf("ERROR: Could not open the file!");
exit(EXIT_FAILURE);
}
while (fscanf(input_file, "%f", &data) != EOF)
{
// Truncate the number to an integer
n = data;
// Take the number if it cannot be an integer
if (n != data)
{
arr[i] = data;
++i;
}
}
// Display the output and check the result
n = i;
for (i = 0; i < n; ++i)
printf(" %g", arr[i]);
fclose(input_file);
return 0;
}
If the number of elements in the data set is unknown, use a dynamic array.
A fun solution would be to read all input as float, cast them to int and compare the two variables for equality. If not equal, some rounding means that it is a float, else it is an int.
Remember that float variables are not accurate representation so you might want to add an appropriate threshold to the comparison that fits your usecase.
#include <stdio.h>
int main(void) {
FILE *myFile;
myFile = fopen("test.txt", "r");
float numberArray[16];
int i;
for (i = 0; i < 16; i++)
{
fscanf(myFile, "%f", &numberArray[i]);
}
for (i = 0; i < 16; i++)
{
int temp = (int)numberArray[i];
if( numberArray[i] != temp ){
printf("Float: %f\n\n", numberArray[i]);
}
else{
printf("Int: %d\n\n", temp);
}
}
}

Reading and storing values from csv file in an array using C

#include <stdio.h>
#include <stdlib.h>
int main() {
int c1[100];
char c2[150];
char c3[100];
float c4[100];
float c5[100];
float c6[100];
float c7[100];
char c8[100];
char c9[100];
float c10[100];
char string[10][100];
int i, j;
char c;
FILE *fp1;
fp1 = fopen("sample.csv", "r");
while (1) {
c = fgetc(fp1);
if (c == EOF)
break;
else
printf("%c", c);
}
for (i = 1; i <= 10; i++) {
fscanf(fp1, "%d,%[^,],%[^,],%[^,],%[^,],%d,%d",
&c1[i], &c2[i], &c3[i], &c4[i], &c5[i],
&c6[i], &c7[i], &c8[i], &c9[i], &c10[i]);
}
for (j = 0; j <= 10; j++) {
printf("\n");
printf("%d", c3); //Here i am trying to read the column3 values but getting random integer values.
//This problem continues to every column
}
return 0;
}
I have to read file sample.csv and store values into the array so that I can perform operation on that values.
I am not getting the exact value from the csv file that I have read.
I am getting some random integer value on running the program.
There are many problems in your code:
you do not check if fopen() succeeded.
c must be defined as int for proper end of file testing
you must rewind the file with rewind(fp1); or fseek(fp1, 0L, SEEK_SET); before reparsing the contents with fscanf()
the loop index i must start at 0 instead of 1, because arrays are 0 based.
it is idiomatic in C to use for (i = 0; i < 10; i++) ... to handle 10 lines of input. i <= 10 would iterate 11 times.
you must check the return value of fscanf() to ensure the input stream has the expected format. The format string does not handle empty text fields.
the fscanf() format string is incompatible with the arguments provided
the printf format string "%d\n" in incompatible with the type of the argument: the argument is the array c3 which is passed as a pointer to its first member, not an int as expected.
Simply read a line in a loop until there are no more lines
#include <stdio.h>
#include <string.h>
#define MAX_ITEMS 10000
#define LARGEST_LINE 1000
#define LARGEST_ELEMENT 100
int main(void) {
int c1[MAX_ITEMS];
char c2[MAX_ITEMS][LARGEST_ELEMENT+1]; // large enough for each `c2`
char c3[MAX_ITEMS][LARGEST_ELEMENT+1];
char c4[MAX_ITEMS][LARGEST_ELEMENT+1];
char c5[MAX_ITEMS][LARGEST_ELEMENT+1];
int c6[MAX_ITEMS];
int c7[MAX_ITEMS];
int tmpc1;
char tmpc2[LARGEST_ELEMENT+1];
char tmpc3[LARGEST_ELEMENT+1];
char tmpc4[LARGEST_ELEMENT+1];
char tmpc5[LARGEST_ELEMENT+1];
int tmpc6;
int tmpc7;
int lineno = 0;
char buf[LARGEST_LINE]; // large enough for the largest line
while (fgets(buf, sizeof buf, fp1)) {
++lineno;
// no error, process line
if (sscanf(buf, "%d,"
"%" LARGEST_ELEMENT "[^,],"
"%" LARGEST_ELEMENT "[^,],"
"%" LARGEST_ELEMENT "[^,],"
"%" LARGEST_ELEMENT "[^,],"
"%d,%d",
&tmpd1, tmpc2, tmpc3, tmpc4, tmpc5, &tmpd6, &tmpd7) == 7) {
// line ok, copy tmp variables and update indexes
c1[i] = tmpd1;
strcpy(c2[i], tmpc2);
strcpy(c3[i], tmpc3);
strcpy(c4[i], tmpc4);
strcpy(c5[i], tmpc5);
c6[i] = tmpd6;
c7[i] = tmpd7;
i++;
} else {
// line with error, you may want to report to the user
fprintf(stderr, "line %d with error.\n", lineno);
}
}
// read "error", probably EOF; close file and report
fclose(fp1);
for (int j = 0; j < i; j++) {
printf("item #%d: %d, %s-%s-%s-%s, %d %d\n",
c1[j], c2[j], c3[j], c4[j], c5[j], c6[j], c7[j]);
}
return 0;
}
Also consider putting all those c arrays inside a struct and make 1 single array of that structure.

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;
}

C Programming: Error in program. Won't show Max/Min/Average of files inputted by user

I'm attempting to create a code that the user inputs a filename and the program will then find the Min, Max, and Average of the numbers in the file.
This is a sample of a file the user would input into the program (the # are comments and would be ignored):
#Data from field experiment 312A
#2015-01-12
35.6
3.75
#2015-01-13
9
#2015-01-14
43.43
7.0001
And this is what I have for my code for the moment, I tried combining different methods, but fear I am just too lost at this point.
#include <stdio.h>
#include <math.h>
int main()
{
char ch, file_name[25];
FILE *fp;
double average, num = 0, min = 0, max = 0, sum = 0, N;
int i;
printf("Please enter the name of the file to load:\n");
scanf(file_name);
fp = fopen(file_name, "r");
if (fscanf(fp, "%lf", &N) == 1)
{
for (i = 0; i < N; i++)
if (num < min || i == 0)
min = num;
if (num > max || i == 0)
max = num;
sum += num;
}
fclose(fp);
average = sum/N;
printf("Smallest: %7.2lf\n", min);
printf("Largest: %7.2lf\n", max);
printf("Average: %7.2lf\n", average);
return(0);
}
Any help would be appreciated.
In your code,
scanf(file_name);
is wrong usage of scanf(), you're missing a format specifier. You have to change that to
scanf("%24s", file_name); //%s is the format specifier for a string input
Check the man page for more details.
Apart from that, there are logical errors in your program. You're reading the file only once, which is not what you want. Also, there is no meaning of the for() loop.
My advice will be:
Open the file, then check for success of foepn(). Otherwise, don't procceed.
Read a whole line using fgets().
Convert the input string to float using strtod().
If conversion success, check for < min and > max, change accordingly, and sum the result.
Otherwise, if conversion fails, it is a comment, ignore that line.
Continue untill fgets() returns NULL (erach end of the file)
Calculate the average based on sum / (number of successful conversions)
Print the sum, max and min.
Close the file.
That said, the recommended signature of main() is int main(void).
EDIT:
A pseudo-code (as requested for better understanding)
#include <stdio.h>
#include <math.h>
#include <float.h>
int main(void)
{
char file_name[25] = {0};
FILE *fp = NULL;;
double average = 0, min = DBL_MAX, max = 0, sum = 0;
int N = 0;
char buf[128] = {0}; // buffer tyo be used with fgets()
ask for the filename (using `scanf("%24s", file_name);`)
open the file (using `fp = fopen(file_name, "r");`)
if file cannot be opened successfully (`if (!fp)`)
exit
while (reading a complete line from file using `fgets(buf, 128, fp)` != EOF) //EOF ==> end of file
{
if (buf[0] == `#`) //comment, no propcessing reqd, continue
continue;
val = strtod(buf, NULL); //you should use proper error checking, as metioned in the man page
if (val) // valid float value found
{
if ( val < min )
min = val;
else if ( val > max )
max = val;
sum += val; //add the value
N++; //increase the counter
}
}
close the file (using `fclose(fp);`)
calculate `average = sum/N;`
printf("Smallest: %7.2f\n", min);
printf("Largest: %7.2f\n", max);
printf("Average: %7.2f\n", average);
return(0);
}
You should initialize min with a very large number.
Your if needs {} otherwise the code executes other than you think.
before you calculate sum/N you should check N>0.
Your combination of fscanf and for does not work this way.

how to read from text file and store in matrix in c

the first to say is that I'm totally new to coding, so plz forgive my mistakes.
I'm now trying to read from a txt file which is rather large, it has about 1000000 lines and 4 cols
56.154 59.365 98.3333 20.11125
98.54 69.3645 52.3333 69.876
76.154 29.365 34.3333 75.114
37.154 57.365 7.0 24.768
........
........
I want to read them all and store them into a matrix, here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
int main()
{
int i;
int j;
/*matrix*/
int** mat=malloc(1000000*sizeof(int));
for(i=0;i<1000000;++i)
mat[i]=malloc(4*sizeof(int));
FILE *file;
file=fopen("12345.txt", "r");
for(i = 0; i < 1000; i++)
{
for(j = 0; j < 4; j++)
{
if (!fscanf(file, " %c", &mat[i][j]))
break;
mat[i][j] -= '0'; /* I found it from internet but it doesn't work*/
printf("\n",mat[i][j]);
}
}
fclose(file);
}
The result is that I got nothing in my matrix. I hope u can help. Thanks in advance for any help.
Many Issues, consider following, and of course see comments
int main()
{
int i;
int j;
/*matrix*/
/*Use double , you have floating numbers not int*/
double** mat=malloc(1000000*sizeof(double*));
for(i=0;i<1000000;++i)
mat[i]=malloc(4*sizeof(double));
FILE *file;
file=fopen("1234.txt", "r");
for(i = 0; i < 1000; i++)
{
for(j = 0; j < 4; j++)
{
//Use lf format specifier, %c is for character
if (!fscanf(file, "%lf", &mat[i][j]))
break;
// mat[i][j] -= '0';
printf("%lf\n",mat[i][j]); //Use lf format specifier, \n is for new line
}
}
fclose(file);
}
fscanf( "%c", ... ) only scans one single character (e.g. '5'). By subtracting '0' you get the integer value 5 from the character '5'. You can use "%d" to scan integers that consist only of digits (not including formatting characters), or "%f" for floats (not sure if 56.154 is to be read as "56 thousand 154" (continental europe) or "56 plus 154/1000" (GB / USA) (the rest of the world: don't be offended I just don't know)
printf( "\n", ... ): you forgot to use any formatting string such as %d (int), %f (float) ... So your parameter will not be printed, just the newline itself.
int** mat=malloc(1000000*sizeof(int)); You're allocating an array of int * here, so it should be int** mat=malloc(1000000*sizeof(int *));
Edit: I've looked again at your text file and have seen numbers like 98.54 that can't be formatted integers. So it's quite clear you will need float or double instead if int for your array and use "%f" for float or "%lf" for double in both fscanf() and printf()
You have a couple of things wrong with your code here.
First off you create a matrix of int yet you are reading in float values it looks like. You probably want to use double
Second, when you are reading a double you should use
fscanf(file, "%lf", &some_double); // fscanf(file, "%d", &some_int); for integers
Also when you are allocating your matrix, your first malloc you should pass
sizeof(double *) // or int * if you are really trying to use integers
Finally your line that does:
mat[i][j] -= '0'
What are you trying to accomplish here? You're taking the int that you (tried) to read in and subtracting off '0'...
Edit I also notice that you are hard coding the number of lines you are reading, I wouldn't do that unless you know the format of the file.

Resources