简体   繁体   中英

Reading file line by line and using strtok() in C

I'm trying to read a configuration file line by line and then tokenize and store the result into separate variables. My configuration file looks like the following

stage 1
num_nodes 2
nonce 234567

I need to tokenize each value in the line separately, so for instance in the first line "stage" used to check if I have read the stage value from the configuration file and then save its value in a variable. My tokenizing seems to be working correct. However, when I try to manipulate my variables after tokenizing it gives me a segmentation fault. At most I can just successfully manipulate one of the variables, ie either stage or num_nodes or nonce but not a combination of them. Even if try to do something like

stage = stage + 1;
num_nodes = num_nodes + 1;

this gives a segmentation fault, however, if I just make a change to one variable, such as:

num_nodes = num_nodes + 1;

then it works fine. I'm pasting the code below, kindly tell me what I'm missing here.

main(int argc, char *argv[]){
  int nonce;
  int num_nodes;
  int stage; 
  char filename[256];   
  char *token1, *token2, *str;  
  FILE* fp;
  char bufr[MAXLINE];  

  printf("Please enter config file name\n");
  scanf("%s",filename);
  printf("You entered %s\n", filename);

  if((fp = fopen(filename, "r")) != NULL){

        while(fgets(bufr, MAXLINE, fp) != NULL){
            if(bufr[0] == '#') // to skip comments
                continue;

            printf("This is bufr: %s",  bufr);
            str = bufr;

              for(str;  ;str = NULL){
                token1 = strtok(str, " ");

                if(strcmp(token2, "num_nodes") == 0){
                    num_nodes = atoi(token1); 
                    printf("num_nodes = %d\n", num_nodes);
                }

                if(strcmp(token2, "nonce") == 0){
                    nonce = atoi(token1);
                    printf("nonce = %d\n", nonce);
                }       

                if(strcmp(token2, "stage") == 0){
                    stage = atoi(token1);
                    printf("stage = %d\n", stage);
                }                   

                token2 = token1; // making a copy of pointer

                if(str == NULL){
                    break;
                }
          }//end of for loop

        }//end of while loop
        fclose(fp); //close the file handle
    }
    else{
        printf("failed, file not found!\n");
    }

/*      This is where the segmentation fault kicks in, try to uncomment two lines and it will give a segmentation fault, if uncomment just one, then it works fine.
    nonce = nonce + 2;  
    num_nodes = num_nodes + 1;
    printf("stage = %d\n", stage);
*/
}

Your code contains:

token1 = strtok(str, " ");

if (strcmp(token2, "num_nodes") == 0){
    num_nodes = atoi(token1); 
    printf("num_nodes = %d\n", num_nodes);
}

You've just set token1 , but you proceed to compare token2 ? This is likely to lead to core dumps, at least on the first time through when token2 has never been set.

At the end, after the loop, the only reason for there to be core dumps is that you've gone trampling around outside the bounds of allocated memory. It isn't immediately obvious why, but the loop structure is…curious, shall we say.

Here's a cleaned-up, not-crashing-for-me version of your code. Your original wasn't too bad, but the indeterminate status of token2 was worrying. One version of the output included information like:

Please enter config file name
You entered config.file
This is bufr: # Comment
This is bufr: 
This is bufr: stage 1
token1 = <<stage>>; token2 = <<>>
token1 = <<1
>>; token2 = <<stage>>
stage = 1
This is bufr: num_nodes 2
token1 = <<num_nodes>>; token2 = <<des>>
token1 = <<2
>>; token2 = <<num_nodes>>
num_nodes = 2
This is bufr: nonce 234567
token1 = <<nonce>>; token2 = <<67
>>
token1 = <<234567
>>; token2 = <<nonce>>
nonce = 234567
This is bufr: 
stage = 1

Notice the left-over debris in token2 . I cleaned that up further in the code below:

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

enum { MAXLINE = 4096 };

int main(void)
{
    int nonce = -1;
    int num_nodes = -1;
    int stage = -1;
    char filename[256];
    char *token1, *token2, *str;
    FILE *fp;
    char bufr[MAXLINE];

    printf("Please enter config file name\n");
    scanf("%s", filename);
    printf("You entered %s\n", filename);

    if ((fp = fopen(filename, "r")) == NULL)
    {
        printf("failed, file not found!\n");
        return(1);
    }

    while (fgets(bufr, MAXLINE, fp) != NULL)
    {
        printf("This is bufr: %s", bufr);
        if (bufr[0] == '#' || bufr[0] == '\n')
            continue;

        token2 = "";
        for (str = bufr; (token1 = strtok(str, " \n\t")) != 0; str = NULL)
        {
            printf("token1 = <<%s>>; token2 = <<%s>>\n", token1, token2);
            if (strcmp(token2, "num_nodes") == 0) {
                num_nodes = atoi(token1);
                printf("num_nodes = %d\n", num_nodes);
            }
            if (strcmp(token2, "nonce") == 0) {
                nonce = atoi(token1);
                printf("nonce = %d\n", nonce);
            }
            if (strcmp(token2, "stage") == 0) {
                stage = atoi(token1);
                printf("stage = %d\n", stage);
            }

            token2 = token1;

            if (str == NULL)    /* Terminate after name/value */
                break;
        }

    }
    fclose(fp);

    nonce = nonce + 2;
    num_nodes = num_nodes + 1;
    printf("stage = %d\n", stage);
    printf("nonce = %d\n", nonce);
    printf("nodes = %d\n", num_nodes);

    return(0);
}

This code compiles cleanly on Mac OS X 10.8.5 with GCC 4.8.1 using the command line:

gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition cfg.c -o cfg

Given an input file called config.file :

# Comment

stage 1
num_nodes 2
nonce 234567
 

(with a blank line at the end), the output was:

Please enter config file name
You entered config.file
This is bufr: # Comment
This is bufr: 
This is bufr: stage 1
token1 = <<stage>>; token2 = <<>>
token1 = <<1>>; token2 = <<stage>>
stage = 1
This is bufr: num_nodes 2
token1 = <<num_nodes>>; token2 = <<>>
token1 = <<2>>; token2 = <<num_nodes>>
num_nodes = 2
This is bufr: nonce 234567
token1 = <<nonce>>; token2 = <<>>
token1 = <<234567>>; token2 = <<nonce>>
nonce = 234567
This is bufr: 
stage = 1
nonce = 234569
nodes = 3

Dude, you can use libconfig to read configuration files. It's more easy to do this with the libconfig than write an algorithm to do this.

http://www.hyperrealm.com/libconfig/

Here you can see an example:

http://simplestcodings.blogspot.com.br/2012/02/libconfig-to-read-configuration-files.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM