文本文件中的Strtok导致seg错误

时间:2015-03-07 02:51:52

标签: c file pointers segmentation-fault

我有一个文本文件,内容如下:

5f6
2f6
4f6

我想从该文本文件中获取数字(因为字符然后使用atol()将其转换为整数

我有代码:

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

然而,程序seg故障但编译。我怎样才能更有效地做到这一点(通过一种不会出错的方法)?

2 个答案:

答案 0 :(得分:2)

你有几个问题

  1. 您不检查文件是否已打开。

    • fopen()之后你必须确保你可以从文件中读取,如果fopen()失败,它会返回NULL这么简单

      if (file == NULL)
          return -1;
      

    可以防止程序其余部分出现问题。

  2. 您的while循环只包含一个语句,因为它没有大括号。

    • 没有大括号,你的while循环相当于

      while (fgets(buf, sizeof(buf), file))
       {
          ptr = strtok(buf, "f");
       }
      
  3. 您不会检查strtok()是否返回了非NULL值。

    • 如果在字符串中找不到令牌,strtok()会返回NULL,并且无论如何都会将返回的指针传递给atol

      这会导致未定义的行为,也许会出现分段错误。

  4. 您不检查是否有传递给程序的参数,但您仍尝试将其与字符串进行比较。也可能存在未定义的行为。

  5. 我不知道以下程序是否会满足您的需求,因为它是您自己的程序,我只是让它更安全,避免未定义的行为

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

答案 1 :(得分:1)

例如,如果您想从例如

获取数字
5f6

作为数字,这比你想象的容易得多。只需读取第一个和第三个字符,然后使用简单的算法将它们转换为数字。

示例:

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

对于您显示的示例输入

5f6
2f6
4f6

输出将是

5 6
2 6
4 6

如果您对算术有疑问,可以使用,因为大多数字符编码(如最常见的ASCII)会将数字字符保持在连续范围内。在ASCII的例子中,例如, '5'53'0'的值为48。这意味着减去'5' - '0'会导致53 - 48等于5