*char 数组末尾的分段错误

Segmentation fault at the end of a *char array

我是 C 语言的新手,运行 遇到了问题。我想使用以下代码将来自 linux 命令行(类似于 date | ./date_split)的字符串输入拆分为一个数组,稍后我将访问和修改该数组。拆分最初有效,但最后出现分段错误。谁能解释我做错了什么?

int main()
{
   char *indate[10];
   int i= 1;
   char str[100][50];
   fgets(&str [0], 50, stdin);
   const char s[2] = " ";
   char *token;

  /* get the first token */
  token = strtok(str, s);
  indate[i] = malloc(strlen(token)+1);
  strcpy(indate[i], token);
  printf( "Array before: %s\n", indate[i]);     

 /* walk through other tokens */
 while( token != NULL )
{
  printf( "Token before: %s\n", token );

  token = strtok(NULL, s);
  indate[i] = malloc(strlen(token)+1);
  strcpy(indate[i], token);

printf( "Token2 After: %s\n", token );
printf( "Array2 After: %s\n", indate[i]);     
i++;   
}

    return(0);
}

给出终端输出:

Array before: Thu
Token before: Thu
Token2 After: 20
Array2 After: 20
Token before: 20
Token2 After: Oct
Array2 After: Oct
Token before: Oct
Token2 After: 11:37:56
Array2 After: 11:37:56
Token before: 11:37:56
Token2 After: EDT
Array2 After: EDT
Token before: EDT
Token2 After: 2016

Array2 After: 2016

Token before: 2016

Segmentation fault (core dumped)

来自 strtok() 手册

RETURN VALUE The strtok() and strtok_r() functions return a pointer to the next token, or NULL if there are no more tokens.

一旦没有更多的标记,token 包含一个 NULL 指针,因此 strlen(token) 段错误。参见 strlen not checking for NULL

你的程序有问题:你对日期组件的索引,i,从 1 而不是 0 开始(对于这个目的来说是一个糟糕的变量名)并且没有一致地更新(第一个条目被覆盖); str() 数组在分配方面完全是一团糟(例如,二维,只使用了一个);您假设第一个 strtok() 成功,但输入错误可能并非如此;在您已经使用结果之前,您不会测试后续 strtok() 调用是否成功;您没有尝试 free()malloc() 的记忆,甚至忘记了一些记忆。

下面是对您的原始代码的返工,其中还添加了一些错误检查和其他细节:

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

#define MAXIMUM_TOKENS 16
#define MAXIMUM_TOKEN_LENGTH 32

const char *separator = " ";

int main()
{
    char string[(MAXIMUM_TOKEN_LENGTH + strlen(separator)) * MAXIMUM_TOKENS + 1]; // estimate

    char *result = fgets(string, sizeof(string), stdin);

    if (result == NULL)
    {
        fprintf(stderr, "An appropriate error message goes here.\n");
        return EXIT_FAILURE;
    }

    /* strip final newline (\n) if present */
    size_t last_index = strlen(string) - 1;

    if (string[last_index] == '\n')
    {
        string[last_index] = '[=10=]';
    }

    /* get the first token */
    char *token = strtok(string, separator);

    char *date_parts[MAXIMUM_TOKENS];
    int date_parts_index = 0;

    /* walk through other tokens */
    while (token != NULL)
    {
        date_parts[date_parts_index++] = strdup(token);
        token = strtok(NULL, separator);
    }

    /* print the tokens and free the strdup/malloc memory */
    for (int i = 0; i < date_parts_index; i++)
    {
        (void) puts(date_parts[i]);
        free(date_parts[i]);
    }

    return EXIT_SUCCESS;
}

用法

% date | ./a.out
Thu
Oct
20
09:58:00
PDT
2016
% 

虽然这是对 strtok() 的适当使用,但请谨慎使用。它是早期的产物,应该避免使用更安全、现代的库函数,如 strsep()strtok_r().