handling trailing \n when using feof() - c

I have written a small program which takes input of a file such as:
13,22,13,14,31,22, 3, 1,12,10
11, 4,23, 7, 5, 1, 9,33,11,10
40,19,17,23, 2,43,35,21, 4,34
30,25,16,12,11, 9,87,45, 3, 1
1,2,3,4,5,6,7,8,9,10
and outputs the largest sum of numbers on each line that is less than 50.
However if the inputted file has a trailing newline character the loop runs one too many times and hence another line is added to the array with random data. So I'm looking for a better way to do this comparison to avoid this issue. I'm also assuming all lines have 10 integers on at the moment as i cannot think of a better way to do the end of line loop comparison.
#include <stdio.h>
#include <stdlib.h>
void readLineData(int lineNo, int val[][10], FILE *fp);
int findSum(int lineNo, int val[][10], FILE *fp);
int main(int argc, char *argv[]) {
FILE *fp;
int val[5][10];
// Open file.
if ((fp = fopen(argv[1], "r")) == NULL)
{
perror("Cannot open file ");
exit(EXIT_FAILURE);
}
for (int i = 0; !feof(fp); i++) // runs too many times if file ends with '\n'
{
readLineData(i, val, fp);
printf("%d\n", findSum(i, val, fp));
}
fclose(fp);
return EXIT_SUCCESS;
}
void readLineData(int lineNo, int val[][10], FILE *fp) {
char c;
for (int i = 0; i < 10; i++) // assuming line contains 10 integers
{
fscanf(fp, "%d,", &val[lineNo][i]);
}
}
int findSum(int lineNo, int val[][10], FILE *fp) {
int highVal = 0;
int value1 = 0;
int value2 = 0;
for(int i = 0; i < 10; i++) //each letter
{
for(int j = 0; j < 10; j++)// every other letter
{
if((val[lineNo][i] + val[lineNo][j]) > highVal && i != j && (val[lineNo][i] + val[lineNo][j]) <= 50)
{
highVal = val[lineNo][i] + val[lineNo][j];
value1 = val[lineNo][i];
value2 = val[lineNo][j];
}
}
}
printf("Line %d: largest pair is %d and %d, with a total of: ", lineNo+1, value1, value2);
return highVal;
}
any help with those loop comparisons and general notation tips is most welcome.
Thanks

The posted code does not distinguish between two lines that have five integers and (the expected) one line that has 10 integers. Suggest reading in a line at a time, using fgets() and then using sscanf() on the read line to ensure that all the read integers belong to the same line.
Check the return value of input operations. For example, sscanf() (and fscanf()) return the number of assignments made. Only process lines that have the expected 10 integers, which would detect invalid lines including the trailing empty line.
For example:
/* Returns 1 on success and 0 on failure. */
int readLineData(int lineNo, int val[][10], FILE *fp)
{
char line[1024]; /* Arbitrarily large. */
if (fgets(line, sizeof(line), fp))
{
/* %n records position where processing ended. */
int pos;
const int result = sscanf(line,
"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n",
&val[lineNo][0],
&val[lineNo][1],
&val[lineNo][2],
&val[lineNo][3],
&val[lineNo][4],
&val[lineNo][5],
&val[lineNo][6],
&val[lineNo][7],
&val[lineNo][8],
&val[lineNo][9],
&pos);
/* 10 integers and full line processed,
except if new-line character present. */
return 10 == result &&
(pos == strlen(line) ||
(pos + 1 == strlen(line) && '\n' == line[pos]));
}
return 0;
}

You could simply consume the newline character yourself:
for (int i = 0; !feof(fp); i++) // runs too many times if file ends with '\n'
{
readLineData(i, val, fp);
printf("%d\n", findSum(i, val, fp));
fscanf(fp, "%*c"); // read a character without storing it in a variable
}
Note that there are undoubtedly better ways that involve reading an entire line at once and simply examining its contents; but this is the easiest way that will fit with what you already have.

you could check if fscanf fails in your readLineData function:
int readLineData(int lineNo, int val[][10], FILE *fp) {
for (int i = 0; i < 10; i++) {// assuming line contains 10 integers
if (fscanf(fp, "%d,", &val[lineNo][i]) != 1) {
return 1;
}
}
return 0;
}

Related

How to resolve this problem relevant File and Null in C?

