C++ 如何将字符串复制到C++;不经过缓冲区

C++ 如何将字符串复制到C++;不经过缓冲区,c++,string,g++,char,C++,String,G++,Char,我希望将字符串复制到char数组中,而不使缓冲区溢出 因此,如果我有一个大小为5的字符数组,那么我想从一个字符串复制最多5个字节到它 代码是什么?更新:认为我会尝试将一些答案结合在一起,这些答案让我确信我自己最初的下意识strncpy反应很差 首先,正如AndreyT在对这个问题的评论中所指出的,截断方法(snprintf、strlcpy和strncpy)通常不是一个好的解决方案。通常最好根据缓冲区长度检查字符串的大小string.size(),并返回/抛出错误或调整缓冲区大小 如果在您的情况下

我希望将字符串复制到char数组中,而不使缓冲区溢出

因此,如果我有一个大小为5的字符数组,那么我想从一个字符串复制最多5个字节到它


代码是什么?

更新:认为我会尝试将一些答案结合在一起,这些答案让我确信我自己最初的下意识strncpy反应很差

首先,正如AndreyT在对这个问题的评论中所指出的,截断方法(snprintf、strlcpy和strncpy)通常不是一个好的解决方案。通常最好根据缓冲区长度检查字符串的大小
string.size()
,并返回/抛出错误或调整缓冲区大小

如果在您的情况下截断是可以的,那么IMHO是最好的解决方案,是确保空终止的最快/开销最小的方法。不幸的是,它不在许多/所有标准发行版中,因此不可移植。AndreyT给出了一个例子,如果您正在做很多这些工作,那么提供您自己的实现可能是值得的。它以O(结果长度)为单位运行。参考规范还返回复制的字节数,这有助于检测源是否被截断

其他好的解决方案是和。它们是标准的,因此是可移植的,并提供安全的空终止结果。它们比strlcpy(解析格式字符串说明符和变量参数列表)有更多的开销,但是除非您做了很多这样的工作,否则您可能不会注意到它们之间的差异。它也以O(结果长度)为单位运行。snprintf总是安全的,如果格式说明符错误,sprintf可能会溢出(正如其他人所指出的,格式字符串应该是
“%.s”
而不是
“%s”
)。这些方法还返回复制的字节数

一个特例解决方案是。它以O(缓冲区长度)运行,因为如果它到达src的末尾,它会将缓冲区的其余部分归零。仅在需要将缓冲区尾部归零或确信目标字符串和源字符串长度相同时才有用。还请注意,它并不安全,因为它不一定以null结尾字符串。如果源代码被截断,则不会追加null,因此使用null赋值顺序调用以确保null终止:
strncpy(buffer,str.c_str(),buffer_LAST);缓冲区[buffer_LAST]='\0'

std::string my_string("something");
char* my_char_array = new char[5];
strncpy(my_char_array, my_string.c_str(), 4);
my_char_array[4] = '\0'; // my_char_array contains "some"
使用,最多可以将n个字符从源复制到目标。但是,请注意,如果源字符串的长度最多为n个字符,则目标字符串不会以null结尾;您必须自己将终止的空字符放入其中


长度为5的字符数组最多只能包含4个字符的字符串,因为第5个字符必须是终止的空字符。因此,在上面的代码中,n=4。

一些不错的libc版本提供了对strcpy(3)
/
strncpy(3)
->的非标准但很好的替代

如果您没有,源代码可以从存储库免费获得

std::string str = "Your string";
char buffer[5];
strncpy(buffer, str.c_str(), sizeof(buffer)); 
buffer[sizeof(buffer)-1] = '\0';
最后一行是必需的,因为strncpy不能保证NUL终止字符串(昨天已经讨论了动机)

如果使用宽字符串,而不是
sizeof(buffer)
,则使用
sizeof(buffer)/sizeof(*buffer)
,或者更好的是,使用类似

#define ARRSIZE(arr)    (sizeof(arr)/sizeof(*(arr)))
/* ... */
buffer[ARRSIZE(buffer)-1]='\0';
首先,这几乎肯定不是你想要的<代码>strncpy是为一个相当特定的目的而设计的。它在标准库中几乎完全是因为它已经存在,而不是因为它通常是有用的

也许做你想做的事情最简单的方法是:

sprintf(buffer, "%.4s", your_string.c_str());
strncpy
不同,这保证了结果将被NUL终止,但如果源长度小于指定长度,则不会在目标中填充额外数据(尽管目标长度为5时,后者不是主要问题)。

使用函数断开链接,如果您的实现提供了一个复制函数(该函数不在标准C库中),那么在目标站点上找不到该函数,但它被广泛接受为零终止字符串的“安全”有限长度复制函数的事实标准名称

如果您的实现没有提供strlcpy函数,请自己实现一个。例如,像这样的东西可能适合你

char *my_strlcpy(char *dst, const char *src, size_t n)
{
  assert(dst != NULL && src != NULL);

  if (n > 0)
  {
    char *pd;
    const char *ps;

    for (--n, pd = dst, ps = src; n > 0 && *ps != '\0'; --n, ++pd, ++ps)
      *pd = *ps;

    *pd = '\0';
  }

  return dst;
}
(实际上,事实上接受的
strlcpy
返回
size\t
,因此您可能更愿意实现接受的规范,而不是我上面所做的)


注意那些建议用于此目的的答案
strncpy
不是一个安全的有限长度字符串复制函数,不应用于此目的。虽然您可以强制strncpy为此“工作”,但它仍然类似于用锤子敲打木螺钉。

如果您总是有一个大小为5的缓冲器,则可以执行以下操作:

std::string s = "Your string";
char buffer[5]={s[0],s[1],s[2],s[3],'\0'};
编辑:
当然,假设您的std::string足够大。

这正是
std::string
的复制函数所做的

#include <string>
#include <iostream>

int main()
{

    char test[5];
    std::string str( "Hello, world" );

    str.copy(test, 5);

    std::cout.write(test, 5);
    std::cout.put('\n');

    return 0;
}
char mystring[101];//100个字符的字符串加上终止符
char*任何_输入;
任何输入=“示例”;
迭代=0;
while(任意输入[迭代]!='\0'&&迭代<100){
mystring[iterate]=任何_输入[iterate];
迭代++;
}
mystring[iterate]='\0';
这是最基本的有效设计

我认为snprintf()是非常安全和简单的

snprintf ( buffer, 100, "The half of %d is %d", 60, 60/2 );
空字符为自动附加到结尾:)


我想这应该行得通。它会将表单字符串复制到一个字符数组。

std::string,不知道任何其他类型的字符串。有字符串、一些或多或少为人所知的库字符串和数不清的本地实现。+1表示唯一答案。但是,相对于strncpy(buffer,str.c_str(),4),这不是有很多不必要的开销吗;缓冲区[4]='\0'?@academicRobot:您测试过它了吗,或者注意到了差异吗?:)
char mystring[101]; // a 100 character string plus terminator
char *any_input;
any_input = "Example";
iterate = 0;
while ( any_input[iterate] != '\0' && iterate < 100) {
    mystring[iterate] = any_input[iterate];
    iterate++;
}
mystring[iterate] = '\0';
snprintf ( buffer, 100, "The half of %d is %d", 60, 60/2 );
void stringChange(string var){

    char strArray[100];
    strcpy(strArray, var.c_str()); 

}