【问题标题】:The correct way to use `strcat()` when the destation does not have enough space?当目标没有足够的空间时使用`strcat()`的正确方法?
【发布时间】:2019-02-12 22:00:05
【问题描述】:

man strcat 说以下内容。

char *strcat(char *restrict s1, const char *restrict s2);

字符串 s1 必须有足够的空间来保存结果。

s1没有足够空间时的正确处理方法是什么?

【问题讨论】:

  • 你使用strncat()
  • ^ 请注意,strncat 经常被错误地使用。第三个参数是从源读取的最大字符数,不包括空终止符。这不是 dest 缓冲区大小,也不是 dest 缓冲区剩余大小。

标签: c string strcat


【解决方案1】:

如果s1 没有足够的空间来容纳strlen(s1) + strlen(s2) + 1,则尝试使用strcat(s1, s2) 会有未定义的行为。

strcat 中没有内部检查 s1 的缓冲区溢出。如果你溢出,你就会溢出。但是,如果使用正确,有一些特定于平台的替代方案可以降低溢出的风险。作为一名 Windows 开发人员,我更喜欢 <strsafe.h> 中的 StringCchCatStringCbCat

如果你想保证strcat的安全,你可以自己封装。比如:

int safe_strcat(char *s1, char *s2, size_t s1_size)
{
    if (strlen(s1) + strlen(s2) + 1 > s1_size)
    {
        return 0;
    }
    strcat(s1, s2);
    return 1;
}

【讨论】:

    【解决方案2】:

    strcat(s1, s2); 可能导致溢出,因此请注意“字符串 s1 必须有足够的空间来保存结果”。是有保证的。

    假设s1 可以容纳N 字符:N-1'\0' + 空字符

    目的地空间不足时使用strcat()的正确方法?

    当串联可能溢出时,我看不到要使用strcat() 的应用程序。而是使用其他功能。


    检测潜在的溢出:

    1. 在通话前测试strlen(s1), strlen(s2)

      size_t l1 = strlen(s1);
      assert(l1 < N); // This really should be true already.
      N -= l1;
      size_t l2 = strlen(s2);
      if (l1 >= N) Handle_TooBigSomehow();
      strcpy(s1 + l1, s2);
      
    2. 使用strncat(char * restrict s1, const char * restrict s2, size_t n)

    注意这里的n 不是 Ns1 可用的大小。

    strncat 函数追加不超过n 个字符(一个空字符和 后面的字符不附加)从s2 指向的数组到s1 指向的字符串的末尾。 s2 的初始字符覆盖s1 末尾的空字符。终止的空字符总是附加到结果中。 C11 §7.23.3.2 2

        size_t l1 = strlen(s1);
        assert(l1 < N); // This really should be true already.
        strncat(s1, s2, N - 1 - l1);
        // or faster
        strncat(s1 + l1, s2, N - 1 - l1);
    

    不幸的是,没有明确的迹象表明空间不足,但至少没有溢出,s1 以空字符结尾。

    【讨论】:

      【解决方案3】:

      程序员有责任知道 s1 的大小。如果你没有足够的空间,你可以调用 realloc(s1,num_of_bytes) 来分配更多的空间。

      【讨论】:

      • 不,你不能。不能保证s1 一开始就是动态内存,即使是,调用者也永远不会知道realloc()
      • 当然它只适用于动态分配的空间。在调用 strcat 之前,程序员必须检查字符串的大小和可用空间,如果需要更多,则重新分配 s1。
      • 如果您已经知道s1 的大小,您应该使用strcpy(&amp;s1[len1], .. 并且根本不应该使用strcat()(这样CPU 就不需要搜索s1 无缘无故)。如果您知道s1s2 的大小(您需要知道realloc()),那么您应该使用memcpy()
      • 问题是关于如何处理使用 strcat 并在目标字符串中需要更多空间的情况。基本上,我们只有几个选择:如果可能,添加空间,中断代码执行并将错误状态报告给调用函数或简单地终止。如果您使用其他成语而不是 strcat 来进行字符串连接,这不是问题的答案。
      猜你喜欢
      • 2011-09-03
      • 1970-01-01
      • 1970-01-01
      • 2022-09-28
      • 1970-01-01
      • 2019-01-21
      • 1970-01-01
      • 1970-01-01
      • 2021-05-11
      相关资源
      最近更新 更多