简体   繁体   中英

Strtok on text file leads to seg fault

I have a text file that reads as follows:

5f6
2f6
4f6

I'd like to obtain the numbers from that textfile (as chars then convert them to integers using atol()

I have the code:

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

int main(int argc, char * argv[])
{
    initscr();
    cbreak();
    noecho();

    char buf[100];
    char * ptr;
    char * ptr2;
    char * ptr3;
    char * ptr4;
    int a;
    int b;
    int c; 
    int d;

    FILE* file;
    if (strcmp(argv[1],"test.txt") == 0)
    {
        file = fopen("test.txt","r");

        while (fgets(buf,100,file) )

        ptr = strtok(str,"f");
        ptr2 = strtok(NULL," ");
        ptr3 = strtok(NULL,"f");
        ptr4 = strtok(NULL," ");
        a = atol(ptr);
        b = atol(ptr2);
        c = atol(ptr3);
        d = atol(ptr4);
    }

    refresh();
    getchar(); 
    endwin();
    return (0);
}

however, the program seg faults but compiles. How would I go about doing this more efficiently (By a method that doesn't seg fault)?

You have several problems

  1. You don't check if the file opened.

    • After fopen() you must ensure that you can read from the file, if fopen() fails, it returns NULL so a simple

       if (file == NULL) return -1; 

    would prevent problems in the rest of the program.

  2. Your while loop only contains one statement because it lacks braces.

    • Without the braces your while loop is equivalent to

       while (fgets(buf, sizeof(buf), file)) { ptr = strtok(buf, "f"); } 
  3. You don't check that strtok() returned a non NULL value.

    • If the token is not found in the string, strtok() returns NULL , and you passed the returned pointers to atol anyway.

      That would cause undefined behavior, and perhaps a segementation fault.

  4. You don't check if there was an argument passed to the program but you still try to compare it to a string. Also potential undefined behavior.

I don't know if the following program will do what you need since it's your own program, I just made it safer, avoided undefined behavior

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

int main(int argc, char * argv[])
{
    char buf[100];
    char *ptr;
    char *ptr2;
    char *ptr3;
    char *ptr4;
    int   a;
    int   b;
    int   c;
    int   d;
    FILE *file;

    initscr();
    cbreak();
    noecho();

    if (argc > 1)
     {
        file = fopen(argv[1], "r");
        if (file == NULL)
            return -1;
        while (fgets(buf,100,file) != NULL)
         {
            ptr  = strtok(str,"f");
            ptr2 = strtok(NULL," ");
            ptr3 = strtok(NULL,"f");
            ptr4 = strtok(NULL," ");
            if (ptr != NULL)
                a = atoi(ptr);
            if (ptr2 != NULL)
                b = atoi(ptr2);
            if (ptr3 != NULL)
                c = atoi(ptr3);
            if (ptr4 != NULL)
                d = atoi(ptr4);
         }
     }
    refresh();
    getchar();
    endwin();

    return 0;
}

If, for example, you want to get the digits from eg

5f6

as numbers, that's much more easy than you think. Just read the first and the third character, and convert them to numbers using simple arithmetic.

Example:

char line[8];
while (fgets(line, sizeof line, file) != NULL)
{
    int firstDigit = line[0] - '0';
    int secondDigit = line[2] - '0';

    printf("%d %d\n", firstDigit, secondDigit);
}

For the example input you show

5f6
2f6
4f6

the output will be

5 6
2 6
4 6

If you're wondering about the arithmetic, it works because most character encodings (like the most common ASCII ) keeps the digit characters in a consecutive range. In the example of ASCII, the value for eg '5' is 53 , and the value for '0' is 48 . That means the subtraction of '5' - '0' results in 53 - 48 which is equal to 5 .

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