我想将字符串复制到char数组中,而不是超出缓冲区。
因此,如果我有一个大小为5的char数组,那么我想将一个字符串中最多5个字节复制到其中。
这样做的代码是什么?
答案 0 :(得分:39)
这正是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;
}
如果您需要空终止,您应该执行以下操作:
str.copy(test, 4);
test[4] = '\0';
答案 1 :(得分:20)
首先,strncpy
几乎肯定不你想要什么。 strncpy
旨在用于相当具体的目的。它几乎完全在标准库中,因为它已经存在,而不是因为它通常很有用。
可能最简单的方法是做你想做的事情,比如:
sprintf(buffer, "%.4s", your_string.c_str());
与strncpy
不同,这可以保证结果将终止NUL,但如果源短于指定值,则不会在目标中填充额外数据(尽管后者不是目标时的主要问题)长度是5)。
答案 2 :(得分:7)
如果您的实现提供了一个(函数不在标准C库中),请使用函数 断开的链接以及目标站点上找不到的材料但它被广泛接受为零端接字符串的“安全”有限长度复制功能的事实上的标准名称。strlcpy
如果您的实施没有提供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
不是一个安全的有限长度字符串复制功能,不应该用于此目的。虽然你可以强迫strncpy
为此目的“工作”,但它仍然类似于用锤子驱动木螺钉。
答案 3 :(得分:3)
更新:我想我会尝试将一些答案和答案联系起来,这些答案让我确信我自己最初的膝跳反应很差。
首先,正如AndreyT在对这个问题的评论中指出的那样,截断方法(snprintf,strlcpy和strncpy)通常不是一个好的解决方案。通常最好根据缓冲区长度检查字符串string.size()
的大小,然后返回/抛出错误或调整缓冲区大小。
如果在你的情况下截断是正常的,恕我直言,strlcpy是最好的解决方案,是确保空终止的最快/最小开销方法。不幸的是,它不在许多/所有标准发行版中,因此不可移植。如果你做了很多这些,可能值得提供你自己的实现,AndreyT给了example。它以O(结果长度)运行。参考规范还返回复制的字节数,这有助于检测源是否被截断。
其他好的解决方案是sprintf和snprintf。它们是标准的,因此是可移植的,并提供安全的空终止结果。它们比strlcpy(解析格式字符串说明符和变量参数列表)有更多的开销,但除非你做了很多这些,否则你可能不会注意到它们之间的区别。它也以O(结果长度)运行。 snprintf总是安全的,如果格式说明符错误,sprintf可能会溢出(正如其他人所说,格式字符串应该是"%.<N>s"
而不是"%<N>s"
)。这些方法还返回复制的字节数。
特殊情况解决方案是strncpy。它在O(缓冲区长度)中运行,因为如果它到达src的末尾,它会将剩余的缓冲区清零。仅在需要将缓冲区的尾部置零或确信目标和源字符串长度相同时才有用。另请注意,它不安全,因为它不一定是null终止字符串。如果源被截断,则不会追加null,因此请使用空赋值顺序调用以确保空终止:strncpy(buffer, str.c_str(), BUFFER_LAST); buffer[BUFFER_LAST] = '\0';
答案 4 :(得分:3)
一些不错的libc版本为strcpy(3)
/ strncpy(3)
- strlcpy(3)
提供了非标准但非常好的替代品。
答案 5 :(得分:2)
void stringChange(string var){
char strArray[100];
strcpy(strArray, var.c_str());
}
我想这应该有效。它将从字符串复制到char数组。
答案 6 :(得分:1)
我认为snprintf()非常安全且相似
snprintf ( buffer, 100, "The half of %d is %d", 60, 60/2 );
null字符会自动追加它:)
答案 7 :(得分: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"
使用strncpy
,您最多可以将 n 个字符从源复制到目标。但请注意,如果源字符串最多为 n 字符长,则目标不会以空值终止;你必须自己把终止空字符放入其中。
长度为5的char数组最多可包含4个字符的字符串,因为第5个字符必须是终止空字符。因此,在上面的代码中, n = 4。
答案 8 :(得分:0)
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';
答案 9 :(得分:0)
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';
这是基本的高效设计。
答案 10 :(得分:-1)
如果你总是有一个5号的缓冲区,那么你可以这样做:
std::string s = "Your string";
char buffer[5]={s[0],s[1],s[2],s[3],'\0'};
编辑: 当然,假设你的std :: string足够大。