strcat 如何影响 strtok?

Posted

技术标签:

【中文标题】strcat 如何影响 strtok?【英文标题】:How does strcat affect the strtok? 【发布时间】:2021-12-29 10:34:21 【问题描述】:

假设我们需要通过连接输入的标记将用户的输入复制到另一个字符串中,例如"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] = '\0';

      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

我很难理解 strtokstrcat 无法附加 tok 的关系。除了tok(根据文档)由strcat 复制之外,它们不共享变量,因此无论strcat 正在做什么都不应该影响strtok 的行为,并且程序应该在第二个@987654331 上崩溃@至少打电话,对吧?但是我们看到strcat 在堆栈粉碎被检测到之前被调用了 3 次。你能解释一下原因吗?

【问题讨论】:

未定义的行为(例如写入input 的次数超出了它的容量)是未定义的。 一旦你故意溢出input,所有的赌注都会被取消。这会导致未定义的行为。 “所以无论 strcat 做什么都不应该影响 strtok”。你为什么那么想?溢出的input 可能会覆盖包括buffer 在内的任何内容,这很可能会影响strtok 上的buffer @DevSolar 是的,但它会从一个运行到另一个运行,因此从技术上讲,它是一个“已定义”的未定义行为。我认为 C 中的 undefined 意味着每次运行都是随机垃圾。 不,技术上这是未定义的行为,即使这可能是可重现和可解释的,它仍然意味着您的代码已损坏,您无权期望可重现性。无论是随机垃圾,每次都相同的结果,还是您的计算机将您的硬盘驱动器内容上传到云空间。 ;-) 这使得解释在这种特定情况下发生的事情变得毫无意义,因为它可能会因不同的编译器版本、标准库实现或月相而有所不同。 char input[1]; // set it too small你成功了! 【参考方案1】:

对于初学者这个数组

char input[1];

未初始化且不包含字符串。

所以这个 strcat 调用

strcat(input, tok);

调用未定义的行为也是因为数组输入不足以存储复制的字符串。它可以覆盖数组之外的内存。

【讨论】:

那么数组之外的内存是否包含buffer数据而strcat只是覆盖它? @minerals 可以覆盖变量 tok 或 buffer 或一起覆盖。【参考方案2】:

代码存在多个问题:

char input[1]; 太小了,什么都做不了。您不能将行中的标记连接到这个小数组中。为了简单起见,您必须使用足够的长度来定义它,即与buffer 相同的长度。 input 必须初始化为空字符串,strcat(input, tok); 才能具有定义的行为。按照编码,第一次调用 strcat 会破坏导致观察到的行为的其他变量,但请注意,由于这种未定义的行为,可能会发生其他任何事情。 char *tok = strtok(buffer, " "); 工作正常,但如果 buffer 仅包含空格(如果有的话)可能会返回空指针。然后do 循环将在strcat(input, tok) 上调用未定义的行为。请改用forwhile 循环。 代码中缺少,不清楚您的意思是在第一次迭代后从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;

【讨论】:

char input[1]; 是故意的,我一边看书一边做实验。感谢您指出空指针。缺少大括号只是复制粘贴后的错误编辑。

以上是关于strcat 如何影响 strtok?的主要内容,如果未能解决你的问题,请参考以下文章

strtok函数怎么用啊?

深入了解一些字符串函数,内存函数

字符串和字符函数

字符串和字符函数

字符串和字符函数

字符串和字符函数