16

有没有一种简单的方法来复制 C 字符串?

我有const char *stringA,我想char *stringB取值(注意stringB不是const)。我试过stringB=(char*) stringA了,但这stringB仍然指向相同的内存位置,所以当stringA以后更改时,stringB也会这样做。

我也试过strcpy(stringB,stringA)了,但似乎如果stringB没有初始化为足够大的数组,就会出现段错误。不过,我对 C 字符串并不是很有经验,我是否遗漏了一些明显的东西?

如果我只是初始化stringBchar *stringB[23],因为我知道我永远不会有一个比22字符长的字符串(并允许空终止符),这是正确的方法吗?如果stringB检查与其他 C 字符串的相等性,额外的空间会影响什么吗?

(并且在这里仅使用字符串不是解决方案,因为我需要最小的开销和轻松访问单个字符。)

4

4 回答 4

25

您可以strdup()用来返回 C 字符串的副本,如下所示:

#include <string.h>

const char *stringA = "foo";
char *stringB = NULL;

stringB = strdup(stringA);
/* ... */
free(stringB);    

您也可以使用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);

如果您不能使用strdup(),我建议使用 ofstrncpy()而不是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);

我自己认为strdup()更干净,所以我尝试在专门处理字符串的情况下使用它。我不知道 POSIX/非 POSIX 方法在性能方面是否有严重的缺点,但我不是 C 或 C++ 专家。

请注意,我将结果转换为malloc()to char *。这是因为您的问题被标记为c++问题。在 C++ 中,需要将结果从malloc(). 但是,在 C 中,您不会强制转换它。

编辑

你去吧,有一个复杂性:strdup()不在 C 或 C++ 中。因此,使用strcpy()orstrncp()与预先确定大小的数组或malloc-ed 指针一起使用。在您可能使用该功能的任何地方,使用strncp()代替 是一个好习惯。strcpy()这将有助于减少出错的可能性。

于 2012-03-07T00:01:18.060 回答
4

如果我只是将 stringB 初始化为 char *stringB[23],因为我知道我永远不会有超过 22 个字符的字符串(并允许空终止符),这是正确的方法吗?

几乎。在 C 中,如果您确定字符串永远不会太长:

char stringB[MAX+1];
assert(strlen(stringA) <= MAX));
strcpy(stringB, stringA);

或者,如果字符串可能太长:

char stringB[MAX+1];
strncpy(stringB, stringA, MAX+1);
if (stringB[MAX] != '\0') {
    // ERROR: stringA was too long.
    stringB[MAX] = '\0'; // 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>:包含固定大小数组的可复制类。

如果检查 stringB 是否与其他 C 字符串相等,额外的空间会影响什么吗?

如果使用strcmp,那么它将停在最短字符串的末尾,并且不会受到额外空格的影响。

于 2012-03-07T00:24:39.747 回答
3

如果你想用纯 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;
于 2012-03-07T00:01:40.440 回答
1

您可能正在寻找strncpy,它允许您从字符串中复制第n一个字符。只需确保在复制到字符串的位置 n 添加空终止符。

于 2012-03-07T00:01:41.413 回答