This is my first post here so dont really know how to post something here with correct format. I have a question on how to read a line from file and read some of the words as string and some as Int.
int check = sscanf(read, "%s %d", string, &integer);
printf("%s, %d", string, integer);
Above is kind of what I did. The input is "oneword 1". What I got is "(null) 4196448". So how can I do it correctly? Thank you
Here is part of my code.
int i;
for (i = 1; i <= 3; i++)
{
char read[MAX_LENGTH_INPUT];
fgets(read, sizeof(read), stdin);
int check2 = sscanf(read, "%s %d", word, &number);
printf("%s %d\n", word, number);
}
So the for loop is to scan three lines in .in file. Can I do that?
Here is the .in file which is the input.
oneword 1
twoword 2
thirdword 3
The output was
(null) 4196448
(null) 4196448
(null) 4196448
Also in your code int check2 = sscanf(read, "%s %d %d", word, &number); format specifier are 3 but arguments 2.
if file contain data like
oneword 1
secondword 2
thirdword 3
fourthword 4
Then
#include <stdio.h>
int main ()
{
FILE *fp = fopen("file", "r");
char read[100];
int integer;
char string[64];
while (fgets(read, sizeof(read), fp) != NULL)
{
int check = sscanf(read, "%s %d", string, &integer);
if (check == 2) {
printf("%s, %d\n", string, integer);
}
else{
printf("Failed to scan all values\n");
}
}
}
And output is
oneword, 1
secondword, 2
thirdword, 3
fourthword, 4
You can modify fgets here to take input from stdin by just replacing fp by stdin in line while (fgets(read, sizeof(read), fp) != NULL)
You are using sscanf
which reads data from char * type and stores them according to parameter format into the locations given by the additional arguments, as if scanf was used, but reading from string instead of the standard input (stdin).
you need to use fscanf and read in your code should be pointer to a FILE.
Related
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);
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;
}
I am currently learning reading from files in C.
Anyway, cutting to the chase:
Text file content:
123456 James Doakes; 0
987987 Dexter Morgan; 0
010203 Masuka Perv; 0
int main()
{
char accountNr[ACCOUNTNRSIZE], ownerName[NAMESIZE], enter[3];
int accountBalance = 0;
char filename[] = "breg.txt";
FILE *file = fopen(filename, "r");
if (file != NULL) {
char line[128];
while (fgets(line, sizeof(line), file) != NULL) {
sscanf(line, "%s %[^;] %d ", accountNr, ownerName, &accountBalance);
printf("%s", ownerName);
//fflushstdin();
}
fclose(file);
} else {
perror(filename);
}
return 0;
}
I wrote this to check if the name for instance James Doakes was registered correctly :
printf("%s", ownerName);
But when it prints that out it's like the stdout is still active and I can push Enter and it will type the name again. My goal is to of course be able to sscanff the number, the full name, and the last number as seperate variables. But it obviously doesn't work. I am guessing a \n gets registered as well. Dunno, I am just speculating.
What am I doing wrong? Why? And how do I solve this?
Much appreciated,
Mif
%s %[^;] %d
means a string terminated by white space, optional white space, a sequence of characters that are not ;, optional white space, then a number.
You appear to be not scanning for the actual ; character itself so that, when you try to get the number, the ; in the input stream will cause it to fail. You can see this with:
#include <stdio.h>
#define ACCOUNTNRSIZE 100
#define NAMESIZE 100
int main (void) {
char accountNr[ACCOUNTNRSIZE], ownerName[NAMESIZE], enter[3];
int accountBalance = 0;
char filename[] = "breg.txt";
FILE *file = fopen(filename, "r");
if (file != NULL) {
char line[128];
while (fgets(line, sizeof(line), file) != NULL) {
int count = sscanf(line, "%s %[^;] %d ", accountNr, ownerName, &accountBalance);
printf ("%d [%s] [%s] [%d]\n", count, accountNr, ownerName, accountBalance);
}
fclose(file);
} else {
perror(filename);
}
return 0;
}
which outputs:
2 [123456] [James Doakes] [0]
2 [987987] [Dexter Morgan] [0]
2 [010203] [Masuka Perv] [0]
In fact, even if you change the breg.txt file to be:
123456 James Doakes; 314159
987987 Dexter Morgan; 271828
010203 Masuka Perv; 42
you still get 0 for the account balance because the scanning only successfully reads two items.
Whenever you use one of the scanf-family functions, you should check the return code to ensure it's scanning the correct number of items, as in:
int count = sscanf (line, "%s %[^;] %d ", accountNr, ownerName, &accountBalance);
if (count != 3) {
fprintf (stderr, "Catostrophic failure, count is %d\n", count);
return 1;
}
The fix here is relatively simple, just use %s %[^;]; %d as the format string.
With that change, the output you see is:
3 [123456] [James Doakes] [314159]
3 [987987] [Dexter Morgan] [271828]
3 [010203] [Masuka Perv] [42]
Keep in mind you don't actually need a space before the %d (though it causes no harm). That particular format specifier skips white space before attempting to scan the number.
Trying to create a program that takes in a text file and reads it line by line. It then finds the two integers that are on each line and adds them together. It then outputs the new line with the original string and total to a new text file. I need help adding the two integers, getting them from each line, and then putting the new line to a text file.
input text file
good morning hello 34 127
ann 20 45
10 11
fun program and you find the same 90 120
news paper said that 56 11
how do you like 20 5
line number 90 34
Outputs first like would look like: and then continue on
good morning hello 161
Code:
int processTextFile(char * inputFileName, char * outputFileName)
{
FILE *fp = fopen(inputFileName, "r");//open file to to read
char buff[1024];
char *p, *p1;
int num;
while (fgets(buff, 1024, fp)!=NULL)
{
printf("%s\n", buff);
while(scanf(buff, "%*[^0-9]%d", &num)== 1)
printf("%d\n", num);
//fscanf(fp, "%s", buff);
}
return 0;
}
EDIT!!!!::
So now that I've been able to accomplish this. How would I sort it by the number produced? for example:
Time is money 52
here I am 3
21
Would output to a new text file in order like
here I am 3
21
Time is money 52
My version using strcspn() is supposed to work with stdin for input and stdout for output. (so you can do executable <textfile >newtextfile)
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char line[1000];
while (fgets(line, sizeof line, stdin)) {
char *ptr;
size_t x = strcspn(line, "0123456789");
if (line[x]) {
errno = 0;
int n1 = strtol(line + x, &ptr, 10);
if (*ptr && !errno) {
errno = 0;
int n2 = strtol(ptr, &ptr, 10);
if (*ptr && !errno) {
int n3 = n1 + n2;
printf("%.*s%d\n", (int)x, line, n3);
} else {
printf("%s", line); // line includes ENTER
}
} else {
printf("%s", line); // line includes ENTER
}
} else {
printf("%s", line); // line includes ENTER
}
}
return 0;
}
The same version without the error checking
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char line[1000];
while (fgets(line, sizeof line, stdin)) {
char *ptr;
size_t x = strcspn(line, "0123456789");
int n1 = strtol(line + x, &ptr, 10);
int n2 = strtol(ptr, &ptr, 10);
int n3 = n1 + n2;
printf("%.*s%d\n", (int)x, line, n3);
}
return 0;
}
The approach should be:
open two files, one for input, one for output.
use sscanf() to read the input buffer.
scan the leading string, and then two number.
if previous sscanf() fails, only check for two number.
if either of the above scanning is success, print the sum to the output file.
A sample code, should look like
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
FILE *fpin = fopen("ipfile", "r");//open file to to read
if (!fpin)
{
printf("Error in ipfile opening\n");
exit (-1);
}
FILE *fpout = fopen("opfile", "w");//open file to to write
if (!fpout)
{
printf("Error in opfile opening\n");
exit (-1);
}
char buff[1024] = {0};
char str[1024] = {0};
int num1 =0, num2= 0;
while (fgets(buff, 1024, fpin)!=NULL)
{
memset(str, 0, sizeof(str));
//printf("%s\n", buff);
if(sscanf(buff, "%[^0-9]%d %d", str, &num1, &num2)== 3)
fprintf(fpout, "%s %d\n", str, (num1+num2));
else if (sscanf(buff, "%d %d", &num1, &num2)== 2)
fprintf(fpout, "%d\n", (num1+num2));
}
return 0;
}
Note:
The above procedure, is a kind of workaround. If the data pattern in the file changes, lot of changes will be required to maintain a code like that. Instead of usinf sscnaf(), for a better and roubust approach, you should
read the line from file
start tokenizing the input buffer (strtok()) and check for ints as tokens (strtol()).
save the returned tokens and ints seperately.
once the strtok() returns NULL, you print the string tokens and the sum of the ints to the o/p file.
I intend not to change your code completely, so I just added some snippets for improvement.
int processTextFile(char *inputFileName, char *outputFileName) {
FILE *fp = fopen(inputFileName, "r");
FILE *out = fopen(outputFileName, "w");
char line[1024];
if (!fp) {
perror(inputFileName);
return;
}
while (fgets(line, sizeof(line), fp) != NULL) {
int num1 = 0, num2 = 0;
char textPart[1024] = "";
if ( !sscanf(line, "%[a-zA-Z' ']%d%d", textPart, &num1, &num2) {
sscanf(line, "%d%d", &num1, &num2);
}
fprintf(out, "%s %d\n", textPart, num1 + num2);
}
fclose(fp);
fclose(out);
}
Explanation:
I scanned the text file, extracted the text part and the two ints. Since I noticed that the ints are placed at the end of each line, I just used sscanf() for that matter.
sscanf(line, "%[a-zA-Z' ']%d%d", textPart, &num1, &num2);
Here, "%[a-zA-Z' ']%d%d" format specifiers means to get only alphabets and spaces.
Since it will only get letters and spaces, the line "10 11" in your input file won't be put to num1 and num2. Because the code inspects first for a string containing letters and spaces. Since 10 and 11 are not of the qualified types, then the line is just skipped.
That's why I added an if-else statement, which checks if sscanf wrote anything to memory. If sscanf returned 0, then it means that no text part is present. Just digits. So the program will scan the two digits.
if ( !sscanf(line, "%[a-zA-Z' ']%d%d", textPart, &num1, &num2) ) {
sscanf(line, "%d%d", &num1, &num2);
}
I also added file checking for input file. It checks if file doesn't exist or can't be opened by the filestream.
if (!fp) {
perror(inputFileName);
return;
}
Here is the content of output file after execution:
good morning hello 161
ann 65
21
fun program and you find the same 210
news paper said that 67
how do you like 25
line number 124
I just want to output 3 integers from the file. Why this doesn't work? I get -1079184140 and similar.
int main(int argc, char *argv[])
{
FILE* stream = fopen(argv[2], "r");
char line[80];
for (int i = 0; i < 3; i++)
{
fgets(line, 80, stream);
printf("%d \n", line);
}
fclose(streamForInput);
}
I would use sscanf.
int number;
sscanf (line, "%d", &number);
printf ("%d \n", number);
That will pull the first integer on a line. This is not the most secure or robust way, but that is out of scope.
PS:
fclose(streamForInput);
Should be:
fclose(stream);
Hmm. The first problem is:
printf("%d \n", line);
because line is a char[]. But you use a %d to output it, so you output line, which is an address. So printf prints the address of line... instead you coud use printf ("%d", atoi(line));
To print a string, which line is, use %s:
printf("%s \n", line);
Now, if it really were an integer, you could use %d:
int num = atoi(line);
printf("%d \n", num );
What you're seeing is the result of treating a pointer type (which is what a string in C basically is) as an integer type. Since pointers hold memory addresses, that -1079184140 is the actual address the pointer holds, represented as a 32 bit signed integer.
If you know exactly the content of the file (three numbers separated by white space), why not directly read it?
if (fscanf(stream, "%d%d%d", &foo, &bar, &baz) < 3)
// handle error
printf("%d\n%d\n%d\n", foo, bar, baz);
But if you want to read lines, there are already other good answers.
To read a file line by line for integers
void read_file(char *filename, int *readbuff, int size)
{
FILE *fp = fopen(filename,"r");
if(fp == NULL){
printf("Failed to open file %s \n", filename);
return;
}
/*the condition in for loop checks if the integer was read into
readbuff[i] and the readbuff is not overflown*/
for(int i = 0 ; fscanf(fp,"%d\n",&readbuff[i]) == 1 && i < size; ++i);
fclose(fp);
return;
}