i'm doing a homework assignment that requires reading from an input file. the program just exits with error, however, and i can't tell why. here's my code.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
int main()
{
FILE *fp = fopen( "input.txt", "r");
FILE *outputF = fopen( "output.txt", "w");
if( !fp || !outputF){
fprintf(stderr, "can't open files for input/output");
exit(EXIT_FAILURE);
}
char line[250];
double factor;
int expo;
while( fscanf( fp, "%f%d", factor, expo) == 1){
if( factor == 0){
fprintf(outputF, "%s\n", "undefined");
}
else{
double total = 1;
for(int i = 0; i < expo; i++){
total = total * factor;
}
fprintf(outputF, "%f", total);
}
}
fclose(fp);
fclose(outputF);
return EXIT_SUCCESS;
}
i'm thinking the problem is with the "while" line but i also tried it with the following code and it did not work. the input file has a doulbe and an int seperated by a space. i.e. "2.33 3"
while(fscanf(fp, "%s", line) == 1){
char *token;
token = strtok(line, " ");
float factor;
sscanf(token, "%f", &factor);
token = strtok(NULL, "\n");
int expo;
sscanf(token, "%d", &expo);
First problem while (fscanf( fp, "%f%d", factor, expo) == 1) has to be
while (fscanf(fp, "%f%d", &factor, &expo) == 2)
read fscanf()'s manual. It does not return a truth value it returns the number of matched specifiers in the string.
Second problem, undefined behavior due to the incorrect scanf() format specifier, for double you need "%lf" and not "%f".
Third problem, you must pass the address of the values you want to read to allow scanf() to store the result in those variables, that's what the & are doing in the fixed fscanf() above.
Note: Your compiler should warn about two of these errers, the wrong format specifier and not using the & address of operator for these particular specifiers. There are two options, you are ignoring these warnings or you are compiling with warnings turned off. The first of these possible reasons is really bad, do not ignore warnings. The second, read the documentation for your compiler and enable as much diagnostics as possible to avoid silly mistakes.
Related
I am trying to make a program that reads numbers from a text file named numbers.txt that contains different numbers in each line.
For example:
8321
12
423
0
...
I have created this program, but it does not work properly. I have tried many things and don't know what to do. Can someone guide me in the right direction? Thank you!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LEN 1000
int main(int argc, char *argv[]) {
char str[MAX_LEN];
FILE *pFile = fopen(argv[1], "r");
int num;
int sum = 0;
int count = 0;
if (pFile == NULL) {
printf("Error opening file.\n");
return 1;
}
while (!feof(pFile) && !ferror(pFile)) {
if (fscanf(pFile, "%d", &num) == 1) {
count++;
while (strcmp(fgets(str, MAX_LEN, pFile), "\0") == 0) {
printf("%s", str);
//sum = sum + (int)(fgets(str, MAX_LEN, pFile));
printf("\n");
}
}
}
fclose(pFile);
printf("count = %d \n", count);
printf("sum = %d \n", sum);
return 0;
}
strcmp(fgets(str, MAX_LEN, pFile),"\0") is wrong in many ways. For one, the argument of strcmp must be a string (which a null pointer isn't), but fgets returns NULL on error or end of file. You need to check that it didn't return NULL and then you can compare the string in str. However, there is no need to strcmp against "\0" (or, in this case equivalently, "") to detect the end of file, because that's when fgets returns NULL.
Another issue is that you are reading with both fscanf and fgets – pick one and stick with it. I recommend fgets since it's generally easier to get right (e.g., on invalid input it's a lot harder to recover from fscanf and make sure you don't get stuck in an infinite loop while also not losing any input). Of course you need to parse the integer from str after fgets, though, but there are many standard functions for that (e.g., strtol, atoi, sscanf).
Don't use !feof(file) as the loop condition (see, e.g., Why is “while ( !feof (file) )” always wrong?). If you are reading with fgets, end the loop when it returns NULL.
You can use strtok to split the numbers in each line, then using atoi function to convert string to int.
For example:
while(fgets(str, MAX_LEN, pFile)) {
// if the numbers are separated by space character
char *token = strtok(str, " ");
while(token != NULL) {
sum += atoi(token);
strtok(NULL, " ");
}
}
if there is only one number per line, you do not need to use strtok:
while(fgets(str, MAX_LEN, pFile)) {
sum += atoi(str);
// OR
sscanf(str,"%d\n", &new_number)
sum += new_number;
}
Your program has multiple problems:
no test if a command line argument was passed.
while (!feof(pFile) && !ferror(pFile)) is always wrong to iterate through the file: feof() gives valid information only after a actual read attempt. Just test if the read failed.
if fscanf(pFile, "%d", &num) == 1) add the number instead of just counting the numbers.
strcmp(fgets(str, MAX_LEN, pFile), "\0") will fail at the end of the file, when fgets() returns NULL.
If the file only contains numbers, just read these numbers with fscanf() and add them as you progress through the file.
Here is a modified version:
#include <stdio.h>
int main(int argc, char *argv[]) {
FILE *pFile;
int num
int sum = 0;
int count = 0;
if (argc < 2) {
printf("Missing filename\n");
return 1;
}
if ((pFile = fopen(argv[1], "r")) == NULL) {
printf("Error opening file %s\n", argv[1]);
return 1;
}
while (fscanf(pFile, "%d", &num) == 1) {
sum += num;
count++;
}
fclose(pFile);
printf("count = %d \n", count);
printf("sum = %d \n", sum);
return 0;
}
This question already has an answer here:
how to identify a field separator from scanf?
(1 answer)
Closed 4 years ago.
For example, I am trying to get the total age from a text file separated by semicolons with the format of Name;Age;Favorite Number
Jack;12;3
Red;21;15
Blue;14;6
I have tried doing something like this.
File *fp;
fp = fopen(in_file,"r");
int sum = 0, age = 0, fav_number = 0;
while (fscanf(fp,"%c %f %f", name, age, fav_number) != EOF) {
fscanf(fp, "%c %f %f", name, age, fav_number);
sum += age;
}
But since it is not separated with space by with semicolon, it wouldn't work. I am not sure how to change it. Any clue on how to do it?
There are few issues with your code. Firstly its recommended to check the return value of fopen() for e.g this
fp = fopen(in_file,"r");
should be
fp = fopen(in_file,"r");
if(fp == NULL) {
/* error handling #TODO */
}
Secondly, the fscanf() arguments are not correct, surely compiler produces the warnings but seems you ignored them. This
while(fscanf(fp,"%c %f %f", &name, &age, &fav_number) != EOF) { /* read the name from file & store into name i.e it should be &name if name is char variable */
fscanf(fp,"%c %f %f", &name, &age, &fav_number);
sum += age;
}
lastly if you want to read the lines separated by semicolon then use %[^;] or use strtok(). Or it's better to read whole line first using fgets() and then use strtok(). To know how strtok() works read the manual page strtok.
There are many issues in your code:
File should be FILE
you should test the return value of fopen()
the format string for fscanf() is incorrect: %c reads just one character, %f requires a pointer to float and you instead provide an int value...
you should compare the return value of fscanf() to the number of expected conversions (3 in your code), not EOF which is only returned at end of file if no conversions were performed.
you call fscanf() twice.
Since you are not interested in the Name and Favorite colour fields, you can just ignore them:
#include <stdio.h>
int main() {
char in_file[] = "test.csv";
FILE *fp;
fp = fopen(in_file, "r");
if (fp != NULL) {
double sum = 0, age = 0;
while (fscanf(fp," %*[^;];%lf;%*lf", &age) == 1) {
sum += age;
}
fclose(fp);
printf("total of ages: %g\n", sum);
}
return 0;
}
Note however that it would be more reliable to read the input file one line at a time and parse it with sscanf():
#include <stdio.h>
int main() {
char buf[256];
char in_file[] = "test.csv";
double sum = 0, age = 0;
FILE *fp;
fp = fopen(in_file, "r");
if (fp == NULL) {
fprintf(stderr, "cannot open input file %s\n", in_file);
exit(1);
}
while (fgets(buf, sizeof buf, fp)) {
if (sscanf(buf,"%*[^;];%lf;%*lf", &age) == 1) {
sum += age;
} else {
fprintf(stderr, "invalid data: %s\n", buf);
fclose(fp);
exit(1);
}
}
fclose(fp);
printf("total of ages: %g\n", sum);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
//#define true 0
typedef struct
{
char currency[8];
int exchangerate;
} randT;
void main()
{
int i, num;
char currency1[8], ch;
FILE *file = fopen("address", "r");
randT name[7];
while(fscanf(file, "%i", &name[i].exchangerate) != EOF)/*I think this is where my problem is*/
{
fscanf(file, "%s %i", &name[i].currency, &name[i].exchangerate);
//printf("%s %i\n", currency1, num);
//if (fscanf(file, "%i", ¤cy1) == EOF) break;
printf("%s %i\n", name[i].currency, name[i].exchangerate);
i++;
}
fclose(file);
}
It is giving segmentation fault(core dumped) and i am fairly new to the fscanf functions and such. Please help!
my text file looks like this:
jeff 4
jina 5
jeffrey 6
jinna 7
jeffu 8
jinina 9
jeffz 10
The cause of the crash is that you need to initialize int i = 0;. As you have it, i is indeterminate, so probably name[i] is a massively out-of-bounds access.
For the fscanf, you have mostly the right idea about the loop, except instead of checking != EOF it's better to check == 1 or however many items you were reading. If the file contains something that can't be processed as a number, then fscanf will not return EOF.
However this is not the right way to read your particular file. You read %i then %s %i every time around, but your file only contains a string and an int. Change to:
while ( 2 == fscanf(file, "%7s %i", name[i].currency, &name[i].exchangerate) )
Also after doing i++ you need to check that i has not gone out of bounds (i.e. it's less than 7).
Note that name[i].currency decays to pointer to char - you shouldn't put & on it. Also you should use the length specifier to avoid running over the end of the array.
I would use the loop structure:
for (num_read = 0; num_read < sizeof name / sizeof name[0]; ++num_read)
{
if ( 2 != fscanf(file,.....
break;
printf(....
}
I have a file of simply tab-separated integers (a .txt file) and I wish to read them in with just C, line by line. So, say each line has 5 integers. How can I accomplish this?
My first attempt was as follows. It was just to read in a single integer, but even that didn't work:
FILE *fp;
char blah[255];
int *some_int;
fp = fopen("test.txt", "rt");
while (fgets(blah, 255, fp) != NULL)
{
sscanf(blah, "%d", some_int);
printf("%d\n", *some_int);
}
Here's a way no one else suggested, that doesn't use fscanf so you can have sane error handling:
char buffer[BUFSIZE];
size_t size = 5;
int *data = malloc(size * sizeof *line);
if(line == NULL) error();
while(fgets(buffer, sizeof buffer, fp)
{
size_t i = 0;
char *next = buffer;
while(*next && *next != '\n')
{
data[i++] = strtol(next, &next, 0);
// check for errors
}
}
Basically, instead of trying to use *scanf's "%d" to read characters, use the function it (probably) calls to do the conversion: strtol. Where *scanf goes through the string to match the format string but doesn't let you "save your place" in between function calls, strtol does, which is what you need to read an arbitrary number of integers.
I haven't written all your code for you - you have to do the hard error handling. Possible errors include:
i == size, in which case you can try to make data bigger with realloc. Alternately, you could loop through the buffer and count how many numbers there are beforehand, then allocate that many so you don't need to reallocate later.
fgets didn't read the entire line (check that the last character before '\0' is '\n'). In this case you'll probably want to refill the buffer and keep reading numbers. Be careful in this case - you'll likely need to go back and recalculate the last number - fgets might have cut it off. (This is one disadvantage to using fgets.)
Erroneous input - handle however you like.
#include <stdio.h>
int main(){
FILE *fp;
int scanned = 0;
int some_ints[5];
fp = fopen("test.txt", "r");
while ((scanned = fscanf(fp, "%d %d %d %d %d", some_ints, some_ints+1, some_ints+2, some_ints+3, some_ints+4)) != EOF) {
if(scanned ==5){
printf("%d %d %d %d %d\n", some_ints[0], some_ints[1], some_ints[2], some_ints[3], some_ints[4]);
}
else {
printf("Whoops! Input format is incorrect!\n");
break;
}
}
}
I'd do something like this:
int storedVals[MAX_STORED_VALS];
int bf;
int ii=0;
while (!feof(fp) && ii<MAX_STORED_VALS) {
if (fscanf(fp," %d",&bf)) {
storedVals[ii++]=bf;
}
}
fscanf automatically does white space trimming. So as long as there's a space in your scan string, it'll get rid of zero or more \t (tabs) and \n (newlines) to find the next integer. Of course, this doesn't do much by way of error correction.
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.