retornar retorna punteros puntero matrices lenguaje como aritmetica c static

retorna - punteros y matrices en c



¿Es seguro devolver un puntero a una variable local estática? (7)

Depende de lo que quieras decir con seguridad. Hay un par de problemas que puedo ver de inmediato:

  1. Has devuelto un char * const , que permitirá a los llamantes cambiar la cadena en esta ubicación. Desbordamiento del búfer potencial. ¿O te refieres a un const char * ?
  2. Es posible que tenga un problema con la reentrada o con la concurrencia.

Para explicar el segundo, considere esto:

const char * const format_error_message(int err) { static char error_message[MAXLEN_ERROR_MESSAGE]; sprintf(error_message, "Error %#x occurred", err); return error_message; }

Si lo llamas así:

int a = do_something(); int b = do_something_else(); if (a != 0 && b != 0) { fprintf(stderr, "do_something failed (%s) AND do_something_else failed (%s)/n", format_error_message(a), format_error_message(b)); }

... ¿Qué se va a imprimir?

Lo mismo para enhebrar

Estoy trabajando con un código que usa ampliamente el modismo de devolver un puntero a una variable local estática. p.ej:

char* const GetString() { static char sTest[5]; strcpy(sTest, "Test"); return sTest; }

¿Estoy en lo cierto al pensar que esto es seguro?

PD, sé que esta sería una mejor manera de hacer lo mismo:

char* const GetString() { return "Test"; }

Edición: disculpas, la firma de la función debería ser, por supuesto:

const char* GetString();


Es muy útil, ya que puede usar la función directamente como parámetro printf. Pero, como se mencionó, múltiples llamadas a la función dentro de una sola llamada causarán un problema, porque la función usa el mismo almacenamiento y al llamarlo dos veces sobrescribirá la cadena devuelta. Pero probé esta pieza de código y parece funcionar: se puede llamar de forma segura a una función, donde givemestring se usa a lo sumo MAX_CALLS veces y se comportará correctamente.

#define MAX_CALLS 3 #define MAX_LEN 30 char *givemestring(int num) { static char buf[MAX_CALLS][MAX_LEN]; static int rotate=0; rotate++; rotate%=sizeof(buf)/sizeof(buf[0]); sprintf(buf[rotate],"%d",num); return buf[rotate]; }

El único problema es la seguridad de la hebra, pero esto se puede resolver con variables locales de hebra (gcc''s __thread keyword)


Fundamentalmente, sí, es seguro en el sentido de que el valor durará indefinidamente porque es estático.

No es seguro en el sentido de que ha devuelto un puntero constante a datos variables, en lugar de un puntero variable a datos constantes. Es mejor si las funciones de llamada no pueden modificar los datos:

const char *GetString(void) { static char sTest[5]; strncpy(sTest, "Test", sizeof(sTest)-1); sTest[sizeof(sTest)-1] = ''/0''; return sTest; }

En el caso simple que se muestra, apenas es necesario preocuparse por los desbordamientos del búfer, aunque mi versión del código sí se preocupa y garantiza la terminación nula. Una alternativa sería usar la función strcpy_s en strcpy_s lugar:

const char *GetString(void) { static char sTest[5]; strcpy_s(sTest, sizeof(sTest), "Test"); return sTest; }

Más importante aún, ambas variantes devuelven un puntero (variable) a datos constantes, por lo que el usuario no debe ir modificando la cadena y (probablemente) pisoteando fuera del rango de la matriz. (Como señala @strager en los comentarios, devolver un const char * no es una garantía de que el usuario no intentará modificar los datos devueltos. Sin embargo, tienen que convertir el puntero devuelto para que no sea const y luego modificar los datos, esto invoca un comportamiento indefinido y todo es posible en ese punto).

Una ventaja del retorno literal es que la promesa de no escritura por lo general puede ser aplicada por el compilador y el sistema operativo. La cadena se colocará en el segmento de texto (código) del programa, y ​​el sistema operativo generará un error (violación de la segmentación en Unix) si el usuario intenta modificar los datos apuntados por el valor de retorno.

[Al menos una de las otras respuestas indica que el código no es reentrante; eso es correcto. La versión que devuelve el literal es reingresante. Si la reentrada es importante, la interfaz debe ser reparada para que la persona que llama proporcione el espacio donde se almacenan los datos.]


Sí, es perfectamente seguro. La vida útil de las estáticas locales es la de la ejecución completa del programa en C. Así que puede devolver un puntero, ya que la matriz estará activa incluso después de que la función retorna, y el puntero devuelto puede ser desreferenciado válidamente.


Sí, esto se usa con frecuencia para devolver la parte de texto de alguna búsqueda, es decir, para traducir un número de error en una cadena que sea amigable para los seres humanos.

Es aconsejable hacer esto en los casos en que:

fprintf(stderr, "Error was %s/n", my_string_to_error(error_code));

Si my_string_to_error() devolvió una cadena asignada, su programa se filtraría dado el uso (muy) anterior de dicha función.

char const *foo_error(...) { return "Mary Poppins"; }

... también está bien, algunos compiladores con muerte cerebral pueden querer que lo lances.

Solo mire cadenas de esta manera, no devuelva un libro :)


static variables static (en una función) son como variables globales con ámbito. En general, deben evitarse (al igual que las variables globales, causan problemas de reentrada), pero a veces son útiles (algunas funciones de la biblioteca estándar los usan). Puede devolver punteros a variables globales, por lo que puede devolver punteros a variables static también.


Primer ejemplo: algo seguro

char* const GetString() { static char sTest[5]; strcpy(sTest, "Test"); return sTest; }

Aunque no se recomienda, esto es seguro, el alcance de una variable estática permanece activa incluso cuando el alcance de la función finaliza. Esta función no es muy segura para subprocesos. Una función mejor le permitiría pasar un char* buffer y un maxsize para que se llene la función GetString() .

En particular, esta función no se considera una función de reentrada porque las funciones de reentrada no deben, entre otras cosas, devolver la dirección a datos no constantes (globales) estáticos . Ver funciones de reentrada .

Segundo ejemplo: completamente inseguro

char* const GetString() { return "Test"; }

Esto sería seguro si const char * un const char * . Lo que diste no es seguro. La razón es porque los literales de cadena se pueden almacenar en un segmento de memoria de solo lectura y permitir que se modifiquen generará resultados indefinidos.

char* const (const pointer) significa que no puede cambiar la dirección a la que apunta el puntero. const char * (puntero a const) significa que no puede cambiar los elementos a los que apunta este puntero.

Conclusión:

Debes considerar cualquiera:

1) Si tiene acceso al código, modifique GetString para tomar un parámetro de un char* buffer para rellenar y un maxsize para usar.

2) Si no tiene acceso al código, pero debe llamarlo, ajuste este método en otra función que esté protegida por un mutex. El nuevo método es como se describe en 1.