Scanning values from file using fscanf - c

Hey I need to read the data from file and print it(i have to use fscanf). My code only works for first value when I add more it's not working.
Here is my code
char name[5]; //this value is fixed size
char isWorking;
double latitude; //the length may vary
double longitude; //the length may vary
while(fscanf(fp2,"%s %c %lf %lf",name,isWorking,latitude,longitude) == 4) {
printf("\n%s %c %lf %lf",id,type,latitude,longitude);
i++;
}
my file looks like that
Bob1 Y 122.232323 -9.323232
Bob2 N 9.0001 -9.001
It doesn't print anything except when I remove other values and try to read only name

Related

How to read comma delimited data from txt file to struct

I have text file which have the following content
inputfile
I have used a function to get data from the input file which is comma delimited.
I want to read data from it and want to remove comma and store the data to Struct Resistor_struct.
I have tried the following code.
'''
#include<stdio.h>
//functions header
int blown_ressistors();
struct resistor_struct
{
char ID_LEN[5];
char id;
float max_poewr;
int resistance;
};
struct resistor_struct rs[100];
int blown_ressistors()
{
FILE *fp = fopen("input.txt", "r");
int i = 0;
if(fp!=NULL)
{
while(fscanf(fp, "%s[^,], %d[^,], %f[^,]",rs[i].ID_LEN,rs[i].resistance, rs[i].max_poewr)!=EOF)
{
printf("%s\t", rs[i].ID_LEN);
printf("%d\t", rs[i].resistance);
printf("%d\t\n", rs[i].max_poewr);
i++;
}
}
else
{
perror("Input.txt: ");
}
'''
output
output image
You don't want to compare the value returned from scanf with EOF.
In your case, the format string is such that scanf can never match more than 1 conversion specifier, since %s[^,], is trying to match the literal input string [^,], but the [ is guaranteed not to match since the first character that scanf will stop consuming for the %s is whitespace. And [ is not whitespace. Try something like:
while(fscanf(fp, " %4[^,], %d, %f", rs[i].ID_LEN, &rs[i].resistance, &rs[i].max_poewr) == 3 )
but note that this will behave oddly on whitespace in the first column. You might want to try: " %4[^, \t\n] , %d, %f", but quite frankly the better solution is to stop using scanf. Even with something trivial like this, your behavior will be undefined on an input like foo, 9999...9999 (where the 2nd column is any value that exceeds the capacity of an int). Just stop using scanf. Read the data and parse it with strtol and strtod.

C fscanf returning the wrong value

I'm really stuck on something.
I have a text file, which has 1 word followed by ~100 float numbers. The float numbers are separated by space, tab, or newline. This format repeats several times throughout the text file.
For example, this is what the text file looks like:
one 0.00591 0.07272 -0.78274 ...
0.0673 ...
0.0897 ...
two 0.0654 ...
0.07843 ...
0.0873 ...
three ...
...
...
This is a snippet of my code:
char word[30];
double a[1000];
double j;
while (!feof(fp))
{
fscanf(fp, "%s", word);
printf("%s\n", word);
while (!feof(fp) && (fscanf(fp, " %lf", &j)) == 1)
{
a[z] = j;
z++;
num_of_vectors++;
}
z = 0;
}
The word "nine" in the text file, is printed as "ne".
And the word "in" doesn't even print, a floating point number gets printed.
What am I doing wrong?
Any help would be much appreciated.
Thanks.
As per the standard:
An input item is defined as the longest sequence of input characters which does not exceed any specified field width and which is, or is a prefix of, a matching input sequence.
The likely reason that nine is giving you ne is because, when reading a double value, nan is one of the acceptable values. Hence, the n and i are read to establish that it's not nan.
Similarly, with the word in, that a valid prefix for inf representing infinity.
The standard also states in a footnote:
fscanf pushes back at most one input character onto the input stream.
so it's quite possible that this is why the i in nine is not being pushed back.
Bottom line is that it's basically unsafe to assume where the file pointer will end up when fscanf operations fail for some reason.
One way to fix this is to use ftell and fseek to save the file pointer for each successfully item, so that you can move back to the correct file position if the thing you're attempting to read is not successful.
Let's say you have the input file:
one 1 2 3 4 5
nine 9 8 7 6 5
in 3.14159 2.71828
The following code will save and restore file positions to make it work as you wish:
#include <stdio.h>
int main(void) {
char buff[50]; double dbl; size_t pos;
FILE *fin = fopen("inputFile.txt", "r");
while (fscanf(fin, "%s", buff) == 1) {
printf("Got string [%s]\n", buff);
pos = ftell(fin);
while (sscanf(buff, "%lf", &dbl) == 1) {
printf("Got double [%f]\n", dbl);
pos = ftell(fin);
}
fseek(fin, pos, SEEK_SET);
}
fclose(fin);
return 0;
}
By commenting out the fseek, you can see similar behaviour to what you describe:
Got string [one]
Got double [1.000000]
Got double [2.000000]
Got double [3.000000]
Got double [4.000000]
Got double [5.000000]
Got string [ne]
Got double [9.000000]
Got double [8.000000]
Got double [7.000000]
Got double [6.000000]
Got double [5.000000]
Got double [3.141590]
Got double [2.718280]
I consider this solution a little messy in that it's continuously having to call ftell and occasionally fseek to get it to work.
Another way is to just read everything as strings and decide whether it's a numeric or string with a sscanf operation after reading it in, as in the following code (with the afore-mentioned input file):
#include <stdio.h>
int main(void) {
char buff[50]; double dbl;
FILE *fin = fopen("inputFile.txt", "r");
while (fscanf(fin, "%s", buff) == 1) {
if (sscanf(buff, "%lf", &dbl) == 1) {
printf("Got double [%f]\n", dbl);
} else {
printf("Got string [%s]\n", buff);
}
}
fclose(fin);
return 0;
}
This works because a floating point value is actually a proper subset of a string (i.e., it has no embedded spaces).
The output of both those programs above is:
Got string [one]
Got double [1.000000]
Got double [2.000000]
Got double [3.000000]
Got double [4.000000]
Got double [5.000000]
Got string [nine]
Got double [9.000000]
Got double [8.000000]
Got double [7.000000]
Got double [6.000000]
Got double [5.000000]
Got string [in]
Got double [3.141590]
Got double [2.718280]
which is basically what was desired.
One thing you need to be aware of is that scanning something like inf or nan as a double will actually work - that is the intended behaviour of the library (and how your original code would have worked had it not had the issues). If that's not acceptable, you can do something like evaluate the string before trying to scan it as a double, to ensure it's not one of those special values.

C - Reading data into an array of struct, memcpy?

edit for clarity:
fscanf is working the way it is written here...it's getting the data into the array that's broken.
another edit for clarity:
The only point of failure is the memcpy line on the second iteration through the loop where fileindex is 0 and i is 1. the memcpy line works fine when i is 0.
I'm converting a program that used to read data from a binary file directly into an array using fread into reading from ascii text. Here's the setup:
#define MAX_FLIGHT_ENTRIES 27000
#define MAX_PLANES_IN_A_FLIGHT 10
typedef struct {
double local_x;
double local_y;
double local_z;
float pitch;
float roll;
float heading;
float gearpos;
float flappos;
float speedbrakepos;
float canopypos;
float afterburnerOn;
float kias;
float time; // record timestamp
} FLIGHT_ENTRY_TYPE;
static FLIGHT_ENTRY_TYPE FlightEntries [MAX_PLANES_IN_A_FLIGHT][MAX_FLIGHT_ENTRIES];
The way this used to work is, in a loop, the array would be filled via:
fread (&FlightEntries[fileIndex][i], sizeof (FLIGHT_ENTRY_TYPE), 1, pFile);
And I believe this would actually instantiate each entry in the array by putting the data directly into memory. Now I'm reading from a text file and I've tried everything I can to get the values into the array, but it only ever writes the first entry FlightEntries[0][0]. Any attempt to read or write to FlightEntries[0][1] crashes. Here's my current best attempt.
for ( i = 0; i < MAX_FLIGHT_ENTRIES; i++)
{
// If the file end is found before it should be, set values to defaults
// and save the file
if (feof(pFile))
{
FlightInfo[fileIndex].endFrameIndex = i - 1;
break;
}
else
{
float plocalx, plocaly, plocalz;
float ppitch, proll, pheading, pgearpos, pflappos, pbrakepos, pcanopypos, pafterburnon, pkias, ptime;
int fresult;
fresult = fscanf(pFile, "%f %f %f %f %f %f %f %f %f %f %f %f %f\n",
&plocalx,
&plocaly,
&plocalz,
&ppitch,
&proll,
&pheading,
&pgearpos,
&pflappos,
&pbrakepos,
&pcanopypos,
&pafterburnon,
&pkias,
&ptime);
FLIGHT_ENTRY_TYPE newEntry;
newEntry.local_x = (double)plocalx;
newEntry.local_y = (double)plocaly;
newEntry.local_z = (double)plocalz;
newEntry.pitch = ppitch;
newEntry.roll = proll;
newEntry.heading = pheading;
newEntry.gearpos = pgearpos;
newEntry.flappos = pflappos;
newEntry.speedbrakepos = pbrakepos;
newEntry.canopypos = pcanopypos;
newEntry.afterburnerOn = pafterburnon;
newEntry.kias = pkias;
newEntry.time = ptime;
memcpy (&FlightEntries[fileIndex][i], &newEntry, sizeof FLIGHT_ENTRY_TYPE);
}
}
I don't think the array entries are getting allocated properly. I've tried accessing the individual structure members directly via FlightEntries[fileIndex][i].local_x = (double)plocalx; and I've also tried using memcpy to do the same thing for each member...am I doing my pointers wrong or something? I have no idea where to go with this. Every time I get past one stumbling block, something else comes up and I think it's all related to the array as opposed to reading from file. Do I have to do something to allocate space?
The big question is:
What does fread do with binary data in FlightEntries[0][1] that memcpy isn't doing? And is my memcpy line correct? Do I need to do some kind of malloc?
...used to read data from a binary file directly into an array using fread....
EDIT
Now I'm reading from a text file and I've tried everything I can to get the values into the array.
Unless the contents of your file match the current definition of the FLIGHT_ENTRY_TYPE struct, and perhaps these definitions:
#define MAX_FLIGHT_ENTRIES 27000
#define MAX_PLANES_IN_A_FLIGHT 10
There will be problems with your read attempt, no matter what you try. (The file contents, and the struct definition MUST be in alignment to do what you are trying to do. Because you are using a text file, this should be easily verifiable.)
Also, feof(pFile) is rarely a good choice for reading a file
Consider changing it to something like this:(pseudo code)
FLIGHT_ENTRY_TYPE newEntry;
int len = sizeof(FLIGHT_ENTRY_TYPE)*2;// *2 to account for comma delimiters, etc. Change as needed
char **stringArray = {0};
//see edits in answer below for defintion of allocArray()
stringArray = allocMemory(stringArray, MAX_PLANES_IN_A_FLIGHT, len);
FILE *fp = fopen(".\\filename.bin", "rb");
if(fp && stringArray)
{
while(fgets(stringArray[i], len, fp)
{
fresult = sscanf(stringArray[i], "%f %f %f %f %f %f %f %f %f %f %f %f %f\n",
&plocalx,
&plocaly,
&plocalz,
&ppitch,
&proll,
&pheading,
&pgearpos,
&pflappos,
&pbrakepos,
&pcanopypos,
&pafterburnon,
&pkias,
&ptime);
if(fresult > 0)
{ ...assign values to newEntry struct... }
}
fclose(fp);
freeMemory(stringArray,MAX_PLANES_IN_A_FLIGHT);
}
The first three members of your struct are double values, and should therefore be read into double values. If you decide to make that change:
float plocalx, plocaly, plocalz;
TO:
double plocalx, plocaly, plocalz;
Be sure to also Change:
fresult = fscanf(pFile, "%f %f %f %f %f %f %f %f %f %f %f %f %f\n",
To:
fresult = fscanf(pFile, "%lf %lf %lf %f %f %f %f %f %f %f %f %f %f\n",
You should also check the return value of sscanf()
The return value: Converts input from the specified source string into a series of values according to the specifiers in formatString. If an input failure occurs before the first conversion, the function returns EOF (-1); otherwise, the function returns the number of input items assigned. If copying takes place between objects that overlap, the behavior is undefined.
EDIT 2
If you do need to create an array of strings (for each line of the file), these functions will help:
char ** allocMemory(char ** a, int numStrings, int maxStrLen)
{
int i;
a = calloc(sizeof(char*)*(numStrings+1), sizeof(char*));
for(i=0;i<numStrings; i++)
{
a[i] = calloc(sizeof(char)*maxStrLen + 1, sizeof(char));
}
return a;
}
void freeMemory(char ** a, int numStrings)
{
int i;
for(i=0;i<numStrings; i++)
if(a[i]) free(a[i]);
free(a);
}
//usage:
#define MAX_FLIGHT_ENTRIES 27000
#define MAX_PLANES_IN_A_FLIGHT 10
int main(void)
{
char **stringArray = {0};
stringArray = allocMemory(stringArray, MAX_PLANES_IN_A_FLIGHT, sizeof FLIGHT_ENTRY_TYPE);
...//read data into string array as shown in code above
return 0;
}
The concept here is that each line of the file is assumed to represent the data to populate one struct instance of the FLIGHT_ENTRY_TYPE struct. Stated differently, one line in the file is read for each struct in the array of structs.
Extenuating unlisted circumstances.
Turns out, since I couldn't debug, I had placed a log file snippet at the end of the loop iteration. I believe that instantiating the logfile was corrupting the array and preventing the array from being written to. Possibly a heap issue, but I'm not sure. I've learned quite a bit from this exercise about dealign with memory pointers as well as better ways to read and write data from file. So Thank you all for the help.

how to return an argument using sscanf

I am reading a line at the time from a text file that has this format: 2.34 4.68 5.98. I want to store these float values in an array so that I can make use of each argument later on but once I use sscanf and try to print the argument I get 0. Any idea what’s the problem is. Thank you.
char* line[2000];
char* State[2000];
sscanf(line[12],"%f", &State[12]).
printf("\n state 1: %2.3f", &State[0]);// this suppose to print 2.34 but it prints 0
You can scan them all at once:
float state[3];
if(sscanf(line[12], "%f %f %f", &state[0],
&state[1], &state[2]) != 3) {
...
} else
printf("\n state1: %f, state2: %f, state3:%f",
state[0], state[1], state[2]);
}
At the moment you're scanning into one place (State[12]) and expecting the value to be stored somewhere else (State[0]).
A few more mistakes you're making:
Storing into a char * array when you should be storing into a float array
Using pointers with printf when it expects to take in actual values
Using . to end a statement...? Not sure if this is a typo
sscanf(line[12],"%f", &State[12]).
OK. You win a prize for having a new (at least to me) way of misunderstanding how arrays work in c.
You almost certainly don't want the [12] in either case here.
The name of an array (either line or State) can be automatically converted to a char* which points at the beginning of the array. So
sscanf(line,"%f", ...);
scans the contents of line. How ever line[12] is a the single character at the position (*line)+12.
You need a float to put the result in or you need to change your format specifier from %f to %s. You should never but the results of a %f into a char*.
You are puting the number in 12th case of your table ; that's strange.
Is it not easier to use fscanf directly ?
FILE *fp = fopen(fileName);
float tabNumbers[3] = {0};
if (fp) {
for (int i = 0; i < 3; ++i)
fscanf(fp, "%f", &tabNumbers[i]);
fclose(fp);
}

Program doesnt want to read file

this is my struct
typedef struct {
char mmsi[10];
char name[20];
double latitude;
double longitude;
int course;
double speed;
}Vessel;
this is my function which doesnt want to work
void searchByLatLong(double latitude, double longitude){
FILE * file;
struct dirent *drnt;
DIR * dir = opendir("./text");
char *path = (char *)malloc(19);
Vessel *vessel = (Vessel *)malloc(sizeof(Vessel));
while((drnt = readdir(dir)) != NULL) {
if(strcmp(drnt->d_name,".") && strcmp(drnt->d_name,"..")) {
strcpy(path,"text/");
strcat(path,drnt->d_name);
file=fopen(path, "r");
fscanf(file," %s %[a-zA-Z0-9 ]19s %lf %lf %d %lf", &vessel->mmsi,&vessel->name,&vessel->latitude,&vessel->longitude,&vessel->course,&vessel->speed);
// if (mmsi+".txt" == drnt->d_name){
printf("%s\n%s\n%lf\n%lf\n%d\n%lf\n\n",vessel->mmsi,vessel->name,vessel->latitude,vessel->longitude,vessel->course,vessel->speed);
//}
fclose(file);
}
seekdir(dir, telldir(dir));
// if(this->mmsi == mmsi){
// printVessel();
// }
}
closedir(dir);
}
When i try to load txt file it loads only two first strings then after it theres some rubbish from memory. Loading the data to another variables changes nothing ;/
This is a sample txt file which should be loaded:
3
RMS Titanic
22.222
33.333
4
5.9
The problem is with your format string. The correct format string is:
" %s %19[a-zA-Z0-9 ] %lf %lf %d %lf"
The field width goes before the conversion specifier. Also, the [...] sequence is a conversion specifier, just like 's'. The problem you're seeing is that fscanf() processes the '3' because it matches the first %s. Then it processes the 'RMS Titanic' because it matches %[a-zA-Z0-9 ] but then processing stops because there is no '19s' in the input. At this point the remaining arguments are uninitialized.
You should check the return value from fscanf(). It will tell you how many conversions were actually performed.
Thanks for posting an interesting question; I learned about fscanf() and the [] notation it accepts.
The [] notation specifies that a string is being read, therefore, the s you have appended to it is considered a literal character that should match. Similarly, the width-specifier you have provided, 19 should appear prior to the [].
Your current code would start working if you had a ship named, e.g., "RMS Titanic19s".
Change your fscanf to:
fscanf(file," %s %19[a-zA-Z0-9 ] %lf %lf %d %lf",
vessel->mmsi,vessel->name,&vessel->latitude,
&vessel->longitude,&vessel->course,&vessel->speed);
and your code will start working.
Notice I fixed some compile warnings by dropping the superfluous & from the char [] members mmsi and name -- these already point to the buffers you wish to fill. You don't need & in front of them. A pedagogical alternative form is &vessel->mmsi[0] -- the address of the first character of mmsi.

Resources