user20842454566
user20842454566

Reputation: 115

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)?

Upvotes: 0

Views: 98

Answers (2)

Some programmer dude
Some programmer dude

Reputation: 409422

If, for example, you want to get the digits from e.g.

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 e.g. '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.

Upvotes: 1

Iharob Al Asimi
Iharob Al Asimi

Reputation: 53016

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;
}

Upvotes: 2

Related Questions