【问题标题】:strncat() is copying to the same string againstrncat() 再次复制到相同的字符串
【发布时间】:2014-10-27 02:52:47
【问题描述】:

我试图在 C 编程中连接两个字符串。这是我的代码:

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

int main(int argc, char const *argv[])
{
    /* code */
        char s1[3],s2[34];

        strncat(s1,"mv ",3);
        strncat(s2,"  /home/xxxxxxx/.local/share/Trash/",34);

        printf("%s \n",s1);

        return 0;

}

当我尝试打印s1 中的值时,它会打印mv /home/xxxxxxx/.local/share/Trash 作为输出。为什么我为 s2 设置的值会与字符串 s1 一起添加?如果问题已经被问到,请放上链接。

【问题讨论】:

  • 使用strncat() 真的很难!你提供的长度是多少?这不是s2 中可用的总长度(在您的示例中);它是在s2sizeof(s2) - strlen(s2) - 1 的当前内容之后剩下的长度(假设您解决了s1s2 都不是以null 结尾的字符串的问题)。也不清楚为什么你想要s1 中的命令和s2 中的参数。使用snprintf(s2, sizeof(s2), "%s %s", "mv", "/home/…"); 可能会做得更好。
  • 避免使用strncat(a, b, sizeof(a));。在确保a 中包含合法字符串后,最好使用strncat(a, b, sizeof(a)-1); a[sizeof(a)-1] = '\0';。这确保没有太多的char 被连接,并且数组被'\0' 终止。

标签: c string concatenation string-concatenation


【解决方案1】:

您的代码中有undefined behavior,因为s1s2 都没有被初始化。未初始化(非静态)的局部变量具有不确定的值,并且它们不太可能具有字符串终止符,strncat 需要找到字符串的结尾才能知道在哪里追加源字符串。

解决上述问题后,当strncat 尝试将字符串终止符写入数组末尾之外时,您还会遇到另一种未定义行为的情况。

另外,您没有连接两个字符串,因为 s1s2 是两个不相关的数组,您只需将文字字符串附加到两个数组的末尾而不是一起。


你可以做的是分配一个足够大的数组来容纳两个字符串和字符串终止符,然后将第一个字符串复制到数组中,然后附加第二个字符串。

或者不使用例如snprintf(或_snprintf正在使用Microsoft Windows运行时库)来构造字符串。

char s[100];
snprintf(s, sizeof(s), "mv %s %s", somepath, someotherpath);

【讨论】:

    【解决方案2】:

    s1 定义为

    char s1[3],
    

    即它具有三个元素(字符)。当strncat被执行时

    strncat(s1," mv",3);
    

    这三个元素分别用 { ' ', 'm', 'y' }

    之后这个数组就没有终止零了。

    printf 函数中的格式说明符%s 输出一个字符数组,直到遇到终止符零。由于数组 s1 没有终止零,因此 printf 继续输出数组之外的所有字节。因为在数组 s1 之后有数组 s2

    char s1[3],s2[34];
    

    然后它也被输出,直到遇到终止零。

    考虑到函数strncat 要求目标字符串以零结尾。但是您没有初始化 s1。所以程序的行为是不确定的。

    如果您希望程序正常运行,您必须将数组 s1 定义为具有四个字符

    char s1[4] = { '\0' },s2[34];
    
    strncat(s1,"mv ",4);
    

    或者写起来会更简单

    char s1[4] = { '\0' },s2[34];
    
    strcat( s1, "mv " );
    

    甚至是以下方式

    char s1[4],s2[34];
    
    strcpy( s1, "mv " );
    

    那就是使用函数strcpy而不是strncpy会更好

    【讨论】:

      【解决方案3】:

      当我尝试在 s1 中打印值时,它会打印 mv /home/ashwini/.local/share/Trash 作为输出。

      这是未定义的行为:s1 不是以 null 结尾的,因为它在三个字符的空格中包含三个字符的字符串;空终止符没有空间。

      您的s2 字符串缓冲区恰好位于内存的相邻区域,因此它也会被打印,直到printf 遇到s2 的空终止符。

      s1 分配更多内存并考虑空终止将解决此问题:

      char s1[4],s2[36];
      s1[0] = '\0';
      strncat(s1," mv", 4);
      s2[0] = '\0';
      strncat(s2,"  /home/xxxxxxx/.local/share/Trash/", 36);
      

      但是,strncat 不适用于处理常规字符串:它是为使用不再广泛使用的固定长度字符串而设计的。不幸的是,C 标准库不包含strlcat,它对“常规”C 字符串具有适当的语义。不过,它可以作为库扩展在许多系统上使用。

      Demo.

      【讨论】:

      • 谢谢。但现在我得到了这个:*** stack smashing detected ***: ./a.out terminated Aborted (core dumped)
      • @bhargav 您的其他字符串也有同样的问题。看看编辑(demo)。
      猜你喜欢
      • 2014-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多