Estoy tratando de devolver una cadena C de una función, pero no funciona. Aquí está mi código.
char myFunction()
{
return "My String";
}
En main
lo llamo así:
int main()
{
printf("%s", myFunction());
}
También probé otras formas myFunction
, pero no funcionan. Por ejemplo:
char myFunction()
{
char array[] = "my string";
return array;
}
Nota: ¡No puedo usar punteros!
Poco antecedentes sobre este problema:
Hay una función que es averiguar qué mes es. Por ejemplo, si es 1, devuelve enero, etc.
Así que cuando se va a imprimir, lo está haciendo de esta manera: printf("Month: %s",calculateMonth(month));
. Ahora el problema es cómo devolver esa cadena de la calculateMonth
función.
return 0
está implícito de forma predeterminada solo en C99 (y C ++) pero no en C90.Respuestas:
La firma de su función debe ser:
Antecedentes:
Es tan fundamental para C & C ++, pero un poco más de discusión debería estar en orden.
En C (y C ++ para el caso), una cadena es solo una matriz de bytes terminados con un byte cero; de ahí que el término "cadena-cero" se use para representar este tipo particular de cadena. Hay otros tipos de cadenas, pero en C (& C ++), este sabor es inherentemente entendido por el lenguaje mismo. Otros lenguajes (Java, Pascal, etc.) utilizan diferentes metodologías para entender "mi cadena".
Si alguna vez usa la API de Windows (que está en C ++), verá parámetros de función con bastante regularidad como: "LPCSTR lpszName". La parte 'sz' representa esta noción de 'cadena-cero': una matriz de bytes con un terminador nulo (/ cero).
Aclaración:
Por el bien de esta 'introducción', utilizo la palabra 'bytes' y 'caracteres' indistintamente, porque es más fácil de aprender de esta manera. Tenga en cuenta que existen otros métodos (caracteres anchos y sistemas de caracteres multibyte ( mbcs )) que se utilizan para hacer frente a caracteres internacionales. UTF-8 es un ejemplo de mbcs. Por el bien de la introducción, silenciosamente 'salto' todo esto.
Memoria:
Esto significa que una cadena como "mi cadena" en realidad usa 9 + 1 (= 10!) Bytes. Es importante saber esto cuando finalmente pueda asignar cadenas de forma dinámica.
Entonces, sin este 'cero final', no tiene una cadena. Tiene una matriz de caracteres (también llamada búfer) en la memoria.
Longevidad de los datos:
El uso de la función de esta manera:
... generalmente lo llevará a fallas de segmento / excepciones no manejadas aleatorias y similares, especialmente 'en el camino'.
En resumen, aunque mi respuesta es correcta: 9 de cada 10 veces terminará con un programa que falla si lo usa de esa manera, especialmente si cree que es una 'buena práctica' hacerlo de esa manera. En resumen: generalmente no lo es.
Por ejemplo, imagine que en algún momento en el futuro, la cadena ahora debe manipularse de alguna manera. Generalmente, un codificador 'tomará el camino fácil' e (intentará) escribir código como este:
Es decir, su programa fallará porque el compilador (puede / puede que no) haya liberado la memoria utilizada
szBuffer
en el momentoprintf()
en quemain()
se invoca. (Su compilador también debería advertirle de estos problemas de antemano).Hay dos formas de devolver cadenas que no vomitarán tan fácilmente.
std::string
) para manejar la longevidad de los datos (lo que requiere cambiar el valor de retorno de la función), oTenga en cuenta que es imposible utilizar cadenas sin utilizar punteros en C. Como he mostrado, son sinónimos. Incluso en C ++ con clases de plantilla, siempre se utilizan búferes (es decir, punteros) en segundo plano.
Entonces, para responder mejor a la (pregunta ahora modificada). (Seguramente habrá una variedad de 'otras respuestas' que se pueden proporcionar).
Respuestas más seguras:
Ejemplo 1, usando cadenas asignadas estáticamente:
Lo que hace aquí lo 'estático' (a muchos programadores no les gusta este tipo de 'asignación') es que las cadenas se colocan en el segmento de datos del programa. Es decir, está asignado de forma permanente.
Si pasa a C ++, usará estrategias similares:
... pero probablemente sea más fácil usar clases auxiliares, por ejemplo
std::string
, si está escribiendo el código para su propio uso (y no como parte de una biblioteca para compartir con otros).Ejemplo 2, usando búferes definidos por el llamador:
Esta es la forma más 'infalible' de pasar cadenas. Los datos devueltos no están sujetos a manipulación por parte de la parte que llama. Es decir, una parte que llama puede abusar fácilmente del ejemplo 1 y exponerlo a fallas en la aplicación. De esta manera, es mucho más seguro (aunque usa más líneas de código):
Hay muchas razones por las que el segundo método es mejor, especialmente si está escribiendo una biblioteca para que la utilicen otros (no es necesario que se bloquee en un esquema de asignación / desasignación particular, los terceros no pueden descifrar su código, y no es necesario que se vincule a una biblioteca de administración de memoria específica), pero como todo código, usted decide lo que más le guste. Por esa razón, la mayoría de las personas optan por el ejemplo 1 hasta que se han quemado tantas veces que se niegan a escribirlo de esa manera;)
Descargo de responsabilidad:
Me jubilé hace varios años y mi C está un poco oxidada ahora. Este código de demostración debería compilarse correctamente con C (aunque está bien para cualquier compilador de C ++).
fuente
char *
, ya que los literales de cadena en C son de tipochar[]
. Sin embargo, no deben modificarse de ninguna manera, por lo queconst char*
se prefiere regresar (consulte securecoding.cert.org/confluence/x/mwAV ). La devoluciónchar *
puede ser necesaria si la cadena se usará en una función de biblioteca externa o heredada que (desafortunadamente) espera unchar*
argumento como, incluso aunque solo se leerá de ella. C ++, por otro lado, tiene literales de cadena deconst char[]
tipo (y, desde C ++ 11, también puede tenerstd::string
literales).fraught with problems
en la sección "Longevidad de los datos" es en realidad perfectamente válido. Los literales de cadena tienen vidas útiles estáticas en C / C ++. Vea el enlace que menciona Giorgi arriba.La cadena de CA se define como un puntero a una matriz de caracteres.
Si no puede tener punteros, por definición no puede tener cadenas.
fuente
void foo( char array[], int length)
. Por supuesto,array
es un puntero bajo el capó, pero no es un puntero "explícitamente" y, por lo tanto, puede ser más intuitivo para alguien que está aprendiendo matrices pero que no ha aprendido los punteros.Tenga en cuenta esta nueva función:
Definí "matriz" como estática. De lo contrario, cuando finaliza la función, la variable (y el puntero que está devolviendo) queda fuera de alcance. Dado que la memoria se asigna en la pila, es y será corromperse. La desventaja de esta implementación es que el código no es reentrante ni seguro para subprocesos.
Otra alternativa sería usar malloc para asignar la cadena en el montón y luego liberar en las ubicaciones correctas de su código. Este código será reentrante y seguro para subprocesos.
Como se señaló en el comentario, esta es una muy mala práctica, ya que un atacante puede luego inyectar código a su aplicación (él / ella necesita abrir el código usando GDB, luego hacer un punto de interrupción y modificar el valor de una variable devuelta para desbordar y la diversión acaba de comenzar).
Es mucho más recomendable dejar que la persona que llama se encargue de las asignaciones de memoria. Vea este nuevo ejemplo:
Tenga en cuenta que el único contenido que se puede modificar es el que tiene el usuario. Otro efecto secundario: este código ahora es seguro para subprocesos, al menos desde el punto de vista de la biblioteca. El programador que llama a este método debe verificar que la sección de memoria utilizada sea segura para subprocesos.
fuente
Su problema es con el tipo de retorno de la función; debe ser:
... y luego su formulación original funcionará.
Tenga en cuenta que no puede tener cadenas C sin que los punteros estén involucrados, en algún lugar a lo largo de la línea.
Además: suba las advertencias del compilador. Debería haberte advertido sobre esa línea de retorno que convierte
char *
achar
sin una conversión explícita.fuente
Según su historia de fondo recién agregada con la pregunta, ¿por qué no devolver un número entero del 1 al 12 para el mes y dejar que la función main () use una instrucción de cambio o una escalera if-else para decidir qué imprimir? Ciertamente no es la mejor manera de hacerlo, sería char *, pero en el contexto de una clase como esta, imagino que probablemente sea la más elegante.
fuente
Puede crear la matriz en el llamador, que es la función principal, y pasar la matriz al destinatario de la llamada, que es su myFunction (). Por lo tanto, myFunction puede llenar la cadena en la matriz. Sin embargo, debe declarar myFunction () como
Y en la función principal, myFunction debe llamarse de esta manera:
Sin embargo, todavía se usa un puntero.
fuente
El tipo de retorno de su función es un solo carácter (
char
). Debe devolver un puntero al primer elemento de la matriz de caracteres. Si no puedes usar punteros, estás jodido. :(fuente
O que tal este:
Y llámelo con el mes que calcula en otro lugar.
fuente
A
char
es solo un carácter de un byte. No puede almacenar la cadena de caracteres, ni es un puntero (que aparentemente no puede tener). Por lo tanto, no puede resolver su problema sin usar punteros (quechar[]
es azúcar sintáctico).fuente
Si realmente no puede usar punteros, haga algo como esto:
El número mágico 9 es espantoso y este no es un ejemplo de buena programación. Pero usted consigue el punto. Tenga en cuenta que los punteros y las matrices son lo mismo (más o menos), por lo que esto es un poco engañoso.
fuente
Bueno, en su código está intentando devolver un
String
(en C que no es más que una matriz de caracteres terminada en nulo), pero el tipo de retorno de su función es elchar
que le está causando todos los problemas. En su lugar, debe escribirlo de esta manera:Y siempre es bueno calificar su tipo
const
mientras asigna literales en C a punteros, ya que los literales en C no se pueden modificar.fuente
El prototipo de su función indica que su función devolverá un carácter. Por lo tanto, no puede devolver una cadena en su función.
fuente
En C, los literales de cadena son matrices con la clase de memoria constante estática, por lo que devolver un puntero a esta matriz es seguro. Hay más detalles en la pregunta de Stack Overflow "Vida útil" de un literal de cadena en C
fuente
Devolver cadena de función
fuente