I have been pondering this task for awhile now and I just can't get it to work.
I am trying to get the function readParameters to read the text from a .txt file and transfer them to the specified variables. I have managed to eliminate almost all the warnings but I cannot figure out how to get it to transfer the values from the .txt file. So all I end up with is the program taking the second route that terminates the program as no parameters could be stored. And just to mention it I am working with C99.

The .txt file includes these values:
rows: 5
columns: 7
northTemp: 4.3
eastTemp: 3.1
southTemp: 2.7
westTemp: 0.9
limit: 0.00005

and the code that I have managed so far is this:

#include <stdio.h>
#include <math.h>
#include <stdlib.h>

/*Function to transfer the parameters from the .txt file to the specified variables*/
int readParameters(FILE *infilep, int *rows, int *columns, double *northTemp,
         double *eastTemp, double *southTemp,
         double *westTemp, double *limit);


int main (int argc,char ** argv){

    int rows, columns;
    double northTemp, eastTemp, southTemp, westTemp, limit;
    FILE *infilep;
    int x;

/*Reads a filename from the commandline and open the file*/

    infilep = fopen(argv[1], "r");
            if(infilep == NULL) {
               fprintf(stderr, "Couldn't open file %s\n", argv[1]);

               return 1;
            }

/*Reads the values from the file (not working yet though)*/

      if (readParameters(infilep, &rows, &columns,
             &northTemp, &eastTemp, &southTemp,
            &westTemp ,&limit)== 1) {

        printf("Could not read parameters.\n");
        printf("Terminating program.\n");

        return 0;
    }

}




int readParameters(FILE *infilep, int *rows, int *columns, double *northTemp,
         double *eastTemp, double *southTemp,
         double *westTemp, double *limit) {

    char storage[100];
    char temp;

  while (!feof(infilep)) {
     if  (fscanf(infilep, "%d\n", rows) == 1 &&
          fscanf(infilep, "%d\n", columns) == 1 &&
          fscanf(infilep, "%s: %lf\n", &temp, northTemp) == 2 &&
          fscanf(infilep, "%s: %lf\n", &temp, eastTemp) == 2 &&
          fscanf(infilep, "%s: %lf\n", &temp, southTemp) == 2 &&
          fscanf(infilep, "%s: %lf\n", &temp, westTemp) == 2 &&
          fscanf(infilep, "%s: %lf\n", &temp, limit) == 2) 
    {
                      printf("temp is %s, %d\n", &temp, *rows);
                       fclose(infilep);
                       return 0;
              } else {
             fclose(infilep);
             printf("The file could not be opened.\n");
             return 1;
            }
    }
}

Does anyone know what I am doing wrong here? Any criticism and help is welcomed.

Thanks in advance for your advice,
Mike

Recommended Answers

All 10 Replies

That is a common file format for a *.ini file used by many MS-Windows programs that contain startup information. You can't store the data directly into a variable using fscanf(). Instead you have to call fgets() to get a line of text, find the colon in the line, then call a series of if statements to use strcmp() on the first part of the text, commonly =called tags. Once a tag name is found you assign the value to the appropriate value. For example, if the first line is read from the file

char line[80] = "rows: 5"; // this is read in a loop from the file
char* ptr = strchr(line,':');
*ptr++ = '\0';
if( strcmp(line,"name") == 0)
   name = atol(ptr);