So I need output size of array in this file text and to do this I must break the loop in the last position by using NULL to break but the problem here that when arr[i] come to value 0, it equal to NULL and break at that position so my size of array is not complete. How to resolve it? Thanks for support!
The file .txt input:
3
4
0
5
6
The code:
#include <stdio.h>
int main() {
char a[20];
char e[40];
int arr[30];
int num, key, k = 0, len = 0;
printf("Enter a filename: ");
scanf("%s", &a);
scanf("%c", &e);
FILE* rfile;
rfile = fopen(a, "r");
if (rfile == NULL) {
printf("Not found the file !!!");
}
else {
printf("Successfully accessed the file: %s\n", a);
int i;
for (i = 0; i < 30; i++) {
fscanf(rfile, "%d", &arr[i]);
fscanf(rfile, "%c", &e);
if (arr[i] == NULL) { // PROBLEM HERE
break;
}
len++;
}
}
printf("The size of array: %d", len);
return 0;
}
You can find some more details regarding what NULL is here, but you should save NULL for pointer comparisons, not comparing against ints as you are doing. In fact, your usage generates a warning:
warning: comparison between pointer and integer
Despite that, 0 == NULL will evaluate to true. Since 0 is in your list of values, you prematurely break revealing your problem. Instead, you simply need to read the entire file, either until you run out of room in your array (already covered by your for loop) or reach the end of the file (designated by EOF). To determine that, you need to check the return value of fscanf. Below is an example of a possible implementation:
#include <stdio.h>
#include <stdlib.h>
int main() {
int arr[30];
int len = 0;
FILE* rfile;
rfile = fopen("file.txt", "r");
if (rfile == NULL) {
printf("Not found the file !!!");
exit(-1);
}
else {
int i;
for (i = 0; i < 30; i++) {
// fscanf returns the number of correctly matched items, or
// EOF when the end of the file is reached (or EOF on error)
int ret = fscanf(rfile, "%d", &arr[i]);
// did we get a correct match?
if (ret == 1)
{
// we matched one number as expected, increment len
len++;
}
// did we reach the end of file?
else if (ret == EOF)
{
// EOF can also indicate an error, check errno here to determine if
// an error occurred instead of end of file, if you want
break;
}
}
}
// prints 5 with your input file example
printf("The size of array: %d\n", len);
return 0;
}
I have no idea what you were trying to accomplish with e, so I removed that as well as other unused variables, and hardcoded user input.
arr is the array of ints arr[i] has type int. NULL is a pointer.
If 0 indicated the end of the data (sentinel value) then:
if (arr[i] == 0) break;
or in a short form
if (!arr[i]) break;

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.

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

Why is this array script not printing right results?

I have a textfile of numbers written in words, with spaces between like..
zero three five two one .. etc there are 3018 words in total.
This is my code:
#include <stdio.h>
int main(void)
{
int i = 0;
int d = 0;
int j = 0;
char array[9054][5];
char hi[9054];
FILE *in_file;
in_file = fopen("message.txt", "r");
while (!feof(in_file))
{
fscanf(in_file, "%s", array[i]);
i++;
}
printf(array[9049]);
while (1);
return 0;
}
so the 9049th worth in my textfile is the number three.. but when I run this script, it prints "threethreezero"instead?? i thought the fscanf ignored whitespace (spaces) so why does accept another three and zero into this string?
OP figured things out with the help of comments, so here is a cumulative fix.
#include <stdio.h>
int main(void)
{
int i = 0;
int d = 0;
int j = 0;
// Make room for the null character
char array[9054][5+1];
char hi[9054];
FILE *in_file;
in_file = fopen("message.txt", "r");
//check `fscanf()`'s return value rather than using feof()
// Limit input put with 5
while (fscanf(in_file, "%5s", array[i]) == 1);
i++;
}
// Check that code read enough input
if (i >= 9049) {
// Do not use `printf()` on uncontrolled strings that may contain %
fputs(array[9049], stdout);
} else {
puts("Oops");
}
while (1);
return 0;
}

show character ASCII code and number of appearance

I want to make a program which reads the text from a file and shows every character, the ASCI code of each one and the number of occurrences.
I wrote this but it doesn't show the occurrences.
#include <stdio.h>
#include <stdlib.h>
int main ()
{
FILE * pFile;
int i=0;
int j=0;
char text[j];
int ascii[256];
int occ[256];
int occurance=0;
int position;
pFile = fopen ("c:/1.in","r");
if (pFile==NULL) perror ("Error opening file");
else
{
while (!feof(pFile)) {
j++;
text[j]=getc (pFile);
ascii[j]= (int) text[j];
position=ascii[j];
occ[position]++;
}
for (i=1;i<j;i++){
occurance=position[i]
printf ("Chracter %c has ascii %d and occurs %d times \n", text[i],ascii[i],occ[occurance] );}
}
system("PAUSE");
return 0;
}
First, I don't see the point in this:
int j=0;
char text[j];
If you want to put every character in the file into an array then read the size of the file and malloc() the correct size to a pointer. But why do that anyway? If you're trying to count ever occurrence of ever character then just keep track of the possibilities.
For completeness you can use an array of 256 characters, but in reality if you're just looking at standard printable characters there should only be about 94.
This:
int main ()
{
int temp = 0, i;
int occ[256] = {0};
FILE * pFile = fopen("test.txt", "r");
if (pFile == NULL) perror("Error opening file");
else {
while (!feof(pFile)) {
temp = getc(pFile);
if((temp < 255) && (temp >= 0))
occ[temp]++;
}
}
//reads every character in the file and stores it in the array, then:
for(i = 0; i<sizeof(occ)/sizeof(int); i++){
if(occ[i] > 0)
printf(" Char %c (ASCII %#x) was seen %d times\n", i, i, occ[i]);
}
return 0;
}
will print every character, the ASCII code (in hex) and the number of times it showed.
An example input file of:
fdsafcesac3sea
yeilds an output of:
Char 3 (ASCII 0x33) was seen 1 times
Char a (ASCII 0x61) was seen 3 times
Char c (ASCII 0x63) was seen 2 times
Char d (ASCII 0x64) was seen 1 times
Char e (ASCII 0x65) was seen 2 times
Char f (ASCII 0x66) was seen 2 times
Char s (ASCII 0x73) was seen 3 times
Below simple logic works fine for me. Add file operations to get the buf.
int main()
{
char buf[] = "abcaabde";
char val[256] = {0};
int i = 0;
for (i = 0; i < sizeof(buf); i++)
{
val[buf[i]]++;
}
for (i = 0; i < 256; i++)
{
if (val[i] != 0)
{
printf("%c occured %d times\n", i, val[i]);
}
}
return 0;
}
Output is
occured 1 times
a occured 3 times
b occured 2 times
c occured 1 times
d occured 1 times
e occured 1 times

Resources