2

I am trying to write a general function that will read in parameters from formatted text file. I want it to be flexible enough that the parameter list can vary. What is the best way to accomplish this in C?

I've been struggling with this for a few days. The strings that I'm able to extract from the file are not what I expected. The sample text file I'm using to debug is simple:

Nx : 1600;
Ny : 400;
dx : .524584;
dy : .25;
dt : 1;

My program is below.

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

int main(int argc, char * argv[])
{
if(argc!=2)
{   
    printf("ERROR:  Usage: ./Practice3 <input file>");      
}
else
    {
FILE * fr = fopen(argv[1], "rt");


if(fr == NULL){printf("file %s not found", argv[1]);}

char * tmpstr1 ;
char * tmpstr2 ;

char * delimPtr;
char * endPtr;

int Nx = 0;
int Ny = 0;
double dx = 0;
double dy = 0;

    char tempbuff[100];

    while(!feof(fr)) 
    {
         if (fgets(tempbuff,100,fr)) {

            delimPtr = strstr(tempbuff,":");
            endPtr = strstr(delimPtr,";");
            strncpy(tmpstr1,tempbuff,delimPtr-tempbuff);
            strncpy(tmpstr2,delimPtr+2 ,endPtr-delimPtr-2);
            printf("<<%s>>\n",  tmpstr1);
            printf("<<%s>>\n",  tmpstr2);

            if (strcmp(tmpstr1,"Nx")==0) {
                 Nx = atoi(tmpstr2);
            } 
            else if (strcmp(tmpstr1,"Ny")==0) {
                 Ny = atoi(tmpstr2);
            }
            else if (strcmp(tmpstr1,"dx")==0) {
                 dx = atof(tmpstr2);
            }
            else if (strcmp(tmpstr1,"dy")==0) {
                 dy = atof(tmpstr2);
            }
            else{
                printf("Unrecongized parameter : \"%s\"\n", tmpstr1);
            }


         }


    }


    fclose(fr);

    printf("\nNx : %d \nNy : %d  \ndx : %f  \ndy : %f \n",  Nx,Ny,dx,dy);


}//end of code executed when input is correct 


}

I am compiling with gcc -std=c99. The tmpstr1 variable prints out with a weird blob character at the end. I can't reliably extract the parameter name the way I have it now. What is a better way?

Also, it seems that tmpstr2 doesn't get overwritten completely from strncpy so the numbers are getting mixed up. It seems like C is not designed to do this kind of sting manipulation easily. But I have to use C for class so I'm stuck. Any ideas?

user3527862
  • 45
  • 1
  • 5
  • 4
    You never actually allocate any memory for the tempstrs, so you have lots of undefined behavior going on. – John3136 Apr 12 '14 at 23:07
  • 1
    Don't use `feof()` to check for end-of-file, check the return value of `fgets()` instead. – EOF Apr 12 '14 at 23:16
  • and `strncpy(tmpstr1,tempbuff,delimPtr-tempbuff);` includes space. and it is not considered for the null-terminator.、 – BLUEPIXY Apr 12 '14 at 23:25
  • @BLUEPIXY: The same is true for `tmpstr2`, due to the `;`-`endPtr`. – EOF Apr 12 '14 at 23:39
  • Thanks for the quick response. Yes, allocating memory for tmpstr1 and tmpstr2 cleared up the problem of unpredictable results. Simple fix. Yay! char tmpstr1[10]=""; char tmpstr2[10]=""; – user3527862 Apr 12 '14 at 23:40
  • What is wrong with using feof() to check for end-of-file? Isn't that what is meant to be used for? – user3527862 Apr 12 '14 at 23:43
  • 1
    @user3527862: `feof()` returns true only *after* you've tried to read past the end of the file. This means your while-loop is executed one time too many. It doesn't hurt in this case, because you also check `if(fgets(...))`, but it's redundant and not checking what you think it is. Also, note the missing null-termination in your code. – EOF Apr 12 '14 at 23:48
  • I think I understand what you mean now about the feof(). I changed the while loop to be -- while( fgets(tempbuff,100,fr)!=0 ) -- and got rid of the if check. Thanks! – user3527862 Apr 13 '14 at 00:09

2 Answers2

2
char tmpstr1[16];
char tmpstr2[16];
...
/*
delimPtr = strstr(tempbuff,":");
endPtr = strstr(delimPtr,";");
strncpy(tmpstr1,tempbuff,delimPtr-tempbuff-1);
strncpy(tmpstr2,delimPtr+2 ,endPtr-delimPtr-2);
*/
sscanf(tempbuff, "%15s : %15[^;];", tmpstr1, tmpstr2);
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70
  • This was very helpful! I took out the ; at the end of lines of txt file with my parameters. This made the final code nicer -- sscanf(tempbuff, "%15s : %15s", tmpstr1, tmpstr2); – user3527862 Apr 12 '14 at 23:57
0

As pointed out by John3136, you don't allocate any memory for tempstr1 and tempstr2. You probably want to define them like tempbuf, as stack arrays.
Furthermore, you misuse strncpy():
a) The part of the strings you copy from is not null-terminated, so memcpy() would be equivalent in your case, which brings us to
b) You have no null-terminator. strncpy() does not add a null-terminator if it wasn't encountered within the number of chars it was told to copy. Thus, you need to put the null-terminator manually: tempstr[n] = '\0'

EOF
  • 6,273
  • 2
  • 26
  • 50