¿Cómo se asignan las cadenas C en memoria?

Digamos que tengo una función simple que devuelve una cadena en C de esta manera:

const char * getString() { const char * ptr = "blah blah"; return ptr; } 

y llamo a getString () desde main () de esta manera:

  const char * s = getString(); 

1) De acuerdo con gdb, la variable ptr se almacena en la stack, pero la cadena señalada por ptr no es:

 (gdb) p &ptr $1 = (const char **) 0x7fffffffe688 (gdb) p ptr $2 = 0x4009fc "blah blah" 

¿Significa esto que “blah blah” no es una variable local dentro de getString ()?

Supongo que si fuera una variable local, no podría pasarla a mi función principal () … Pero si no lo es, ¿dónde está almacenada? ¿En el montón? ¿Es esa una “clase de” asignación de memoria dinámica implementada por el sistema operativo cada vez que toca una cadena, o qué?

2) Si uso una matriz en lugar de un puntero, de esta manera:

 const char *getString2() { const char a[] = "blah blah blah"; return a; } 

El comstackdor me advierte que:

warning: address of local variable 'a' returned

(y por supuesto el progtwig comstack, pero no funciona).

En realidad, si pido gdb, me sale

 (gdb) p &a $2 = (const char (*)[15]) 0x7fffffffe690 

Pero pensé que const char * ptr y const char a [] eran básicamente lo mismo. Parece que no lo son.

¿Me equivoco? ¿Cuál es exactamente la diferencia entre las dos versiones?

¡Gracias!

Cuando escribes

 const char *ptr = "blah blah"; 

luego sucede lo siguiente: el comstackdor genera una cadena constante (de tipo char [] ) con el contenido "blah blah" y la almacena en algún lugar del segmento de datos del ejecutable (básicamente tiene una duración de almacenamiento similar a la de las variables declaradas usando la palabra clave static ).

Luego, la dirección de esta cadena, que es válida durante toda la vida útil del progtwig, se almacena en el puntero ptr , que luego se devuelve. Todo está bien.

¿Significa esto que "blah blah" no es una variable local dentro de getString ()?

Déjame responder con una frase rota en inglés: sí, no lo es.

Sin embargo, cuando declara una matriz, como en

 const char a[] = "blah blah"; 

entonces el comstackdor no genera una cadena estática. (De hecho, este es un caso un tanto especial al inicializar cadenas.) Luego genera un código que asignará una pieza de memoria de stack suficientemente grande para a matriz (¡no es un puntero!) Y la llenará con los bytes de la cadena. Aquí a es en realidad una variable local y devolver sus direcciones da como resultado un comportamiento indefinido.

Asi que…

Pero pensé que const char *ptr y const char a[] eran básicamente lo mismo.

No, en absoluto, porque las matrices no son punteros .

Supongo que si fuera una variable local, no podría pasarla a mi función principal () … Pero si no lo es, ¿dónde está almacenada?

Los literales de cadena generalmente se almacenan en una sección de datos de solo lectura ( .rodata ). C estándar solo dice que tienen duración de almacenamiento estático. Por lo tanto, puede devolver un puntero a dicho literal, pero no es el caso de las matrices.

En el siguiente ejemplo, el objeto apuntado por p1 tiene una duración de almacenamiento estática, mientras que la matriz p2 tiene una duración de almacenamiento automática.

 char *f(void) { const char *p1 = "hello, world"; char p2[] = "hello, world"; return p1; /* allowed */ return p2, /* forbidden */ } 

Tienes razón en que no son lo mismo. char a [] es una matriz formada en la stack, y luego rellena con “blah ..” – dentro de la función, tienes esencialmente `const char a [15]; strcpy (a, “bla bla bla”);

The const char *ptr = "blah blah blah"; por otro lado, es simplemente un puntero (el puntero en sí está en la stack), y el puntero apunta a la cadena “blah blah blah”, que se almacena en otra parte [en “datos de solo lectura” muy probablemente].

Notará una gran diferencia si intenta alterar algo, por ejemplo: a[2] = 'e'; vs ptr[2] = 'e'; – el primero tendrá éxito, porque está modificando un valor de stack, donde el segundo (probablemente) fallará, porque está modificando un fragmento de memoria de solo lectura, que por supuesto no debería funcionar.

En su función, el scope de a[] matriz a[] está dentro de la función getString2() . su variable matriz local .

 const char *getString2() { const char a[] = "blah blah blah"; return a; } 

En el caso anterior, la cadena "blah blah blah" copia el fist en a[] y está intentando devolver esa matriz con return a statement de return a , pero no una cadena constante.

Donde como en el primer código getString() : ptr = "blah blah"; Punto de ptr a memoria que tiene scope global.

 const char * getString() { const char * ptr = "blah blah"; return ptr; } 

En este caso, devuelve la dirección de la cadena constante "blah blah" que es legal hacer.

Así que en realidad es su problema de scope.

es útil aprender sobre el diseño de memoria de los progtwigs en C y el scope variable en C

Ellos no son los mismos.

El primero es un puntero a una cadena literal. El puntero en sí está en el almacenamiento automático. La cadena está en memoria estática, de sólo lectura. Es inmutable.

El segundo es una matriz de caracteres automática (de stack) (y ese retorno es, como dice la advertencia, no es legal).