Can't get txt file to print correctly - c

This is a homework assignment for my C Programming class.
I am given a text file, with two data columns; the first column is the age; the second column is the avgprice. I'm able to read and print the values fine. However, for some reason the age and avgprice are flipped in the output. I have no clue why.
Here is the code
#include "stdafx.h"
#include <stdio.h>
int main() {
double age, avgprice; //age = 1st column, avgprice = 2nd column
FILE *corolla; //ptr for file
char eof; //needed for end of file check
corolla = fopen("C:/Users/Nate/Downloads/DataFiles/corolla.txt", "r");
if (corolla == NULL) { //makes sure the file exists
printf("File does not exist!\n");
return 0; //prevents crashing
}
else {
printf("Age \t\t Average Price\n"); //header for data when printed
/*prints values until we're at the end of the file*/
while (fscanf(corolla, "%c", &eof) != EOF) {
fscanf(corolla, "%lf %lf", &age, &avgprice); //scans in data from file
printf("%.1f \t\t $%.2f\n", age, avgprice); //prints data from file
}
}
fclose(corolla); //closes file
return 0;
}
This is what the output looks like
It's puzzling to me because I have used this exact format to do the same thing with other data files--no issues. For some reason, this one file is having difficulty.
Here is the datafile I'm supposed to be reading. I've uploaded it to my Dropbox that way you can inspect the formatting if necessary. Corolla.txt

This line:
while (fscanf(corolla, "%c", &eof) != EOF)
reads a character from the file. The first character in the file is 1 so it reads that 1 into eof.
Your next line is:
fscanf(corolla, "%lf %lf", &age, &avgprice);
which reads the next two entries from the file, which are 13990 and 2, in that order. So the first age is 13990 and the first avgprice is 2.
After that, the file pointer is now pointing to the blank space after the 2. When you go:
fscanf(corolla, "%c", &eof)
it reads a space into eof.
Then when you get to:
fscanf(corolla, "%lf %lf", &age, &avgprice);
It reads the next two values, 13495 and 3 respectively. And so on.
To fix this you should stop doing fscanf(corolla, "%c", &eof). I don't know what you are expecting this to do exactly , but it does not test whether you're at the end of the file or not. Instead it reads a character, ignores the character, and checks the return value of fscanf.
To fix your code:
while (2 == fscanf(corolla, "%lf %lf", &age, &avgprice))
{
printf("%.1f \t\t $%.2f\n", age, avgprice); //prints data from file
}
The return value of fscanf is the number of items successfully read (if it succeeded). When it returns something other than 2 you know you must have hit the end of the file.

Your input file uses a line-based format. fscanf reads the input chunk by chunk. A chunk is usually something separated by white space, which can be space, tabs or even the new-line. Therefore fscanf is not suited to read line-based formats.
In my opinion, it is better to read the input in two steps: first, read a line with fgets, then read the data from that line with sscanf. For example:
#include <stdlib.h>
#include <stdio.h>
int main()
{
FILE *f;
int line = 0;
f = fopen("kk", "r");
if (f == NULL) {
printf("File does not exist!\n");
return 0;
}
printf("%20s%20s\n", "age", "avg. price ($)");
for (;;) {
char buffer[80];
int age, price;
if (fgets(buffer, sizeof(buffer), f) == NULL) break;
line++;
if (sscanf(buffer, "%d %d", &age, &price) < 2) {
printf("(Skipping bad input in line %d).\n", line);
} else {
printf("%20d%20d\n", age, price);
}
}
fclose(f);
return 0;
}
This also gives you a kind of low-level error reporting.
Also, there's usually no need to do extra checking for EOF. The file input functions return a special value when the end of the file is reached. fscanf and getc return EOF; fgets returns NULL. It is usually always better to stop reading based on these return values.
In your case, the fscanf("%c", &oef) eats up the first character in your file, the digit 1. Luckily, after that it only feeds on new-line so your input doesn't get tripped up worse. (But change your scan format to "%lf %lf " for a drastic price reduction.)

Related

get 3 (max) digit integer from txt file

First of all I am new to files in c, so it may be a simple question,
however I still didn't find a solution:
let's say that's the content of my file:
99
blah blah
...
...
I want to scan only the number from the beginning (it is always in a separate line)
My question is how to make it take the number (99) as one number and stop scanning.
int main(){
FILE* fp = fopen(file_name, "r");
int integer;
...
fclose(fp);
printf("%d", integer);
}
output for the file example:
99
-the nuber can be between 1 and 100-
I want to scan only the number from the beginning (it is always in a separate line).
That's a good hint, suggesting a line by line parsing of the input. You can use a combination of fgets(1) and sscan(2) to read that number.
fgets will read up to a certain number of character from a stream and store those character into a buffer. If it finds a newline, it stops reading, store the newline into the buffer followed by the null-terminator. Otherwise it only adds the terminator. If it fails, it returs a NULL pointer.
sscanf works basically like scanf or fscanf, but it reads from a character array, not from a stream.
It's also better to always check the return value of those library function.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUF_SIZE 1024
int main(void)
{
char const *file_name = "data.txt";
FILE *in_file = fopen(file_name, "r");
if (!in_file) {
fprintf(stderr, "Error while reading \"%s\": %s", file_name, strerror(errno));
return EXIT_FAILURE;
}
char buffer[BUF_SIZE];
int number = 0;
while( fgets(buffer, BUF_SIZE, in_file) ) {
if ( sscanf(buffer, "%d", &number) == 1 ) {
if ( 0 < number && number < 100 ) {
printf("%d", number);
break;
}
}
}
fclose(in_file);
return EXIT_SUCCESS;
}
Example.
Some references of the functions used in the previous snippet
1) fgets: man-pages or cppreference.
2) sscanf: man-pages or cppreference
Why not use scanf? (fscanf to be more precise):
On success, the function returns the number of items of the argument
list successfully filled.
(source: cppreference)
So just check how many values did you read, if 0 that means it's not a number so you can just skip that string, for that you can use "%*" prefix to ignore the data.
You also said:
I want to scan only the number from the beginning (it is always in a
separate line)
so after you read the number just skip the whole line with "%*[^\n]" (reads
data until a new line symbol is encountered)
int num;
int scanReturn;
FILE* f = fopen("file.txt", "r");
...
do {
scanReturn = fscanf(f, "%d", &num);
if(scanReturn == 0)
{
scanReturn = fscanf(f, "%*s");
}
else if(scanReturn != EOF)
{
fscanf(f, "%*[^\n]");
printf("%d, ", num);
}
} while(scanReturn != EOF);
fclose(f);

After reading from text file, results are displayed incorrectly

