Can you use 'fscanf' to read in individual chars and an int? - c

I am trying to convert some code that reads in three integers per line of txt file til end of file.
ie:
int int int
int int int
int int int
What I am trying to get it to do now is read in is:
z z 5
z z 6
z z 5
til end of file.
I'm having an issue right after it opens the file. I placed several debuggers to track the progress and I commented what is printed. It only shows the before and after of the first line of the file. So I'm guessing it is only reading one line.
int i,origin,destin,wt;
char a, b;
int nodes = 0;
printf("before file is opened\n"); // displayed
FILE *fptr = fopen("input.txt","r");
printf("after file is opened\n"); // displayed
while (fscanf(fptr, "%c %c %d", &a, &b, &wt) == 3){
printf("\before is : %c %c\n", a, b); // shows the first line of file
origin = convertToNum(a);
destin = convertToNum(b);
printf("\nconversion is : %d %d\n", origin, destin); // 1st line of file shown
}
edit
Changing:
while (fscanf(fptr, "%c %c %d", &a, &b, &wt) == 3)
to:
while (fscanf(fptr, "%c %c %d", &a, &b, &wt) != EOF)
Produces slightly better results. It will read in one line just fine.
Every other line seems to have a whitespace issue.

I didn't realize %c also grabbed newline characters.
char buf[512];
while (fgets(buf, sizeof buf, fptr) != 0) {
sscanf(buf, "%c %c %d", &a, &b, &wt);

Related

C - Read string with integers from formatted text file

I have a text file following this format:
Thing 1: 0 0 128
Other thing: 255 64 255
Something else: 32 32 8
I intend to add more to this file eventually but the format will remain the same. What I want to do is read everything before the colon into a string and everything after it as an integer. I've tried this:
fscanf((file = fopen("colors.txt", "r")) == NULL){
return -1;
}
fscanf("%s: %d %d %d", colorStr, &r, &g, &b);
while(!feof(file)){
printf("%s: %d %d %d", colorStr, r, g, b);
fscanf(file, "%s: %d %d %d", colorStr, &r, &g, &b);
}
fclose(file);
However, I get this output:
Thing 1:: 0 0 0
0: 0 0 0
0: 0 0 0
128: 0 0 0
And so on. Ideally, the output should read like this:
Thing 1: 0 0 128
Other thing: 255 64 255
Something else: 32 32 8
How can I fix this? The colorStr, r, g, and b variables were set up earlier in the program.
The problem with your code is that the text contains spaces, which %s does not allow.
Changing the format string to %[^:] will fix this problem.
However, the code would remain vulnerable to buffer overrun. Make sure that your format string includes the max size of colorStr to prevent it:
char colorStr[100];
fscanf(file, " %99[^:]: %d %d %d", colorStr, &r, &g, &b);
Your code uses feof(file), which is incorrect. You should put fscanf into loop header. This would let you remove the duplicate fscanf call before the loop:
while(fscanf(file, " %99[^:]: %d %d %d", colorStr, &r, &g, &b) == 4) {
printf("%s: %d %d %d\n", colorStr, r, g, b);
}
Note the space in front of the leading % format specifier. It instructs fscanf to skip the trailing spaces and/or '\n' from the previous line.
Demo.

How to read lines with different formats

I have an input file with the following form
i 176064 Patterson Denise 8.58 11 DEN 15788
q 188464
ra 148702 167443
a 73131
d 163464
f 6.00
ct 73131 PHY
b 3
p 15703
pe
m 144626 6.51 8
e
The first character in each line[i,q,ra,a...] represents an code to a function , while the rest are values that I must store into variables,depending on that code. What's the best way to achieve this ? I have been thinking about using fscanf but each line does not have a specific format, the format itself depends on the code [i,q,ra,a,b..]
To read a line, use fgets()
char buffer[100];
while (fgets, buffer, sizeof buffer, istream) != NULL) {
Then scan the line against the various formats, each ending with " %n". "%n" records the scan position, if it got that far. Additional tests could check for extraneous extras character starting at n.
int num1, num2, num3;
char last[sizeof buf];
char first[sizeof buf];
char code[sizeof buf];
double rate;
int n = 0;
// v..v..v..v...v..v..v spaces optional here
sscanf(buffer, "i %d %s %s %lf %d %s %d %n",
&num1, last, first, &rate, &num2, code, &num3, &n);
if (n) {
Handle_i();
continue;
}
sscanf(buffer, "q %d %n", &num1, &n);
if (n) {
Handle_q();
continue;
}
sscanf(buffer, "ra %d %n", &num1, &num2, &n);
if (n) {
Handle_ra();
continue;
}
sscanf(buffer, "e %n", &n);
if (n) {
Handle_e();
continue;
}
...
fail();
}
As each format begins with a unique letter pattern, the sscanf() will quickly exit on mis-match.
Alternative, code could parse out the initial letters for a slightly more efficient decision tree. Suspect profiling will show little performance difference.
As with any complex format, consider how one would maintain the code and it is bound to evolve.

How to read an unknown quantity of integers from console?

I have entries like these:
0 5 260
1 0 -598
1 5 1508
2 1 -1170
I don't know previously how many (console) inputs I'll get, so I have to read until there are no entries left.
I started with a code like this:
int a, b, c;
while(scanf("%d %d %d", &a, &b, &c)!=EOF){
// do stuff here
}
But it never stops asking for new input.
Then, I saw people in other threads suggesting this:
int a, b, c;
while(scanf("%d %d %d", &a, &b, &c)==1){
// do stuff here
}
In this case, it doesn't even enter the while.
Does anyone know what I'm doing wrong?
An approach: Continue asking for input until the input is closed (EOF) or some problem is encountered. (Invalid line of input)
The below uses fgets() to read a line.
Then, " %n" to detect where scanning stopped. If scanning does not reach %n, n will still have the value of 0. Otherwise it gets the offset in buffer where scanning stopped, hopefully it was at the null character '\0'.
char buffer[100];
while (fgets(buffer, sizeof buffer, stdin)) {
int n = 0;
sscanf(buffer, "%d%d%d %n", &a, &b, &c, &n);
if (n == 0) {
fprintf(stderr, "3 int were not entered\n");
break;
}
if (buffer[n] != 0) {
fprintf(stderr, "Extra input detected.\n");
break;
}
// do stuff here with a,b,c
}
There are many approaches to solve this issue.
while(scanf("%d %d %d", &a, &b, &c)==1)
means that "if scanf() successfully read just one value, proceed in the loop."
Therefore, if you enter something like 0 junk, the scanf() read just 1 data and will enter the loop once.
Try using
while(scanf("%d %d %d", &a, &b, &c)==3)
to have it enter the loop when scanf() successfully read three values, which is what expected.

C Program to get file name and range of numbers from user generate numbers from a specified range and print to file

I am writing a program to get a few things from the user and then write the results to a file. The program will get the file name, number of numbers to generate, the lowest and highest numbers to be generate, then write it all to a file that is named by the user.
The program is doing two things that are not correct:
it is generating numbers outside the user specified range
it is adding a ? to the end of the file name, I tried using strlen to remove the last character of the string but I get and error: incompatible implicit declaration of built-in function 'strlen'.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char s[100];
FILE *fout;
int i, x, len;
int h, l, q, a;
printf("Please enter the file name: ");
fgets(s, sizeof(s), stdin);
printf("How many numbers should we generate: ");
scanf("%d", &q);
printf("lowest number to generate: ");
scanf("%d", &l);
printf("Highest number to generate: ");
scanf("%d", &h);
fout = fopen(s, "wb");
a = h - l;
if ( fout == NULL)
{
printf("That file is not available\n");
exit(1);
}
fprintf(fout, "%d\n", q);
for (i=0; i < q; ++i)
{
x = (rand() % l) + a;
fprintf(fout, "%d ", x);
}
fclose(fout);
return 0;
}
concerning the file name: remove the newline character '\n' (or '\x0a') at the end of s after fgets():
if( s[strlen(s)-1] == '\n' )
s[strlen(s)-1] = '\0';
for completeness: on windows you had to remove carriage return + newline '\r'+'\n' (or '\x0d'+'\x0a')
concerning the wrong numbers: it should be x = (rand() % a) + l; (modulus range + lowest, not the other way round)

Parsing data from ASCII formatted file in C

I am trying to do what's been done here Read co-ordinates from a txt files using C Program . The data that I am trying to input is in this format:
f 10 20 21
f 8 15 11
. . . .
f 11 12 25
The only difference in my point structure is that I have a an extra char to store the letter in the first column (which may or may not be the letter f). I guess im either declaring my char wrong, or I'm calling it in printf incorrectly. Either way, I only get the first line read and then my program terminates. Any ideas ?
Here is my MWE below
#define FILEPATHtri "/pathto/grid1DT.txt"
#define FILEPATHorg "/pathto/grid1.txt"
#define MAX 4000
#include <stdio.h>
#include <stdlib.h>
#include "math.h"
typedef struct
{
float x;
float y;
float z;
char t[1];
}Point;
int main(void) {
Point *points = malloc( MAX * sizeof (Point) ) ;
FILE *fp ;
fp = fopen( FILEPATHtri,"r");
int i = 0;
while(fscanf(fp, "%s %f %f %f ", points[i].t, &points[i].x, &points[i].y, &points[i].z ) == 4 )
{
i++;
}
fclose(fp);
int n;
for (n=0; n<=i; n++){
printf("%c %2.5f %2.5f %2.5f \n", points[i].t, points[n].x, points[n].y, points[n].z ); }
printf("There are i = %i points in the file \n And I have read n = %i points ",i,n);
return 0;
}
Since there's only 1 char in there, not a string just use a single char in your code:
char t;
}Point;
Then when you read it in:
while(fscanf(fp, "%c %f %f %f ", &points[i].t, &points[i].x, &points[i].y, &points[i].z ) == 4 )
{
I'll note that having an array of 1 char, at the end of a structure, sets you up for the struct hack which might not have been your intentions... A good reason to use just char t instead of char t[1]
Also this line:
for (n=0; n<=i; n++){
Should be
for (n=0; n<i; n++){
One last note... if you wanted to print the character out that you read in the prints at the bottom, you should be using n:
// note your previous code was points[i].t
printf("%c %f %f %f \n", points[n].t, points[n].x, points[n].y, points[n].z ); }
Check this
while(fscanf(fp, "%c %f %f %f ", points[i].t, &points[i].x, &points[i].y, &points[i].z ) == 4 )
{
i++;
}
fclose(fp);
int n;
for (n=0; n<i; n++){
printf("%c %2.5f %2.5f %2.5f \n", points[n].t, points[n].x, points[n].y, points[n].z ); }
printf("There are i = %i points in the file \n And I have read n = %i points ",i,n);
getch();
return 0;
}
modification are since only a single character is read %s modified to %c also in printf its not points[i].t its points[n].t . Also the limit checking in for loop is also corrected to n<i

Resources