else if( strcmp(line,"another name) == 0)
   AnbotherName = atol(pointer);

 // etc. etc with more if statements

Adding to what Ancient Dragon has already mentioned, in case you need to use fscanf(), you would have to match the entire line.

So, for eg: Say the text file has:
rows: 5

this would be matched by

fscanf(<file>, "%s: %d", <var1>, <var2>);

@Ancient Dragon:
Wouldn't this above approach work as well? Please correct me if i'm wrong.

Ok, if I would do as myk45 suggests:

 if  (fscanf(infilep, "%s: %d\n",  &temp, rows) == 1 &&
          fscanf(infilep, "%s: %d\n",  &temp, columns) == 1 &&
          fscanf(infilep, "%s: %lf\n", &temp, northTemp) == 2 &&
          fscanf(infilep, "%s: %lf\n", &temp, eastTemp) == 2 &&
          fscanf(infilep, "%s: %lf\n", &temp, southTemp) == 2 &&
          fscanf(infilep, "%s: %lf\n", &temp, westTemp) == 2 &&
          fscanf(infilep, "%s: %lf\n", &temp, limit) == 2) 

But then I am still stuck at how I am supposed to transfer the variables from the file to the variables indicated.
SHould I store the value from the file into an array and then transfer it to the variable?
Could someone explain to me how fscanf works again? It feels like I have lost the right way of using it somewhere.

//Mike

fscanf() reads dataa from the file directly into a variable, it is not necessary to do other transfers. The parameters to fscanf() must all be pointers to your program's variables so that fscanf() can change their values. In your example you need to do it like this:

char temp[80]; // the tag name
int rows;
int columns;
// etc for each variable

fscanf(infilep, "%s: %d\n",  temp, &rows)

In the above you see that char arrays are always passed as pointers so there is no need to use & operator on them. Another way to do it, if you like using &, is like this: &temp[0], which creates a pointer to the first character in the array. Either way of coding it is correct.

The problem with using fscanf() like the above is that you can't scramble the lines in the fine and still get the same results. Once you write the program the file format must be written in stone. If you take my original suggestion then the lines of the file can be in any order you wish, the program is not dependent on the file order and vice versa.

Thanks Ancient Dragon. Now I actually understand what fscanf does. I kind of wish my college professors could explain it a little better.

Anyways, the reason I am using fscanf is because I know that the .txt files that will be tested are all in the format I showed in my first post

rows: 5
columns: 7
northTemp: 4.3
eastTemp: 3.1
southTemp: 2.7
westTemp: 0.9
limit: 0.00005

My biggest problem now is that the program seems to not be able to read the parameters at all, as if it the if function is false and thus jumps right down to the else function, giving me the output.

"The file could not be opened.
Could not read parameters.
Terminating program."

I am doing a little trial and error right now, working through it bit by bit to see if I can find the problem but I am having no luck yet to get the program to read the file.

I can post my new code per request since I cannot edit my first post with the old code.

Your format string is incorrect. The %s will read until the first whitespace, so a literal ':' won't be matched (since it was already extracted) and will cause the fscanf() call to fail. If you want to match it then this would be better (example using the first line):

char temp[80];
int rows;

...

fscanf(infilep, "%79[^:]: %d\n", temp, rows);

Note that temp is an array rather than just a char. It doesn't seem like AD made it clear that your use of a char is very broken. Also note that I included a field width matching the size of the array. This ensures that you don't experience undefined behavior from buffer overflow if the string in the file exceeds the size of the array.

The actual specifier is a scanset. It looks for any character that isn't a colon (including whitespace!), as the '[^' scanset is like a logical NOT. This leaves the colon to be matched by the literal in the format string.

hmm, That helps me alot.Thanks deceptikon.
Thanks to you, myk45 and AD I have finally been able to get a value into the variable.
Now my problem is this:
My code thra I have change looks like

     fscanf(infilep, "%[^:]s : %d\n", storage,  &a);
     printf("temp is %s, %d\n", storage, a);

right now. I have printf to verify that the variables have a value. But when I ask it to read a file (plate1.txt in this case) it gives me the output

temp is rows, 1957308768

and if I try to read columns with this code snippet:

     fscanf(infilep, "%[^:]s : %d\n", storage,  &a);
     printf("temp is %s, %d\n", storage, rows);
     fscanf(infilep, "%[^:]s : %d\n", storage,  &b);
     printf("temp is %s, %d\n", storage, columns);

I get the output

temp is rows, 1957308768
temp is rows, 1956754134

and so on as I add more variables to store values in.

So my question here is:

How would you recommend me to continue to be able to achieve a readout that reads

temp is rows, 5
temp is columns, 7
etc.

if the .txt file is the same as in the previous posts?

rows: 5
columns: 7
northTemp: 4.3
eastTemp: 3.1
southTemp: 2.7
westTemp: 0.9
limit: 0.00005

Remove the space just before the colon in the fscanf() format specifier string. Not sure it will fix it but worth a try.

and if I try to read columns with this code snippet:

I notice that you're reading the value for the rows and columns into a and b, respectively. But you try to print rows and columns. Since you used the address-of operator for a and b, I can make a reasonable guess that they're not pointers referencing rows and columns. That's your immediate problem, but fixing it still won't produce the correct output (see below).

I also notice that you didn't pay close attention to the code example I gave you. %[^:] is the specifier, the scanset is not a modifier for the %s specifier. Your format string has %[^:]s, which means scanf() will look for a literal 's' in the stream, then any amount of whitespace, then a colon. There's no way your format string will work, because it depends on two mutually exclusive values for the next character. The scanset stops on a colon without reading it, but the next expected character is the literal 's'; it can't be both a colon and an 's'.

The following is correct, read it very carefully:

fscanf(infilep, "%[^:] : %d\n", storage,  &a);
printf("temp is %s, %d\n", storage, a);
fscanf(infilep, "%[^:] : %d\n", storage,  &b);
printf("temp is %s, %d\n", storage, b);

Remove the space just before the colon in the fscanf() format specifier string. Not sure it will fix it but worth a try.

It won't have any effect. Literal whitespace in a format string just means that scanf() will skip any amount of whitespace before trying to read the next character. Since there can't possibly be any whitespace, it's a no-op.

Thank you all for your help. you have all been very helpful.
I have now solved the problem and the function works perfectly now.

My working code looks like this:

    int a, b;
    double c, d, e, f, g;
    char storage[100];

   fscanf(infilep, "%s %d\n", storage, &a);
   printf("temp is %s %d\n", storage, a);
   fscanf(infilep, "%s %d\n", storage, &b);
   printf("temp is %s %d\n", storage, b);
   fscanf(infilep, "%s %lf\n", storage, &c);
   printf("temp is %s %lf\n", storage, c);
   fscanf(infilep, "%s %lf\n", storage, &d);
   printf("temp is %s %lf\n", storage, d);
   fscanf(infilep, "%s %lf\n", storage, &e);
   printf("temp is %s %lf\n", storage, e);
   fscanf(infilep, "%s %lf\n", storage, &f);
   printf("temp is %s %lf\n", storage, f);
   fscanf(infilep, "%s %lf\n", storage, &g);
   printf("temp is %s %lf\n", storage, g);

              fclose(infilep);
              return 0;
}

If I ever need help again I'll post a new discussion and definitely look for your responses.

//Mike

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.