C *字符数组末尾的分段错误
我刚开始使用C语言,现在遇到了一个问题。我想使用以下代码将linux命令行中的字符串输入(类似于C *字符数组末尾的分段错误,c,arrays,linux,segmentation-fault,memory-segmentation,C,Arrays,Linux,Segmentation Fault,Memory Segmentation,我刚开始使用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] = " "
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()手册
返回值
strtok()和strtok_r()函数返回指向下一个
令牌,如果没有更多令牌,则为NULL
一旦不再有令牌,token
包含一个空指针,因此strlen(令牌)
seg故障。请参见strtok()手册中的
返回值
strtok()和strtok_r()函数返回指向下一个
令牌,如果没有更多令牌,则为NULL
一旦不再有令牌,
token
包含一个空指针,因此strlen(令牌)
seg故障。请参阅程序的问题:日期组件的索引,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] = '\0';
}
/* 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;
}
尽管这是对strtok()的适当使用,但要小心。它是早期的产物,应该避免使用更安全的现代库函数,如strep()
和strtok_r()
,程序问题:日期组件的索引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] = '\0';
}
/* 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;
}
尽管这是strtok()的恰当用法,但要小心。它是早期的产物,应该避免使用更安全的现代库函数,如strep()和strtok_r()
fgets(&str[0],50,stdin);
在我看来是错误的。您正在传递一个char**
值,而不是char*
。编译此代码时是否启用了警告?请尝试将-Wall
添加到命令行选项中。编辑:token=strtok(str,s);
也是错误的;str
应该是char*
,而不是char**
。这将是开始学习如何使用a的好时机。正如你所说,它确实在fgets上给了我警告,我不知道存在调试器。谢谢你让我知道!我已经找到了如何让它在没有分段错误的情况下运行的方法,when在更新数组之前,我添加了一个if(token==Null){break;}
。但我仍然不知道为什么会这样做!fgets(&str[0],50,stdin);
在我看来是错误的。您正在传递一个char**
值,而不是char*
。编译此代码时是否启用了警告?请尝试将-Wall
添加到命令行选项中。编辑:token=strtok(str,s);
也是错误的;str
应该是char*
,而不是char**
。这将是开始学习如何使用a的好时机。正如你所说,它确实在fgets上给了我警告,我不知道存在调试器。谢谢你让我知道!我已经找到了如何让它在没有分段错误的情况下运行的方法,whe我添加一个if(token==Null){break;}
在更新数组之前。但我仍然不知道为什么会这样!哇,这比我之前写的要好得多,非常感谢!我会牢记你的建议,并据此修改我写的内容哇,这比我之前写的好得多,非常感谢!我会牢记你的建议并修改至少我已经写了相应的信