Forma adequada de copiar os textos em C

Há uma maneira fácil de copiar as cordas C?

tenho const char *stringA, e quero char *stringB tomar o valor (note que stringB não é const). Eu tentei stringB=(char*) stringA, mas isso faz stringB ainda apontar para o mesmo local de memória, então quando stringA mais tarde muda, stringB também muda.

Eu também tentei strcpy(stringB,stringA), mas parece que se stringB não foi inicializado para uma grande variedade o suficiente, há uma segfault. Não tenho muita experiência com C-strings, estou a perder algo óbvio? Se eu ... inicializar {[[2]} como char *stringB[23], Porque eu sei que nunca terei um texto maior que 22 caracteres (e permitindo o terminador nulo), é esse o caminho certo? Se stringB for verificado a igualdade com outras cadeias de caracteres C, o espaço extra irá afectar alguma coisa?

(e só usar strings não é uma solução aqui, pois eu preciso de sobrecarga mínima e acesso fácil a caracteres individuais) {[[16]}

Author: Evan Teran, 2012-03-07

4 answers

Podias usar strdup() para devolver uma cópia de uma cadeia C, como em:

#include <string.h>

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

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

Você também pode usar strcpy(), mas você precisa alocar espaço primeiro, o que não é difícil de fazer, mas pode levar a um erro de excesso, se não for feito corretamente:

#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);

Se não puder utilizar strdup(), recomendaria a utilização de strncpy() em vez de strcpy(). A função strncpy() copia até - e apenas até - n bytes, o que ajuda a evitar erros de excesso de fluxo. No entanto, se strlen(stringA) + 1 > n teria de acabar contigo. Mas, geralmente, você saberá que Tamanhos você precisa para as coisas:

#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);
Eu próprio acho que strdup() é mais limpo, por isso tento usá-lo onde se trabalha exclusivamente com cordas. Não sei se há desvantagens graves na abordagem POSIX/não-POSIX, em termos de desempenho, mas não sou um especialista em C ou C++.

Note que eu lancei o resultado de malloc() para char *. Isto é porque a sua pergunta está marcada como uma pergunta c++. Em C++, é necessário lançar o resultado de malloc(). No entanto, em C, não lançarias isto.

EDITAR

Aqui está, há uma complicação: strdup() não está em C ou C++. Então use strcpy() ou strncp() com uma matriz pré-dimensionada ou um ponteiro malloc-ed. É um bom hábito usar strncp() em vez de strcpy(), onde quer que você possa usar essa função. Ajudará a reduzir o potencial de erros.

 12
Author: Alex Reynolds, 2012-03-07 07:47:02

Se Eu apenas inicializar stringB como char * stringB [23], Porque eu sei que nunca vou ter uma string mais de 22 caracteres (e permitindo o terminador nulo), é esse o caminho certo?

Quase. Em C, se tiver a certeza de que o texto nunca será muito longo:
char stringB[MAX+1];
assert(strlen(stringA) <= MAX));
strcpy(stringB, stringA);

Ou, se houver uma possibilidade de que a corda possa ser demasiado longa:

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
}

Em C++, deve usar std::string, a menos que tenha provado que a sobrecarga é proibitiva. Muito implementações têm uma "otimização de cadeia curta", que evitará alocação dinâmica para cadeias curtas; nesse caso, haverá pouca ou nenhuma sobrecarga sobre o uso de um array de estilo C. O acesso a caracteres individuais é tão conveniente como com uma matriz de estilo C; em ambos os casos, s[i] dá o carácter na posição i como um value. A cópia torna-se stringB = stringA; sem perigo de comportamento indefinido.

Se realmente achar que std::string está inutilizável, considere std::array<char,MAX+1>: um copiável classe que contém uma matriz de tamanho fixo.

Se o stringB for verificado pela igualdade com outras cadeias de C, o espaço extra irá afectar alguma coisa?

Se você usar strcmp, então ele vai parar no final do texto mais curto, e não será afetado pelo espaço extra.

 3
Author: Mike Seymour, 2012-03-07 00:45:42

Se o quiseres fazer em puro estilo C que:

char* new_string = strdup(old_string);
free(new_string);

Se o quiser fazer em (Tipo de) estilo C++:

char* new_string = new char[strlen(old_string) + 1];
strcpy(new_string,old_string);
delete[] new_string;
 2
Author: sirgeorge, 2012-03-07 00:01:40
Provavelmente estás à procura de ... strncpy, o que lhe permite copiar os primeiros caracteres n de um texto. Certifique-se apenas de adicionar o terminador nulo na posição n do texto copiado para.
 0
Author: Ken Wayne VanderLinde, 2012-03-07 00:01:41