texto - ¿Cuál es la diferencia entre devolver un char*y un char
obtener el primer caracter de una cadena c++ (6)
Pensé que el valor de retorno de ambas funciones no estaría definido ya que están devolviendo datos que están fuera del alcance.
Ambas funciones devuelven un puntero. Lo que importa es el alcance del referente .
En
function1
, el referente es el literal de cadena
"Hello, World!"
, que tiene una duración de almacenamiento estático.
string
es una variable local que apunta a esa cadena y, conceptualmente, se devuelve una copia de ese puntero (en la práctica, el compilador evitará copiar innecesariamente el valor).
En la
function2
, conceptualmente, el referente es la
string
matriz local, que se ha dimensionado automáticamente (en tiempo de compilación) para ser lo suficientemente grande como para contener el literal de cadena (incluido un terminador nulo, por supuesto), y se ha inicializado con una copia de la cadena .
La función devolvería un puntero a esa matriz, excepto que la matriz tiene una duración de almacenamiento automática y, por lo tanto, ya no existe después de salir de la función (de hecho, está "fuera de alcance", en una terminología más familiar).
Dado que este es un comportamiento indefinido, el compilador
en la práctica puede hacer todo tipo de cosas
.
¿Eso significa que todos los
char*
son estáticos?
Nuevamente, necesita distinguir entre el puntero y el referente. Los punteros apuntan a los datos; ellos mismos no "contienen" los datos.
Has llegado a un punto en el que debes estudiar adecuadamente qué matrices y punteros están realmente en C; desafortunadamente, es un poco complicado. La mejor referencia que puedo ofrecer es this , en formato de preguntas y respuestas.
Esta pregunta ya tiene una respuesta aquí:
- ¿Cómo acceder a una variable local desde una función diferente usando punteros? 9 respuestas
- Literales de cadena: ¿A dónde van? 8 respuestas
- ¿Cuál es la diferencia entre char s [] y char * s? 13 respuestas
¿Por qué la primera función devuelve la cadena "Hola, Mundo" pero la segunda función no devuelve nada? Pensé que el valor de retorno de ambas funciones no estaría definido ya que están devolviendo datos que están fuera del alcance.
#include <stdio.h>
// This successfully returns "Hello, World"
char* function1()
{
char* string = "Hello, World!";
return string;
}
// This returns nothing
char* function2()
{
char string[] = "Hello, World!";
return string;
}
int main()
{
char* foo1 = function1();
printf("%s/n", foo1); // Prints "Hello, World"
printf("------------/n");
char* foo2 = function2(); // Prints nothing
printf("%s/n", foo2);
return 0;
}
Pensé que el valor de retorno de ambas funciones no estaría definido ya que están devolviendo datos que están fuera del alcance.
No. Ese no es el caso.
En la función
function1
está devolviendo el puntero a un literal de cadena.
Devolver el puntero a un literal de cadena está bien porque los literales de cadena tienen
una duración de almacenamiento estático
.
Pero eso no es cierto con
la variable local automática
.
En la función
function2
la
string
matriz es una variable local automática y la instrucción
return string;
devuelve un puntero a una variable local automática.
Una vez que la función regrese, la
string
variable ya no existirá.
Desreferenciar el puntero devuelto causará un comportamiento indefinido.
la segunda función no devuelve nada
El conjunto de
string
en la segunda función:
char string[] = "Hello, World!";
Tiene duración de almacenamiento automático . No existe después de que el flujo de control ha regresado de la función.
Mientras que la
string
en la primera función:
char* string = "Hello, World!";
apunta a una cadena literal, que tiene una duración de almacenamiento estático . Eso implica que, la cadena todavía existe después de regresar de la función. Lo que está devolviendo de la función es un puntero a esta cadena literal.
Lo primero que debe aprender sobre las cadenas es que un literal de cadena es realmente una matriz de caracteres de solo lectura con una vida útil del programa completo. Eso significa que nunca saldrán del alcance, siempre existirán durante la ejecución del programa.
Lo que hace la primera función (
function1
) es devolver un puntero al primer elemento de dicha matriz.
Con la segunda función (
function2
) las cosas son un poco diferentes.
Aquí la
string
variable es una
variable local
dentro de la función.
Como tal, quedará fuera de alcance y dejará de existir una vez que la función regrese.
Con esta función, devuelve un puntero al primer elemento de esa matriz, pero ese puntero se volverá inmediatamente inválido ya que apuntará a algo que ya no existe.
Desreferenciarlo (lo que sucede cuando lo pasa a
printf
) conducirá a
un comportamiento indefinido
.
Una cosa muy importante para recordar al codificar en C u otros lenguajes basados en pila es que cuando una función regresa, esta (y todo su almacenamiento local) desaparece. Esto significa que si desea que otra persona pueda ver los resultados del trabajo arduo de sus métodos, debe colocarlo en algún lugar que aún exista después de que su método haya dejado de hacerlo, y para hacerlo significa que necesita comprender donde C almacena cosas y cómo.
Probablemente ya sepa cómo funciona una matriz en C. Es solo una dirección de memoria que se incrementa por el tamaño del objeto y probablemente también sepa que C no verifica los límites, por lo que si desea acceder al undécimo elemento de un diez matriz de elementos, nadie lo detendrá, y mientras no intente escribir nada, no se hará daño. Lo que quizás no sepa es que C extiende esta idea a la forma en que usa funciones y variables. Una función es solo un área de memoria en una pila que se carga bajo demanda y el almacenamiento de sus variables son solo desplazamientos de esa ubicación. Su función devolvió un puntero a una variable local, específicamente, la dirección de una ubicación en la pila que contiene la ''H'' de ''Hello World / n / 0'', pero cuando llamó a otra función (el método de impresión) esa memoria era reutilizado por el método de impresión para hacer lo que necesitaba. Puede ver esto con bastante facilidad (¡NO HAGA ESTO EN EL CÓDIGO DE PRODUCCIÓN!)
char* foo2 = function2(); // Prints nothing
ch = foo2[0]; // Do not do this in live code!
printf("%s/n", foo2); // stack used by foo2 now used by print()
printf("ch is %c/n", ch); // will have the value ''H''!
"Hello, World!"
es un literal de cadena, que tiene una duración de almacenamiento estático, por lo que el problema está en otra parte.
Su primera función devuelve el
valor
de
string
, que está bien.
Sin embargo, la segunda función devuelve la
dirección
de una variable local (
string
es la misma que
&string[0]
), lo que resulta en un comportamiento indefinido.
Su segunda declaración
printf
podría no imprimir nada, o "¡Hola, mundo!", O algo completamente diferente.
En mi máquina, el programa solo tiene una falla de segmentación.
Siempre eche un vistazo a los mensajes que genera su compilador.
Para su ejemplo,
gcc
da:
file.c:12:12: warning: function returns address of local variable [-Wreturn-local-addr]
return string;
^
lo cual se explica por sí solo.