如何:保护内存 - strncat()?

时间:2011-10-27 21:29:32

标签: c windows string coding-style

function(char *a, char *b)
{

   char newStr[100];

   strncpy(newStr, a, sizeof(newStr)); //Line 1 - copy no more than 100 bytes  

   strncat(newStr, b, (sizeof(newStr) -  strlen(newStr)));   //Line 2 - ?

   newStr[99] = NULL; //Line 3 - null terminate string

}

第2行:正确指定100个字节减去 strlen 从a复制的内容以确保我不复制100个字节?

谢谢。

2 个答案:

答案 0 :(得分:3)

strncpy()不会做你认为它做的事情。

strncat()strcat()的“更安全”版本,可让您指定目标数组的大小。

strncpy() strcpy()的相应“更安全”版本。如果目标数组太大,strncpy()将使用空字符填充它; 99%的时间这是不必要的,因为您只需要一个'\0'来标记字符串的结尾。更糟糕的是,如果目标数组太小,strncpy()将复制尽可能多的字符并使目标无法终止

strncpy()是为早期Unix系统用来存储文件名的模糊数据结构而设计的。文件名存储在用空字节填充的固定长度的14字节缓冲区中。如果文件名长度恰好是14个字符,则不会有空终止符。 这不是字符串

如果那是你想要的那种数据结构,那么strncpy()就是这样。否则,不要使用它;确认目标足够大后,只需使用strcpy()

以下是我写这个函数的方法:

void function(char *a, char *b)
{
    char newStr[100];

    /* Make newStr an empty string so you can concatenate onto it */
    newStr[0] = '\0';
    strncat(newStr, a, sizeof newStr - 1);                  /* edited */
    strncat(newStr, b, sizeof newStr - strlen(newStr) - 1); /* edited */

    /* Presumably you do something with newStr here */
}

注意:

  1. 声明函数的返回类型。如果你没有明确地声明它,你的编译器可能会默认为int,但这样的风格很差,而且语言功能已经过时了。
  2. 避免使用strncat()
  3. 我使用'\0'而非NULL来终止字符串。 NULL是一个空指针常量;不要用它来表示null 字符
  4. 此处存在严重的低效率:第二个strncat()必须从newStr的开头重新扫描。对于少量的短字符串来说,这并不是什么大问题,但是对于大量字符串被连接到一个大型目标数组中,它会导致严重的减速。有很多方法,但它们可能是非标准的(strlcpy()strlcat())或不方便。

    编辑:感谢Matthew在我的代码中指出了错误。我我已修好它们;如果我用新的错误替换旧的错误,我相信我可以依靠某人来打击我。

    另一种选择是:

    snprintf(newStr, sizeof newStr, "%s%s", a, b);
    

答案 1 :(得分:2)

这几乎是正确的。首先,NUL终止线:

newStr[99] = NULL;

错了。

strncat总是NUL-teriminates,第三个参数是写 NOT 的最大字节数,包括NUL。

假设,如果strncat没有NUL终止,那么该行的问题是它总是会写入数组的最后一个元素,即使实际的字符串可能要短得多。如果a和b是“Hello”和“world!”,那么最终的数组将是:

H | E |升| L | O |,| | W | O | R |升| d |!| G | I | B | C |ë| R | I | S | H

其中gibberish表示这些位置的数组的先前内容。只有99岁,在大多数这些未初始化的残余物之后,才会有一个NUL。

编辑:另外,基思对strncpy是正确的。他的功能部分正确,但第二个函数可以溢出缓冲区,因为它没有考虑已经存在的字符串。两行组合可以写入199个字符(包括NUL)。

另外,我错误的第三个参数包括NUL。这让我们(改编自Keith):

void function(char *a, char *b)
{
    char newStr[100];

    /* Make newStr an empty string so you can catenate onto it */
    newStr[0] = '\0';
    strncat(newStr, a, sizeof newStr - 1);
    strncat(newStr, b, sizeof newStr - strlen(newStr) - 1);

    /* Presumably you do something with newStr here */
}