如果strcat函数中的目标字符串不是以null结尾,那么它是未定义的行为吗?

时间:2016-08-11 09:49:44

标签: c string language-lawyer strcat

以下计划

// Code has taken from http://ideone.com/AXClWb
#include <stdio.h>
#include <string.h>

#define SIZE1 5
#define SIZE2 10
#define SIZE3 15

int main(void){
    char a[SIZE1] = "Hello";
    char b[SIZE2] = " World";
    char res[SIZE3] = {0};

    for (int i=0 ; i<SIZE1 ; i++){
        res[i] = a[i];
    }

    strcat(res, b);
    printf("The new string is:  %s\n",res);
    return 0;
}

有明确定义的行为。根据要求,源字符串b以空值终止。但是如果行

那会是什么行为
char res[SIZE3] = {0};  // Destination string

替换为

char res[SIZE3];  

标准是否明确说明目标字符串也将被终止?

4 个答案:

答案 0 :(得分:3)

我认为man 明确表示

  

描述

     

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

Enphasis mine

BTW我认为strcat在连接新字符串之前开始搜索到目标字符串中的null terminator,所以它显然是UB,只要dest字符串具有自动存储。

在建议的代码中

for (int i=0 ; i<SIZE1 ; i++){
    res[i] = a[i];
}

5字符a而不是空终结符复制到res字符串,以便从514的其他字节未初始化。

标准也谈到了safaer实现strcat-s

  

K.3.7.2.1 strcat_s函数

     

概要

    #define _ _STDC_WANT_LIB_EXT1_ _ 1
      #include <string.h>
      errno_t strcat_s(char * restrict s1,
           rsize_t s1max,
           const char * restrict s2);
     

<强>运行约束

     

2 m 在输入时表示值 s1max - strnlen_s(s1,s1max)   的 strcat_s

我们可以看到strlen_s总是返回dest缓冲区的有效大小。从我的观点来看,这个实现是为了避免问题的UB而引入的。

答案 1 :(得分:2)

如果您将res保留为未初始化,则在将a复制到res(for for循环)后,res中没有NUL终止符。因此,如果目标字符串不包含NUL字节,则strcat()的行为是未定义的。

基本上strcat()要求它的两个参数都是字符串(即两者都必须包含终止的NUL字节)。否则,它是undefined behaviour。这个 从strcat()

的描述中可以明显看出

§7.23.3.2, strcat() function

  

strcat函数附加s2 指向的字符串的副本   (包括终止空字符)到字符串的末尾   由s1指出。 s2的初始字符会覆盖null   s1末尾的字符。

(强调我的)。

答案 2 :(得分:2)

TL; DR 是。

由于这是一个语言律师问题,让我加上我的两分钱。

引用C11,章节§7.24.3.1/ 2(强调是我的

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

strcat函数附加s2指向的字符串的副本(包括   终止空字符)s1指向的字符串的末尾。最初的字符   s2的覆盖范围覆盖s1末尾的空字符。[...]

,根据定义,字符串 以null结尾,引用§7.1.1/ 1

  

string 是一个连续的字符序列由第一个null终止并包含   字符。

因此,如果源char数组不是以空值终止的(即,不是字符串),strcat()可能会超出搜索范围< em>结束,它调用undefined behavior

根据您的问题,char res[SIZE3];是一个自动局部变量,将包含不确定的值,如果用作strcat()的目标,将调用UB。

答案 3 :(得分:1)

如果char res[SIZE3];位于堆栈上,则会包含随机/未定义的内容。
你永远不会知道res[SIZE3]中是否会有一个零字节,所以strcat这是未定义的。

如果char res[SIZE3];未初始化的全局,那么它将全部为零,这将使其表现为空c-string < / em>,strcat将是安全的(只要SIZE3足够大,可以附加你的内容)。