复制C字符串的正确方法
Proper way to copy C strings
有没有一种简单的方法可以复制C字符串?
我有const char *stringA
,我希望char *stringB
取该值(注意,stringB
不是const
)。我尝试了stringB=(char*) stringA
,但这使得stringB
仍然指向相同的内存位置,所以当stringA
后来更改时,stringB
也会更改。
我也尝试过strcpy(stringB,stringA)
,但似乎如果stringB
没有初始化为足够大的数组,就会出现segfault。不过,我对C字符串不是很有经验,是不是遗漏了一些显而易见的东西?
如果我只是将stringB
初始化为char *stringB[23]
,因为我知道我永远不会有超过22
个字符的字符串(并且允许空终止符),这是正确的方法吗?如果检查stringB
是否与其他C字符串相等,那么额外的空间会影响什么吗?
(在这里,仅仅使用字符串并不是一个解决方案,因为我需要最小的开销和对单个字符的轻松访问。)
您可以使用strdup()
返回C字符串的副本,如:
#include <string.h>
const char *stringA = "foo";
char *stringB = NULL;
stringB = strdup(stringA);
/* ... */
free(stringB);
stringB = NULL;
您也可以使用strcpy()
,但您需要首先分配空间,这并不难做到,但如果操作不正确,可能会导致溢出错误:
#include <string.h>
const char *stringA = "foo";
char *stringB = NULL;
/* you must add one to cover the byte needed for the terminating null character */
stringB = (char *) malloc( strlen(stringA) + 1 );
strcpy( stringB, stringA );
/* ... */
free(stringB);
stringB = NULL;
如果您不能使用strdup()
,我建议使用strncpy()
而不是strcpy()
。strncpy()
函数最多可复制--最多只能复制--n
字节,这有助于避免溢出错误。但是,如果是strlen(stringA) + 1 > n
,则需要自己终止stringB
。但是,一般来说,你会知道你需要什么尺寸的东西:
#include <string.h>
const char *stringA = "foo";
char *stringB = NULL;
/* you must add one to cover the byte needed for the terminating null character */
stringB = (char *) malloc( strlen(stringA) + 1 );
strncpy( stringB, stringA, strlen(stringA) + 1 );
/* ... */
free(stringB);
stringB = NULL;
我觉得strdup()
更干净,所以我试着在专门处理字符串的地方使用它。我不知道POSIX/非POSIX方法在性能方面是否有严重的缺点,但我不是C或C++专家。
请注意,我将malloc()
的结果强制转换为char *
。这是因为您的问题被标记为c++
问题。在C++中,需要强制转换malloc()
的结果。然而,在C中,您将而不是强制执行此操作。
编辑
有一个复杂的问题:strdup()
不在C或C++中。因此,将strcpy()
或strncp()
与预先确定大小的数组或malloc
指针一起使用。使用strncp()
而不是strcpy()
是一个好习惯,无论您在哪里使用该函数。这将有助于减少出错的可能性。
如果我只是将stringB初始化为char*stringB[23],因为我知道我的字符串永远不会超过22个字符(并且允许使用null终止符),这是正确的方法吗?
差不多。在C中,如果你确信字符串永远不会太长:
char stringB[MAX+1];
assert(strlen(stringA) <= MAX));
strcpy(stringB, stringA);
或者,如果字符串可能太长:
char stringB[MAX+1];
strncpy(stringB, stringA, MAX+1);
if (stringB[MAX] != ' ') {
// ERROR: stringA was too long.
stringB[MAX] = ' '; // if you want to use the truncated string
}
在C++中,您应该使用std::string
,除非您已经证明开销过高。许多实现都有"短字符串优化",这将避免短字符串的动态分配;在这种情况下,使用C样式数组将几乎没有开销。访问单个字符与使用C样式数组一样方便;在这两种情况下,s[i]
都将位置i
处的字符作为左值。复制成为stringB = stringA;
,没有未定义行为的危险。
如果您确实发现std::string
不可用,请考虑std::array<char,MAX+1>
:一个包含固定大小数组的可复制类。
如果检查字符串B是否与其他C字符串相等,那么额外的空间会影响什么吗?
如果使用strcmp
,则它将停止在最短字符串的末尾,并且不会受到额外空间的影响。
如果你想用纯C风格来做,那么:
char* new_string = strdup(old_string);
free(new_string);
如果你想用(某种)C++风格:
char* new_string = new char[strlen(old_string) + 1];
strcpy(new_string, old_string);
delete[] new_string;
您可能正在寻找strncpy
,它允许您从字符串中复制第一个n
字符。只需确保在复制到的字符串的位置n添加null终止符。
- 有哪些有效的方法可以消除一组 100 万个字符串>重复数据?
- 在 c++ 中对类中的 c 字符串动态数组进行排序的最佳方法是什么?
- 具有字符串化的可变参数宏的现代/通用方法
- 接收字符串并使用它来调用方法C++
- 如何分隔字符串并将标记传递给方法
- 是否有通用方法可以找到任何以 null 结尾的字符串的长度?
- 当映射包含字符串向量作为值时,从值中获取键的有效方法
- 在 C++11 中字符串化变量名称的替代方法
- 连接和压缩标准::vector<std::字符串的最佳方法>
- Esp8266 & Nodemcu:返回请求字符串的方法
- 将位字符串转储到二进制文件的最佳方法是什么
- 有没有一种 STL 方法可以找到字符串的所有排列,给出一个以 C++ 为单位的大小?
- 如何将字符串从 C++/CLI 方法返回到调用它的非托管C++
- 创建字符串数组的有效方法
- 如何使用字符串::replace方法写入文件
- 是否有更有效的方法来生成日期的REGEX字符串
- C++-将对象(如字符串)映射到表中成员函数的正确方法
- 有没有更快的方法从成员函数返回格式化字符串
- 有没有一种方法可以在不复制数据的情况下从string_view创建字符串流
- 从c++中的类指针对象调用方法(字符串)