¿Cuál es la diferencia entre char s[] y char*s?

8 minutos de lectura

En C, uno puede usar un literal de cadena en una declaración como esta:

char s[] = "hello";

o así:

char *s = "hello";

Entonces cuál es la diferencia? Quiero saber qué sucede realmente en términos de duración del almacenamiento, tanto en tiempo de compilación como de ejecución.

  • c-faq.com/aryptr/index.html c-faq.com/charstring/index.html

    – Sinan Ünür

    9 de noviembre de 2009 a las 23:22

  • char *s=”hola”, aquí s puede apuntar cualquier otra cadena en tiempo de ejecución, quiero decir que no es un puntero constante, puede asignar otro valor en tiempo de ejecución p = “Nishant”, mientras que s[] aquí s es un puntero constante…. no se puede reasignar otra cadena pero podemos asignar otro valor de carácter en s[index].

    –Nishant Kumar

    16 mayo 2012 a las 14:49

  • @NishantQuerías decir … puedes asignar otro valor en tiempo de ejecución s = “Nishant”, mientras que s[] … ¿Tuviste? De lo contrario, es un poco confuso en el contexto.

    – Yifangt

    4 de marzo a las 4:26


avatar de usuario
bdonlan

En primer lugar, en los argumentos de función, son exactamente equivalentes:

void foo(char *x);
void foo(char x[]); // exactly the same in all respects

En otros contextos, char * asigna un puntero, mientras que char [] asigna una matriz. ¿Adónde va la cuerda en el primer caso, te preguntarás? El compilador asigna en secreto una matriz anónima estática para contener el literal de cadena. Asi que:

char *x = "Foo";
// is approximately equivalent to:
static const char __secret_anonymous_array[] = "Foo";
char *x = (char *) __secret_anonymous_array;

Tenga en cuenta que nunca debe intentar modificar el contenido de esta matriz anónima a través de este puntero; los efectos no están definidos (a menudo significan un bloqueo):

x[1] = 'O'; // BAD. DON'T DO THIS.

El uso de la sintaxis de matriz lo asigna directamente a la nueva memoria. Por lo tanto, la modificación es segura:

char x[] = "Foo";
x[1] = 'O'; // No problem.

Sin embargo, la matriz solo vive mientras su alcance contiene, por lo que si hace esto en una función, no devuelva ni filtre un puntero a esta matriz; haga una copia en su lugar con strdup() o similar. Si la matriz se asigna en el ámbito global, por supuesto, no hay problema.

avatar de usuario
cristo

Un ejemplo de la diferencia:

printf("hello" + 2); //llo
char a[] = "hello" + 2; //error

En el primer caso, la aritmética de punteros está funcionando (las matrices pasadas a una función se descomponen en punteros).

  • Si bien este código puede responder a la pregunta, proporcionar un contexto adicional sobre por qué y/o cómo este código responde a la pregunta mejora su valor a largo plazo.

    – Pato Donald

    19 de noviembre de 2020 a las 11:47

avatar de usuario
ilkkachu

Dadas las declaraciones

char *s0 = "hello world";
char s1[] = "hello world";

asuma el siguiente mapa de memoria hipotético (las columnas representan caracteres en desplazamientos de 0 a 3 de la dirección de fila dada, por ejemplo, el 0x00 en la esquina inferior derecha está en la dirección 0x0001000C + 3 = 0x0001000F):

                     +0    +1    +2    +3
        0x00008000: 'h'   'e'   'l'   'l'
        0x00008004: 'o'   ' '   'w'   'o'
        0x00008008: 'r'   'l'   'd'   0x00
        ...
s0:     0x00010000: 0x00  0x00  0x80  0x00
s1:     0x00010004: 'h'   'e'   'l'   'l'
        0x00010008: 'o'   ' '   'w'   'o'
        0x0001000C: 'r'   'l'   'd'   0x00

El literal de cadena "hello world" es una matriz de 12 elementos de char (const char en C++) con duración de almacenamiento estática, lo que significa que la memoria se asigna cuando se inicia el programa y permanece asignada hasta que finaliza el programa. Intentar modificar el contenido de un literal de cadena invoca un comportamiento indefinido.

La línea

char *s0 = "hello world";

define s0 como un puntero a char con duración de almacenamiento automático (es decir, la variable s0 sólo existe para el ámbito en el que se declara) y copia el dirección del literal de cadena (0x00008000 en este ejemplo) a ella. Tenga en cuenta que desde s0 apunta a un literal de cadena, no debe usarse como argumento para ninguna función que intente modificarlo (por ejemplo, strtok(), strcat(), strcpy()etc.).

La línea

char s1[] = "hello world";

define s1 como una matriz de 12 elementos de char (la longitud se toma del literal de cadena) con duración de almacenamiento automático y copia el contenido del literal a la matriz. Como puede ver en el mapa de memoria, tenemos dos copias de la cadena "hello world"; la diferencia es que puede modificar la cadena contenida en s1.

