使用strtok时出现段错误

时间:2017-12-04 23:32:04

标签: c segmentation-fault strtok

我正在尝试从输入中读取每个数字,如下所示:

179    2358 5197    867 
5541    172 4294    1397
2637    136 3222    591 

...并逐行获取每行的最小值/最大值,然后使用strtok获取行中的每个数字,但在第二个while循环中出现seg错误。

代码:

#include "header.h"
#include <string.h>

int main(void) {
  int8_t* line = malloc(sizeof(int8_t) * 75);
  int8_t* temp;

  int32_t minim, maxim;
  int32_t current;

  stdin = fopen("stdin", "r");
  while (fgets(line, 75 * sizeof(int8_t), stdin)) {
    printf("%s", line);
    temp = strtok(line," \n\t");
    maxim = minim = atoi(temp);

    while (temp != NULL) {
      current = atoi(temp);
      temp = strtok(NULL, " \n\t");

      if (current < minim)
        minim = current;
      if (current > maxim)
        maxim = current;

    } 

    printf("\nMin and max: %d %d\n", minim, maxim);
  }

  printf("\n");
  return 0;
}

标题:

#ifndef HEADER_H
# define HEADER_H

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

  typedef                   char  int8_t;
  typedef   signed     short int int16_t;
  typedef   signed           int int32_t;
  typedef   signed long long int int64_t;

  typedef unsigned          char  uint8_t;
  typedef unsigned     short int uint16_t;
  typedef unsigned           int uint32_t;
  typedef unsigned long long int uint64_t;

#endif

我只是不知道它可能是错的。感谢。

2 个答案:

答案 0 :(得分:4)

好的,所以...

  1. 您的<header.h>打破了我的编译器,因为它重新定义了标识符int8_t等。按标准保留。 (投诉编译器不太正确,因为没有包含相关的标题,但是你有。)如果您定义自己的类型,请使用您自己的标识符。或者将<stdint.h>包含在“真正的”intX_t类型中(是的,我知道某个“大”编译器没有该标题)。

  2. 当然,最简单的方法是将char *用于字符串而不是int8_t *。 (char的签名是实现定义的,无论如何,一个好的编译器会相当大声地抱怨使用char *涉及的许多隐式转换而不是。)

  3. 您对int32_tminim使用精确宽度类型maxim,但忽略使用正确的printf()宽度说明符( PRId32中指定的<inttypes.h>。由于我看不出对精确宽度类型的任何特定需求,我将其替换为普通int(仅%d就足够了)。

  4. 完成后,请删除sizeof( char )的提及,因为按照定义 1

  5. 检查返回函数值。 fopen()可能会失败。确保没有。

  6. 不要“重用”stdin文件描述符。这只会令人困惑。您的stdin来自终端,文件还是管道,取决于您如何调用可执行文件。如果您打开文件,请使用FILE * handle_name,而不是stdin。此外,stdin 一个打开的文件描述符(即您的程序的标准输入),因此您必须使用freopen(),而不是fopen()才能拥有它从不同的来源正确接收。最简单的方法是实际使用stdin(这也为使用您的程序提供了最大的灵活性)。

  7. 执行释放您获得的资源。 free()记忆。 fclose()个文件。许多操作系统可以保护您免受此类疏忽,并在您之后进行清理。有些人没有。

  8. 一旦你解决了那些你在评论中打喷嚏的问题......

    #include <stdlib.h>                           // <-- added
    #include <stdio.h>                            // <-- added
    #include <string.h>
    
    int main() {
      char* line = malloc(75);                    // <-- turned to char *
      char* temp;                                 // <-- turned to char *
    
      int minim, maxim;                           // <-- turned to int
      int current;                                // <-- turned to int
    
      while (fgets(line, 75, stdin)) {            // <-- using stdin directly
        printf("%s", line);
        temp = strtok(line," \n\t");
        maxim = minim = atoi(temp);
    
        while (temp != NULL) {
          current = atoi(temp);
          temp = strtok(NULL, " \n\t");
    
          if (current < minim)
            minim = current;
          if (current > maxim)
            maxim = current;
    
        }
    
        printf("\nMin and max: %d %d\n", minim, maxim);
      }
    
      printf("\n");
      free( line );                                // <-- releasing memory
      return 0;
    }
    

    ...你的程序有效:

    ./testme.exe < file.dat                      # feeding file.dat to stdin
    179    2358 5197    867
    
    Min and max: 179 5197
    5541    172 4294    1397
    
    Min and max: 172 5541
    2637    136 3222    591
    
    Min and max: 136 3222
    

    这里的课程:干净利落的代码。启用最严格的编译器警告,并注意它们。

    至于覆盖stdinfopen()的结果一样,标准状态(强调我的):

      

    229)[...] [stderrstdinstdout] 无需修改左值 {可以分配{1}}功能。

答案 1 :(得分:0)

stdin = fopen("stdin", "r");

这不符合您的想法。这会尝试在名为“stdin”的当前目录中打开一个文件。它打开标准输入流。

您很可能没有此名称的文件,因此此函数可能会失败并返回NULL。并且因为您没有检查返回值,所以将NULL指针传递给fgets。这会调用未定义的行为,在这种情况下表现为崩溃。

程序启动时,标准输入流已经打开。因此,请删除fopen电话,它应该有效。