I've written a program that reads four variables (three strings and one character) every line from a text file. But when I display the variables, an unexpected character pops up at the end of each line. (I've ensured that the lengths of the variables are large enough).
Why is this? (Overflowing buffers, again?) And how do I fix this?
Text file contents:
M0001 Cool Name F 123-456789
M0002 Name Cool M 987-654321
Code:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *text;
char id[6], name[101], gender, contact[13];
text = fopen("test.txt", "r");
while (fscanf(text, "%s %[^\n]s %c %s\n", id, name, &gender, contact) != EOF)
printf("%s %s %c %s\n", id, name, gender, contact);
fclose(text);
return 0;
}
The output I expect:
M0001 Cool Name F 123-456789
M0002 Name Cool M 987-654321
What I get instead:
M0001 Cool Name F 123-456789 1⁄4
M0002 Name Cool M 987-654321 1⁄4
in the call to fscanf(), the format string: "%s %[^\n]s %c %s\n" is not correct.
the '[^\n]' will read to the end of the line (which will overflow the input buffer: `name'. Then the next char is NOT an 's' because the next character is the newline.
should compare the returned value to 4, not EOF
the input/format specifiers '%[...]' and '%s' have no problem overflowing the input buffer, so should ALWAYS have a MAX_CHARACTERS modifier that is one less than the length of the input buffer (those format specifiers always append a NUL byte to the input
The following proposed code:
cleanly compiles
documents why each header file is included
performs the desired functionality
splits the 'name' into 'firstname' and 'lastname' for easier handling and to match the format of the input data
properly checks the returned value from fscanf()
properly checks for any error from fopen() and if an error is returned, properly outputs the error message and the text indicating why the system thinks the function failed to stderr
uses an appropriate format string for the calls to fscanf() and printf()
replaces 'magic' numbers with meaningful names via a enum statement
And now the proposed code:
#include <stdio.h> // fopen(), fclose(), fscanf(), perror(), printf()
#include <stdlib.h> // exit(), EXIT_FAILURE
enum{
MAX_ID_LEN = 6,
MAX_NAME_LEN = 20,
MAX_CONTACT_LEN = 13
};
int main( void )
{
char id[ MAX_ID_LEN ];
char firstname[ MAX_NAME_LEN ];
char lastname[ MAX_NAME_LEN ];
char gender;
char contact[ MAX_CONTACT_LEN ];
FILE *text = fopen("test.txt", "r");
if( !text )
{
perror( "fopen to read 'test.txt' failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
while (5 == fscanf(text, "%5s %19s %19s %c %12s",
id, firstname, lastname, &gender, contact) )
{
printf("%s %s %s %c %s\n",
id, firstname, lastname, gender, contact);
}
fclose(text);
return 0;
}
%[^\n]s eats up everything from that point on and puts it in name. So only id and name are filled. gender and contact have 'random' contents coming from the program stack (as they are not initialized).
By accident the your stack had 1/4 in gender + contact.
On my machine, the program crashes.
As the number of space-delimited words in your name apparently is variable, you can only use %[^\n]s to grab "as much as possible" – but that will also eat up any and all following relevant data. A quick solution would be to re-design the input format and place the name at the very end; then, your fscanf argument would be:
"%s %c %s %s\n", id, &gender, contact, name
Alternatively, rewrite the code to use less fscanf and more 'manual' parsing:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main (void)
{
FILE *text;
char id[6], name[101], gender, contact[13];
char *lookback;
int result;
unsigned int line_number = 0;
text = fopen ("test.txt", "r");
if (text == NULL)
{
printf ("file not found!\n");
return EXIT_FAILURE;
}
do
{
result = fscanf(text, "%s %[^\n]s\n", id, name);
line_number++;
if (result == EOF)
break;
if (result != 2)
{
printf ("error in data file on line %u (expected at least 2 items)\n", line_number);
break;
}
/* at this point, 'name' also contains 'gender' and 'contact' */
lookback = strrchr (name, ' ');
if (lookback == NULL || strlen(lookback+1) > 12)
{
printf ("error in data file on line %u (expected 'contact')\n", line_number);
break;
}
/* lookback+1 because lookback itself points to the space */
strcpy (contact, lookback+1);
/* cut off at lookback */
*lookback = 0;
lookback = strrchr (name, ' ');
if (lookback == NULL || strlen(lookback+1) != 1)
{
printf ("error in data file on line %u (expected 'gender')\n", line_number);
break;
}
/* lookback now points to the space before the gender */
gender = toupper(lookback[1]);
if (gender != 'F' && gender != 'M')
{
printf ("error in data file on line %u (expected 'M' or 'F')\n", line_number);
break;
}
/* cut off again at lookback; now name is complete */
*lookback = 0;
printf ("%s %s %c %s\n", id, name, gender, contact);
} while (1);
fclose(text);
return EXIT_SUCCESS;
}
This method does have a couple of associated drawbacks. One of the perks of scanf is that it normalizes whitespace; multiple spaces and tabs (or even returns) will silently be translated to a single space before scanning. This code, on the other hand, explicitly checks for a single space character. If there is variation in the whitespace in your data file, you must account for that as well.
With the last two items 'manually' processed, you can opt to not use fscanf at all. You can read an entire line of text at once with fgets (which also has a line length check built in) and look for spaces using strchr and strrchr. To counter possible whitespace problems, search the line for tabs and double spaces and change these to a single space.

fscanf copies a line from file twice in C

while(1<2) {
nscan=fscanf(infile, "%s %s %d%c",temp.name, temp.surname,&temp.code,&termch);
if(nscan==EOF) break;
if(nscan!=4 || termch!='\n')
printf("Error\n");
RecBSTInsert(&a,temp);
}
for some reason nscan //if(nscan==EOF) break; does not get executed when it is supposed to and it runs one more time giving the binary tree one more value, which is same with the last one.
fscanf:
Upon successful completion, these functions shall return the number of
successfully matched and assigned input items.
fscanf does not return the input provided. That is why you are not seeing EOF like you are testing for.
See: manpage for *scanf functions.
To answer your other question, try looping through like this:
while (fscanf(infile, "%s %s %d%c, temp.name, temp.surname, &temp.code, &termch) == 4)
{
//...
}
Edit again: I threw together a small program to simulate what I think you are doing. Here is my implementation, which takes from a file "testfile.txt" which looks like:
Bill Person 1
Bob Dog 2
Andrew Cat 3
With only one newline between each line. It matches the pattern %s %s %d%c (where \n is the %c).
Program to use this file:
#include <stdio.h>
#include <stdlib.h>
struct test {
char name[64];
char surname[64];
int code;
};
int main()
{
struct test temp;
char endchar;
FILE *infile = fopen("./testfile.txt", "r+"); // works with "r" as well, just a habit
if (infile == NULL)
return -1;
while (fscanf(infile, "%s %s %d%c", temp.name, temp.surname,
&temp.code, &endchar) == 4)
{
printf("Got one!\n");
}
return 0;
}
Of course, the printf exists in place of whatever logic you want to do on the current "temp" input.

Segmentation fault solution

I have a text file having info as
Emp_Id Dept_Id
1 1
1 2
1 3
2 2
2 4
I am trying to read this file through C with this code below :
#include "stdio.h"
#include "stdlib.h"
int main()
{
FILE *fp;
char line[100];
char fname[] = "emp_dept_Id.txt";
int emp_id, dept_id;
// Read the file in read mode
fp = fopen(fname, "r");
// check if file does not exist
if (fp == NULL)
{
printf("File does not exist");
exit(-1);
}
while (fgets(line, 100, fp) != NULL)
{
printf("%s", line);
sscanf(line, "%s %s", &emp_id, &dept_id);
printf("%s %s", dept_id, dept_id);
}
fclose(fp);
return 0;
}
While i am trying to compile the code its all fine but when running it shows the follwoing error :
Segmentation fault (core dumped)
What can be the possible solution and mistakes for my code .
thanks
P.S : I am on IBM AIX and using CC . And have no other option to move from them .
Use %d to scan and print integers:
sscanf(line, "%d %d", &emp_id, &dept_id);
printf("%d %d", dept_id,dept_id);
(You should probably be checking the return value of sscanf as well, to make sure it really did read two integers - reading the first line into integers isn't going to work.)
You are trying to scan and print two integers using %s, it should be %d.
Your code invokes undefined behaviour because you use the wrong conversion specifier for reading and printing integers. You should use %d instead of %s. Also, output a newline to immediately print output to the screen as stdin stream is line buffered by default. Change your while loop to
while(fgets(line, 100, fp) != NULL)
{
// output a newline to immediately print the output
printf("%s\n", line);
// change %s to %d. also space is not needed
// between %d and %d since %d skips the leading
// whitespace characters
sscanf(line, "%d%d", &emp_id, &dept_id);
// sscanf returns the number of input items
// successfully matched and assigned. you should
// check this value in case the data in the file
// is not in the correct format
// output a newline to immediately print the output
printf("%d %d\n", dept_id, dept_id);
}

reading primitives from file in C

I am new to C, and want to read some data from a file.
Actually, I find many reading functions, fgetc, fgets, etc..
But I don't know which one/combination is the best to read a file with the following format:
0 1500 100.50
1 200 9
2 150 10
I just need to save each row above into a struct with three data members.
I just need to know the best practice to do that, hence I am new to C programming.
Thanks.
Try reading each line using fgets. With each line, you can then use sscanf.
FILE* f = fopen("filename.txt", "r");
if (f) {
char linebuff[1024];
char* line = fgets(linebuff, 1024, f);
while (line != NULL) {
int first, second;
float third;
if (sscanf(line, "%d %d %g", &first, &second, &third) == 3) {
// do something with them..
} else {
// handle the case where it was not matched.
}
line = fgets(linebuff, 1024, f);
}
fclose(f);
}
This may have errors, but it's just meant to give you an example of how you might use the functions. Be sure to validate what sscanf returns you.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void
read_file(const char *fname)
{
FILE *f;
char line[1024];
int lineno, int1, int2, nbytes;
double dbl;
if ((f = fopen(fname, "r")) == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
for (lineno = 1; fgets(line, sizeof line, f) != NULL; lineno++) {
int fields = sscanf(line, " %d %d %lg %n", &int1, &int2, &dbl, &nbytes);
if (fields != 3 || (size_t) nbytes != strlen(line)) {
fprintf(stderr, "E: %s:%d: badly formatted data\n", fname, lineno);
exit(EXIT_FAILURE);
}
/* do something with the numbers */
fprintf(stdout, "number one is %d, number two is %d, number three is %f\n", int1, int2, dbl);
}
if (fclose(f) == EOF) {
perror("fclose");
exit(EXIT_FAILURE);
}
}
int main(void)
{
read_file("filename.txt");
return 0;
}
Some notes on the code:
The fscanf function is quite difficult to use. I had to experiment a while until I got it right. The space characters between the %d and %lg are necessary so that any white-space between the numbers is skipped. This is especially important at the end of the line, where the newline character must be read.
Most of the code is concerned with checking errors thoroughly. Almost every return value of a function call is checked whether it succeeded or not. In addition, the number of fields and the number of characters that have been read are compared to the expected values.
The format strings for fscanf and fprintf differ in subtle details. Be sure to read the documentation for them.
I used the combination of fgets to read one line at a time and sscanf to parse the fields. I did this because it seemed impossible to me to match a single \n using fscanf.
I used the GNU C Compiler with the standard warning flags -Wall -Wextra. This helped to avoid some easy mistakes.
Update: I forgot to check that each invocation of fgets reads exactly one line. There might be lines that are too long to fit into the buffer. One should check that the line always ends with \n.

Resources