strcat 如何影响 strtok?
How does strcat affect the strtok?
假设我们需要通过连接输入的标记将用户的输入复制到另一个字符串中,例如 "hello world" -> "helloworld"
.
#include <stdio.h>
#include <string.h>
int main(void) {
char buffer[50];
printf("\nEnter a string: ");
while (fgets(buffer, sizeof(buffer), stdin) != 0) {
size_t size = strlen(buffer);
if (size > 0 && buffer[size - 1] == '\n') {
char input[1]; // set it too small
buffer[size - 1] = '[=10=]';
char *tok = strtok(buffer, " "); // works fine
do {
strcat(input, tok); // append to "input" that has not enough space
printf("\nfound token: %s", tok);
tok = strtok(NULL, " "); // produces garbage
} while (tok);
break;
}
}
运行 上面的代码:
Enter a string: hello world
found token: hello
found token: w
found token: r
*** stack smashing detected ***: <unknown> terminated
我很难理解 strtok
与 strcat
未能追加 tok
有什么关系。他们不共享变量,除了 tok
是(根据文档)由 strcat
复制的,所以无论 strcat
做什么都不应该影响 strtok
行为和程序至少应该在第二次 strcat
调用时崩溃,对吧?但是我们看到 strcat
在检测到堆栈粉碎之前被调用了 3 次。你能解释一下为什么吗?
对于初学者这个数组
char input[1];
未初始化且不包含字符串。
所以调用strcat
strcat(input, tok);
调用未定义的行为也是因为数组输入不够大,无法存储复制的字符串。它可以覆盖数组之外的内存。
代码中存在多个问题:
char input[1];
太小了,做不了什么。您不能将行中的标记连接到这个极小的数组中。您必须为其定义足够的长度,为了简单起见,即与 buffer
相同的长度。
input
必须初始化为空字符串,strcat(input, tok);
才能具有已定义的行为。如编码所示,对 strcat
的第一次调用会破坏导致观察到的行为的其他变量,但请注意,由于这种未定义的行为,其他任何事情都可能发生。
char *tok = strtok(buffer, " ");
工作正常,但如果 buffer
只包含空白,则可能 return 一个空指针。 do
循环将在 strcat(input, tok)
上调用未定义的行为。请改用 for
或 while
循环。
- 代码中缺少
}
,不清楚您的意思是在第一次迭代后从 while
循环中 break
还是仅在结束时行。
这是修改后的版本:
#include <stdio.h>
#include <string.h>
int main(void) {
char buffer[50];
char input[sizeof buffer] = "";
printf("Enter a string: ");
if (fgets(buffer, sizeof(buffer), stdin)) {
char *tok = strtok(buffer, " \n");
while (tok) {
strcat(input, tok);
printf("found token: %s\n", tok);
tok = strtok(NULL, " \n");
}
printf("token string: %s\n", input);
}
return 0;
}
假设我们需要通过连接输入的标记将用户的输入复制到另一个字符串中,例如 "hello world" -> "helloworld"
.
#include <stdio.h>
#include <string.h>
int main(void) {
char buffer[50];
printf("\nEnter a string: ");
while (fgets(buffer, sizeof(buffer), stdin) != 0) {
size_t size = strlen(buffer);
if (size > 0 && buffer[size - 1] == '\n') {
char input[1]; // set it too small
buffer[size - 1] = '[=10=]';
char *tok = strtok(buffer, " "); // works fine
do {
strcat(input, tok); // append to "input" that has not enough space
printf("\nfound token: %s", tok);
tok = strtok(NULL, " "); // produces garbage
} while (tok);
break;
}
}
运行 上面的代码:
Enter a string: hello world
found token: hello
found token: w
found token: r
*** stack smashing detected ***: <unknown> terminated
我很难理解 strtok
与 strcat
未能追加 tok
有什么关系。他们不共享变量,除了 tok
是(根据文档)由 strcat
复制的,所以无论 strcat
做什么都不应该影响 strtok
行为和程序至少应该在第二次 strcat
调用时崩溃,对吧?但是我们看到 strcat
在检测到堆栈粉碎之前被调用了 3 次。你能解释一下为什么吗?
对于初学者这个数组
char input[1];
未初始化且不包含字符串。
所以调用strcat
strcat(input, tok);
调用未定义的行为也是因为数组输入不够大,无法存储复制的字符串。它可以覆盖数组之外的内存。
代码中存在多个问题:
char input[1];
太小了,做不了什么。您不能将行中的标记连接到这个极小的数组中。您必须为其定义足够的长度,为了简单起见,即与buffer
相同的长度。input
必须初始化为空字符串,strcat(input, tok);
才能具有已定义的行为。如编码所示,对strcat
的第一次调用会破坏导致观察到的行为的其他变量,但请注意,由于这种未定义的行为,其他任何事情都可能发生。char *tok = strtok(buffer, " ");
工作正常,但如果buffer
只包含空白,则可能 return 一个空指针。do
循环将在strcat(input, tok)
上调用未定义的行为。请改用for
或while
循环。- 代码中缺少
}
,不清楚您的意思是在第一次迭代后从while
循环中break
还是仅在结束时行。
这是修改后的版本:
#include <stdio.h>
#include <string.h>
int main(void) {
char buffer[50];
char input[sizeof buffer] = "";
printf("Enter a string: ");
if (fgets(buffer, sizeof(buffer), stdin)) {
char *tok = strtok(buffer, " \n");
while (tok) {
strcat(input, tok);
printf("found token: %s\n", tok);
tok = strtok(NULL, " \n");
}
printf("token string: %s\n", input);
}
return 0;
}