s0 y s1 son intercambiables en la mayoría de los contextos; Aquí están las excepciones:

sizeof s0 == sizeof (char*)
sizeof s1 == 12

type of &s0 == char **
type of &s1 == char (*)[12] // pointer to a 12-element array of char

Puede reasignar la variable s0 para apuntar a un literal de cadena diferente o a otra variable. No puede reasignar la variable s1 para apuntar a una matriz diferente.

  • Si bien este código puede responder a la pregunta, proporcionar un contexto adicional sobre por qué y/o cómo este código responde a la pregunta mejora su valor a largo plazo.

    – Pato Donald

    19 de noviembre de 2020 a las 11:47

Esta declaración:

char s[] = "hello";

crea uno objeto – un char arreglo de tamaño 6, llamado sinicializado con los valores 'h', 'e', 'l', 'l', 'o', '\0'. La ubicación de esta matriz en la memoria y el tiempo de vida depende de dónde aparezca la declaración. Si la declaración está dentro de una función, vivirá hasta el final del bloque en el que se declara, y casi con certeza se ubicará en la pila; si está fuera de una función, lo hará probablemente almacenarse dentro de un “segmento de datos inicializados” que se carga desde el archivo ejecutable en la memoria grabable cuando se ejecuta el programa.

Por otro lado, esta declaración:

char *s ="hello";

crea dos objetos:

  • un solo lectura matriz de 6 chars que contiene los valores 'h', 'e', 'l', 'l', 'o', '\0'que no tiene nombre y tiene duración del almacenamiento estático (lo que significa que vive durante toda la vida del programa); y
  • una variable de tipo pointer-to-char, llamada sque se inicializa con la ubicación del primer carácter en esa matriz de solo lectura sin nombre.

La matriz de solo lectura sin nombre generalmente se encuentra en el segmento de “texto” del programa, lo que significa que se carga desde el disco a la memoria de solo lectura, junto con el código en sí. La ubicación de la s La variable de puntero en la memoria depende de dónde aparece la declaración (como en el primer ejemplo).

  • En ambas declaraciones para “hola”, la memoria se asigna en tiempo de compilación. Y otra cosa, char *p = “hola” aquí, “hola” se almacena en el segmento de texto como indicó en su respuesta … y ¿qué pasa con char s[] = “hola” también se almacenará primero en la parte del segmento de texto y durante el tiempo de ejecución se copiará en la pila como Rickard ha indicado en su respuesta. por favor aclarar este punto.

    –Nishant Kumar

    16 mayo 2012 a las 15:00

  • @Nishant: En el char s[] = "hello" caso, el "hello" es solo un inicializador que le dice al compilador cómo se debe inicializar la matriz. Puede o no dar como resultado una cadena correspondiente en el segmento de texto, por ejemplo, si s tiene una duración de almacenamiento estática, entonces es probable que la única instancia de "hello" estará en el segmento de datos inicializado – el objeto s sí mismo. Incluso si s tiene una duración de almacenamiento automático, se puede inicializar mediante una secuencia de almacenamientos literales en lugar de una copia (p. movl $1819043176, -6(%ebp); movw $111, -2(%ebp)).

    – café

    17 de mayo de 2012 a las 1:28

  • Más precisamente, GCC 4.8 lo pone en .rodataque la secuencia de comandos del enlazador vuelca en el mismo segmento que .text. Mira mi respuesta.

    – Ciro Santilli Путлер Капут 六四事

    5 de junio de 2015 a las 7:33


  • @caf En la primera respuesta de Rickard, está escrito que char s[] = "Hello world"; coloca la cadena literal en la memoria de solo lectura y copia la cadena en la memoria recién asignada en la pila. Pero, su respuesta solo habla sobre la cadena literal colocada en la memoria de solo lectura y omite la segunda parte de la oración que dice: copies the string to newly allocated memory on the stack. Entonces, ¿su respuesta está incompleta por no especificar la segunda parte?

    – ajaysinghnegi

    7 de enero de 2019 a las 10:11

  • @AjaySinghNegi: Como dije en otros comentarios (a esta respuesta y la respuesta de Rickard), la cadena en char s[] = "Hellow world"; es solo un inicializador y no se almacena necesariamente como una copia separada de solo lectura. Si s tiene una duración de almacenamiento estática, es probable que la única copia de la cadena esté en un segmento de lectura y escritura en la ubicación de s, e incluso si no, el compilador puede optar por inicializar la matriz con instrucciones de carga inmediata o similar en lugar de copiar desde una cadena de solo lectura. El punto es que, en este caso, la cadena inicializadora en sí misma no tiene presencia en el tiempo de ejecución.

    – café

    8 de enero de 2019 a las 9:39

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad