如何使用visual c ++中的strncpy_s函数?

时间:2012-02-16 17:29:24

标签: c++ string visual-studio visual-c++ visual-studio-express

我正在学习C ++中的一些新东西,我试图从Visual C ++中测试这个strncpy_s函数。然而,由于程序崩溃我遇到了一些问题,我不知道最近发生了什么,但我确信这是一个非常愚蠢的问题。源代码是这样的:

#include "stdafx.h"
#include <iostream>
#include <cstdio>
#include <cstring>

int main()
{
    char *p;
    p=(char *)malloc(sizeof(char)*strlen("Hello!\n"));
    strncpy_s(p,strlen("Hello!\n"),"Hello!\n",strlen("Hello!\n"));
    std::cout << p;
    std::cout << strlen("Hello!\n") << std::endl;
    return 0;
}

正如我所说我不使用std :: string因为我想尝试这个新功能并知道它是如何工作的。

6 个答案:

答案 0 :(得分:2)

您需要再使用一个字符来终止字符('\0'),因此您需要将strlen("Hello!\n")替换为strlen("Hello!\n") + 1。您可以将此长度存储在某个变量中,而不是再次调用strlen。此外,由于您使用的是C ++,因此可以使用new / delete代替malloc / free

int len = strlen("Hello!\n") + 1;
char *p;
p = new char[len];
strncpy_s(p, len, "Hello!\n", len);
std::cout << p << len << std::endl;
delete[] p;

答案 1 :(得分:2)

我接受了我的评论,我更仔细地阅读了the documentation。您的代码传递了无效参数,并且正在调用无效参数处理程序。也许这就是发生的事情。即:

p=(char *)malloc(sizeof(char)*strlen("Hello!\n"));

此行为7个字符分配空间,这是字符串的长度,但没有足够的空间用于空终结符。 (这通常是一个错误)

strncpy_s的文档说:这些函数尝试将strSource的前D个字符复制到strDest,其中D是count的较小者和strSource的长度。 如果这些D字符符合在strDest(其大小以numberOfElements给出)并仍为空终结符留出空间,则会复制这些字符并附加终止空值; 否则,strDest [0]设置为空字符,并调用无效参数处理程序,如参数验证中所述。

您是否可能看到“无效参数处理程序”?

答案 2 :(得分:2)

'安全性增强'字符串函数主要用于在遇到问题时崩溃。

来自Microsoft's docs on strncpy_s()

  

这些函数尝试将strSource的前D个字符复制到   strDest,其中D是计数中的较小者和strSource的长度。   如果这些D字符符合strDest(其大小为   numberOfElements)并且仍为空终止符留出空间   复制这些字符并附加终止空值;   否则,strDest [0]设置为空字符和无效字符   调用参数处理程序,如参数验证中所述。

     

上段有例外。如果count是_TRUNCATE,   然后尽可能多地复制适合strDest的strSource   仍然留下了终止null的空间,它始终是附加的。

description of the Paramter Validation是:

  

找到无效参数时的C运行时的行为是   调用当前分配的无效参数处理程序。默认   无效参数调用Watson崩溃报告,这会导致   应用程序崩溃并询问用户是否要加载崩溃   转储到Microsoft进行分析。在调试模式下,参数无效   也会导致断言失败。

     

使用此功能可以更改此行为   _set_invalid_parameter_handler将无效参数处理程序设置为您自己的函数。 ...

您的示例程序提供的缓冲区太小了char(空终结符没有空间)。

因此,除非您明确更改strxxxx_s函数遇到错误时应执行的操作,否则您的程序将因设计而崩溃。这个想法是崩溃比可能打开安全漏洞的bug更好。

答案 3 :(得分:1)

strlen(s)只会告诉你没有NULL终结符的字符串的长度。要分配复制字符串的空间,通常使用strlen(s)+1为NULL终止符添加空间。

答案 4 :(得分:1)

您需要分配strlen(“Hello!\ n”)+ 1(对于null终止符)。而sizeof(char)完全没有意义,因为sizeof(char)在所有平台上都保证为1。

答案 5 :(得分:0)

如果您使用的是C ++,为什么要使用malloc或char *?

std::string p = "Hello!\n";
std::cout << p;
std::cout << p.length();

std::string* p = new std::string("Hello!\n");
std::cout << p;
std::cout << p->length();

但要回答原始问题,您可能需要使用strlen(p) + 1

如果您需要字符串中的字符*,则可以使用p.c_str()