2009-08-17 54 views
90

Conozco un poco de C y ahora estoy mirando C++. Estoy acostumbrado a char matrices para hacer frente a cadenas de C, pero mientras miro el código C++ veo que hay ejemplos que usan tanto el tipo y la carbonilla cadena matrices:Diferencia entre los tipos de cadena y char [] en C++

#include <iostream> 
#include <string> 
using namespace std; 

int main() { 
    string mystr; 
    cout << "What's your name? "; 
    getline (cin, mystr); 
    cout << "Hello " << mystr << ".\n"; 
    cout << "What is your favorite team? "; 
    getline (cin, mystr); 
    cout << "I like " << mystr << " too!\n"; 
    return 0; 
} 

y

#include <iostream> 
using namespace std; 

int main() { 
    char name[256], title[256]; 

    cout << "Enter your name: "; 
    cin.getline (name,256); 

    cout << "Enter your favourite movie: "; 
    cin.getline (title,256); 

    cout << name << "'s favourite movie is " << title; 

    return 0; 
} 

(ambos ejemplos de http://www.cplusplus.com)

Supongo que esta es una pregunta ampliamente formulada y respondida (¿obvio?), pero sería bueno si alguien pudiera decirme cuál es exactamente la diferencia entre esas dos formas de trabajar con cadenas en C++ (rendimiento , API i integración, la forma en que cada uno es mejor, ...).

Gracias.

+0

Esto puede ayudar: [C++ char * vs std :: string] (http://stackoverflow.com/questions/801209/c-char-vs-stdstring) –

Respuesta

140

Una matriz de caracteres es sólo eso - una serie de caracteres:

  • Si asigna en la pila (como en el ejemplo), siempre va a ocupar por ejemplo. 256 bytes sin importar cuánto tiempo el texto que contiene es
  • Si está asignado en el montón (usando malloc() o nuevo char []) usted es responsable de liberar la memoria después y siempre tendrá la sobrecarga de una asignación de pila .
  • Si copia un texto de más de 256 caracteres en la matriz, podría colapsar, producir mensajes de afirmación desagradables o provocar un comportamiento (inexistente) inexplicable en otro lugar de su programa.
  • Para determinar la longitud del texto, la matriz debe escanearse, carácter por carácter, para un carácter \ 0.

Una cadena es una clase que contiene una matriz de caracteres, pero la administra automáticamente. La mayoría de las implementaciones de cadenas tienen una matriz integrada de 16 caracteres (por lo que las cadenas cortas no fragmentan el montón) y usan el montón para cadenas más largas.

Puede acceder matriz de caracteres de una cadena como esta:

std::string myString = "Hello World"; 
const char *myStringChars = myString.c_str(); 

C cadenas ++ pueden contener incrustado \ 0 caracteres, sabe de su longitud sin contar, son más rápidos que los arrays de char-heap asignado para textos cortos y se protege de los desbordamientos del búfer. Además, son más legibles y fáciles de usar.

-

Sin embargo, C++ cadenas no son (muy) adecuado para el uso a través de fronteras DLL, porque esto requeriría cualquier usuario de tal función DLL para asegurarse de que está usando exactamente el mismo compilador y C aplicación en tiempo de ejecución ++, no sea que arriesgue que su clase de cuerdas se comporte de manera diferente.

Normalmente, una clase de cadena también liberaría su memoria de pila en el montón de llamadas, por lo que solo podrá liberar memoria de nuevo si está utilizando una versión compartida (.dll o .so) del tiempo de ejecución.

En resumen: use cadenas de C++ en todas sus funciones y métodos internos. Si alguna vez escribe un .dll o .so, use C strings en sus funciones públicas (dll/so-exposed).

+3

Además, las cadenas tienen un conjunto de funciones auxiliares que pueden ser realmente ordenadas. –

+1

No creo en el bit sobre los enlaces DLL. En circunstancias muy especiales, podría romperse ((una DLL está enlazada estáticamente con una versión diferente del tiempo de ejecución que la utilizada por otras DLL) y cosas peores probablemente ocurrirían primero en estas situaciones) pero en el caso general donde todo el mundo está usando la versión compartida del tiempo de ejecución estándar (por defecto) esto no sucederá. –

+1

Ejemplo: distribuye los binarios compilados de VC2008SP1 de una biblioteca pública llamada libfoo, que tiene una cadena estándar & en su API pública. Ahora alguien descarga su libfoo.dll y realiza una compilación de depuración. Su cadena std :: podría contener algunos campos de depuración adicionales, lo que hace que el desplazamiento del puntero para cadenas dinámicas se mueva. – Cygon

6

Bueno, el tipo de cadena es una clase completamente administrada para cadenas de caracteres, mientras que char [] sigue siendo lo que era en C, una matriz de bytes que representa una cadena de caracteres para usted.

En términos de API y biblioteca estándar, todo se implementa en términos de cadenas y no de caracteres [], pero todavía hay muchas funciones de la libc que reciben char [], por lo que puede necesitar utilizarlas para aquellas, aparte de de eso siempre usaría std :: string.

En términos de eficiencia, por supuesto, un buffer crudo de memoria no administrada casi siempre será más rápido para muchas cosas, pero tome en cuenta la comparación de cadenas, por ejemplo, std :: string siempre tiene el tamaño para verificarlo primero, mientras que char [] necesitas comparar personaje por personaje.

6

Arkaitz tiene razón en que string es un tipo administrado. Lo que esto significa para usted es que nunca tiene que preocuparse por cuánto tiempo es la cadena, ni tiene que preocuparse por liberar o reasignar la memoria de la cadena.

Por otro lado, la notación char[] en el caso anterior ha restringido el búfer de caracteres a exactamente 256 caracteres. Si trataste de escribir más de 256 caracteres en ese búfer, en el mejor de los casos sobrescribirás otra memoria que tu programa "posee". En el peor de los casos, intentará sobrescribir la memoria que no posee, y su sistema operativo matará su programa en el acto.

¿Línea inferior? Las cadenas son mucho más amigables con los programadores, las [char] son ​​mucho más eficientes para la computadora.

+3

En el peor de los casos, otras personas sobrescribirán la memoria y ejecutarán códigos maliciosos en su computadora. Ver también [desbordamiento de búfer] (http://cwe.mitre.org/data/definitions/120.html). –

5

Personalmente, no veo ninguna razón por la que uno quiera usar char * o char [] excepto por compatibilidad con el código anterior. std :: string no es más lento que usar una cadena de caracteres, excepto que manejará la reasignación por usted. Puede establecer su tamaño cuando lo crea, y así evitar la reasignación si lo desea. Su operador de indexación ([]) proporciona acceso de tiempo constante (y en todo el sentido de la palabra es exactamente lo mismo que usar un indexador de cadena de caracteres). El uso del método at también te da seguridad en los límites comprobados, algo que no obtienes con c-strings, a menos que lo escribas. Su compilador optimizará con mayor frecuencia el uso del indexador en el modo de lanzamiento. Es fácil perder el tiempo con c-strings; cosas como eliminar frente a eliminar [], seguridad de excepción, incluso cómo reasignar una cadena de caracteres.

Y cuando tenga que tratar con conceptos avanzados como tener cadenas COW y no COW para MT, necesitará std :: string.

Si le preocupan las copias, siempre y cuando use referencias y referencias const siempre que sea posible, no tendrá ningún sobrecarga debido a las copias, y es lo mismo que haría con el c-string .

+0

+1 Aunque no tuvo en cuenta los problemas de implementación como la compatibilidad con DLL, obtuvo COW. –

+0

¿Qué tal si sé que mi matriz de caracteres en 12 bytes? Si instalo una cadena para eso, puede que no sea realmente eficiente, ¿verdad? –

+0

@David: si tiene un código extremadamente sensible a la perforación, entonces sí. Puede considerar la llamada de std :: string ctor como una sobrecarga además de la inicialización de los miembros de std :: string. Pero recuerde que la optimización prematura ha creado una gran cantidad de bases de código innecesariamente estilo C, así que tenga cuidado. – Abhay

0

Piensa en (char *) como string.begin(). La diferencia esencial es que (char *) es un iterador y std :: string es un contenedor. Si te apegas a las cadenas básicas a (char *) te dará lo que std :: string :: iterator hace. Puede usar (char *) cuando desee el beneficio de un iterador y también la compatibilidad con C, pero esa es la excepción y no la regla. Como siempre, tenga cuidado con la invalidación del iterador. Cuando la gente dice (char *) que no es seguro, esto es lo que quieren decir. Es tan seguro como cualquier otro iterador de C++.

1

Las cadenas tienen funciones de ayuda y administran las matrices de caracteres automáticamente. Puede concatenar cadenas, para una matriz de caracteres que necesitaría copiar a una nueva matriz, las cadenas pueden cambiar su longitud en tiempo de ejecución. Una matriz char es más difícil de administrar que una cadena y ciertas funciones solo pueden aceptar una cadena como entrada, lo que requiere que convierta la matriz en una cadena. Es mejor usar cadenas, fueron hechas para que no tengas que usar matrices. Si las matrices fueran objetivamente mejores, no tendríamos cadenas.

0

Una de las diferencias es la terminación nula (\ 0).

En C y C++, char * o char [] tomará un puntero a un carácter único como parámetro y hará un seguimiento a lo largo de la memoria hasta alcanzar un valor de memoria 0 (a menudo llamado el terminador nulo).

Las cadenas de C++ pueden contener caracteres \ 0 incrustados, conocer su longitud sin contar.

#include<stdio.h> 
#include<string.h> 
#include<iostream> 

using namespace std; 

void NullTerminatedString(string str){ 
    int NUll_term = 3; 
    str[NUll_term] = '\0';  // specific character is kept as NULL in string 
    cout << str << endl <<endl <<endl; 
} 

void NullTerminatedChar(char *str){ 
    int NUll_term = 3; 
    str[NUll_term] = 0;  // from specific, all the character are removed 
    cout << str << endl; 
} 

int main(){ 
    string str = "Feels Happy"; 
    printf("string = %s\n", str.c_str()); 
    printf("strlen = %d\n", strlen(str.c_str())); 
    printf("size = %d\n", str.size()); 
    printf("sizeof = %d\n", sizeof(str)); // sizeof std::string class and compiler dependent 
    NullTerminatedString(str); 


    char str1[12] = "Feels Happy"; 
    printf("char[] = %s\n", str1); 
    printf("strlen = %d\n", strlen(str1)); 
    printf("sizeof = %d\n", sizeof(str1)); // sizeof char array 
    NullTerminatedChar(str1); 
    return 0; 
} 

Salida:

strlen = 11 
size = 11 
sizeof = 32 
Fee s Happy 


strlen = 11 
sizeof = 12 
Fee 
+0

Tenga en cuenta que está respondiendo a una pregunta hecha hace 8 años. –

+0

@ n.m: sí, lo sé. cuando estoy pasando, la mayoría de los puntos están cubiertos en esto y he agregado un punto más que ayudará a obtener todas las respuestas (al máximo) en un solo lugar. –

Cuestiones relacionadas