【问题标题】:Size definition of strcat() functionstrcat() 函数的大小定义
【发布时间】:2014-01-04 14:56:25
【问题描述】:

问题是我为什么要定义字符串的大小(string[] 应该是string[some-number]) 当程序如下时,它给了我Abort trap: 6

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

int main(void)
{
  char buffer1[] = "computer";
  char string[]="program";
  strcat( buffer1, string );
  printf( "buffer1 = %s\n", buffer1 );

}

这是来自http://www.tutorialspoint.com/cprogramming/c_data_types.htm 的程序,它运行良好:

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

int main ()
{
   char str1[12] = "Hello";
   char str2[12] = "World";
   char str3[12];
   int  len ;

   /* copy str1 into str3 */
   strcpy(str3, str1);
   printf("strcpy( str3, str1) :  %s\n", str3 );

   /* concatenates str1 and str2 */
   strcat( str1, str2);
   printf("strcat( str1, str2):   %s\n", str1 );

   /* total lenghth of str1 after concatenation */
   len = strlen(str1);
   printf("strlen(str1) :  %d\n", len );

   return 0;
}

什么是错误?即使我在程序中定义了所有字符串的大小,我的代码仍然给出Abort trap:6?

【问题讨论】:

    标签: c string size strcat


    【解决方案1】:

    来自 strcat 的手册页:

    描述 strcat() 函数将 src 字符串附加到 dest 字符串,覆盖终端 在 dest 的末尾添加一个空字节 ('\0'),然后添加一个终止空字节。这 字符串不能重叠,dest 字符串必须有足够的空间存放结果。如果 dest 不够大,程序行为不可预测;缓冲区溢出是一个 最喜欢的攻击安全程序的途径。

    当你声明你的字符串时,编译器将你的初始字符串的大小分配为 9(resp.8),用于 buffer1(resp.string)(包括 '\0')。

    因此,strcat 将产生 9 - 1 + 8(即 16 个字节),但只有 9 个可用。

    【讨论】:

      【解决方案2】:

      您的strcat 是缓冲区溢出buffer1,它只能容纳strlen("computer")+1 字节。省略数组大小并不意味着“动态”数组!当您指定数组的大小时,您将保留任意数量的字节:当然,您需要再次避免缓冲区溢出。

      所以,

       strcpy(str3, str1);
      

       strcat( str1, str2);
      

      没问题,因为str3 的大小对于str1 来说已经足够了,而str1 对于strlen(str1) + strlen(str2) + 1 来说就足够了,即正好是 11:5(你好)+5(世界)+1(终结者)。选择幻数 12 是有原因的,它大到足以容纳字符串和终结符。

      关于 C 字符串

      C 字符串是最后一个为“null”的字符数组'\0',即它们是最后一个为 0 的字符数组。需要此终止符以便与字符串相关的函数可以理解字符串的结束位置.

      如果碰巧在字符串的中间发现一个空字节,从 C 字符串函数的角度来看,字符串将在该点结束。例如

      char buffer1[] = "computer\0program";
      // array: { 'c', 'o', ... '\0', 'p', 'r', 'o', .., 'm', '\0' }
      
      // ...
      printf("%s\n", buffer1);
      

      将仅打印computer。但是此时缓冲区将足够大以容纳计算机和程序,一个终止符(和另一个额外的字节),因为编译器计算了 char 数组的大小,考虑到语法上以第二个 " 结尾的字符的文字序列.

      但对于所有 C 字符串函数,buffer1 中包含的字符串是 computer。另请注意,sizeof buffer1 将给出正确的缓冲区大小,即 17,而 strlen(buffer1) 的结果仅为 8。

      【讨论】:

      • 为什么是+2 而不是+1?因为我们只在 buffer1 结束后使用单个 \0?
      • 1 确实足够了。我错了。但偶数更好。或者他们想在 Hello 和 World 之间添加一个空格
      • 但是,当我定义 buffer1 足以容纳它们(16)时,string 的大小应该仍然是 +18),为什么?那是因为我们使用的是\0string,而不是buffer1 的吗?
      • 所有 C 字符串都是以 null 结尾的,并且必须以 null 结尾才能使字符串函数正常工作(它们需要知道字符串在哪里结束)。因此,如果要连接长度为 n1 和 n2 的两个字符串,则需要 n1+n2+1 个字节。当你想为字符串 n1 提供足够的空间时,你需要 n1+1 个字节;对于字符串 2,您需要 n2+1 个字节。以此类推
      • 如果你不“写入”到string,你不必担心缓冲区长多少字节。由于您让编译器选择正确的大小,string 将能够容纳strlen(string) + 1 字节,如前所述,仅此而已。由于字符串必须以 null 结尾,因此您可以记住的最长字符串为 strlen("program") 字节长。但是,如果您不处理 C 字符串,例如,您可以使用该缓冲区来存储额外的字节。 memcpy(string, "program1", 8) 可以,但是你不能使用 string 作为 C 字符串。
      【解决方案3】:

      strcat的第一个参数是用来存储结果的,所以它必须有足够的空间来存放连接的字符串。

      在您的代码中:

      char buffer1[] = "computer";
      

      相当于:

      char buffer1[9] = "computer";
      

      定义了一个 char 数组,其空间刚好可以容纳字符串 "computer",但没有足够空间容纳结果。

      【讨论】:

      • 这意味着 strcat() 函数不能用于组合 2 个字符串,而是将第二个字符串放在第一个字符串的 \0?对吗?
      • @MotherLand 是的,strcat 将第二个字符串放入前一个\0 的第一个字符串中,并在新的末尾放入一个新的\0
      • 但是,如果我定义第一个数组的大小足以容纳buffer1string\0string 的大小应该是+1 但我们不使用它?
      【解决方案4】:
      char buffer1[] = "computer";
      

      创建一个足以容纳 9 个字符的缓冲区(strlen("Hello" + 1 byte for \0))。如果您向其写入更多数据,您最终会得到 未定义的行为 (UB)。这就是您执行 strcat 时会发生的情况。
      UB 意味着程序可能会崩溃或显示任何行为。你很幸运,一个带有 UB 的程序崩溃了,因为它不需要,但如果它确实发生了,至少有迹象表明它有问题。大多数情况下,带有 UB 的程序将继续正确运行,并在您最不希望或不希望它们发生时崩溃。

      【讨论】:

        猜你喜欢
        • 2013-10-14
        • 2016-07-17
        • 1970-01-01
        • 2019-03-26
        • 2019-11-26
        • 2013-10-08
        • 1970-01-01
        • 2019-08-10
        • 2020-09-13
        相关资源
        最近更新 更多