2010-03-14 13 views
5

Tengo función:Volviendo char * en función de

char *zap(char *ar) { 

    char pie[100] = "INSERT INTO test (nazwa, liczba) VALUES ('nowy wpis', '"; 
    char dru[] = "')"; 
    strcat(pie, ar); 
    strcat(pie, dru); 
    return pie; 
} 

y principal hay:

printf("%s", zap(argv[1]) ); 

Al compilar consigo la advertencia:

test.c: In function ‘zap’: 
test.c:17: warning: function returns address of local variable 

¿Cómo debería volver char * propertly?

+1

Parece que estás interactuando con una base de datos. ¿Debe usar C puro? Además, la mayoría de los DB tienen API para construir de forma segura las sentencias de SQL. ¿Puedes usar esos? – kennytm

+0

Gracias, sí, uso MySQL C API, pero debo crear una cadena para usar como consulta, porque no puedo usar variables en la consulta en sí. – Devel

Respuesta

18

Su mejor opción probablemente no es para regresar él en absoluto - en su lugar, pasar el buffer desea llenar en la función como un parámetro.

void zap(char * pie, const char *ar) { 
    strcpy(pie, "INSERT INTO test (nazwa, liczba) VALUES ('nowy wpis', '"); 
    char dru[] = "')"; 
    strcat(pie, ar); 
    strcat(pie, dru); 
} 

A continuación, llame así:

char pie[100]; 
zap(pie, "foo"); 

A prueba de balas esta función, también es necesario para pasar de la longitud de la memoria intermedia, y después comprobar contra esto cada vez que está a punto de añadir un nuevo elemento de consulta.

+5

desbordamiento de búfer dice hola – knittl

+2

Si hay un desbordamiento de búfer en este código, también habría uno en el original. Intento ilustrar un concepto, no escribir un código perfecto. –

+1

es suficiente. aún podrías escribir un mejor código usando strncpy. por cierto, te falta un paren en la línea 2;) – knittl

4

asignar la memoria para pie con malloc

+0

Como mencionaste malloc, ¿podrías ayudarme a escribir un malloc adecuado para esta función? – Devel

2
char pie[100]; 

void zap(char* pie, char *ar) { 

    char pies[100] = "INSERT INTO test (nazwa, liczba) VALUES ('nowy wpis', '"; 
    char dru[] = "')"; 
    strcpy(pie, pies); 
    strcat(pie, ar); 
    strcat(pie, dru); 
} 

zap(pie, argv[1]); 
printf("%s", pie ); 
2

Sugeriría encarecidamente cambiar esta función, dejar que el usuario pase un búfer y una longitud también y usar ese búfer en su lugar. Alternativamente, puede asignar una nueva instancia del valor de retorno, es decir, con malloc, pero asegúrese de dejar un comentario al usuario para liberarlo de nuevo.

1

declara la matriz static char

static char pie[100] = "INSERT INTO test (nazwa, liczba) VALUES ('nowy wpis', '"; 
+1

Los conflictos de subprocesos dicen hola, y la posibilidad de desbordamiento del búfer todavía está allí. –

+0

... ... ...: D ... ... ... – knittl

12

con las soluciones publicadas todo el trabajo, pero sólo para responder a su pregunta de por qué se obtiene una advertencia:

Cuando se declara la empanada como tampón en la función, no está asignando memoria de pila, la variable se está creando en la pila. Ese contenido de memoria solo está garantizado dentro del alcance de esa función. Una vez que abandona la función (después de la devolución) esa memoria se puede reutilizar para cualquier cosa y puede encontrar que la dirección de memoria a la que está apuntando se sobrescribe en cualquier momento. Por lo tanto, se le advierte que está devolviendo un puntero a la memoria que no se garantiza que permanezca.

Si desea asignar memoria persistente en una función c que puede hacer referencia fuera de esa función, necesita utilizar malloc (u otras funciones de asignación de memoria de montón). Eso asignará la memoria para esa variable en el montón y será persistente hasta que la memoria se libere con la función gratuita. Si no está claro en la pila frente a la memoria del montón, es posible que desee googlear en él, hará que su experiencia en C sea mucho más fluida.

+0

Aquí hay una buena respuesta para [stack vs heap] (https://stackoverflow.com/questions/79923/what-and-where-are-the-stack- and-heap) –

4
 
#include <assert.h> 
#include <stdio.h> 

/** 
* Returns the buffer, just for convenience. 
*/ 
char *generateSQL(char *buf, size_t bufsize, const char *ar) { 
    int n; 

    n = snprintf(buf, bufsize, "INSERT INTO test (nazwa, liczba) VALUES ('nowy wpis', '%s')", ar); 
    /* FIXME: Properly escape the argument, just in case it contains an apostrophe. */ 
    assert(0 <= n && (unsigned) n < bufsize); 
    return buf; 
} 

int main(int argc, char **argv) 
{ 
    char buffer[4096]; 

    assert(1 < argc); 
    printf("%s\n", generateSQL(buffer, sizeof(buffer), argv[1])); 
    return 0; 
} 
+0

Eso está bien, pero generalmente no desea usar assert() para verificar el error de tiempo de ejecución ... – jpalecek

+0

Lo sé ... pero es tan simple ...: -/ –

+0

¡Gran código, gracias! ¿Puedes leer en mi mente? ;) – Devel

0

enfoque ligeramente diferente:

void zap(char **stmt, char *argument, size_t *stmtBufLen) 
{ 
    char *fmt="INSERT INTO test(nazwa, liczba) VALUES ('nowy wpis', '%s')"; 
    /** 
    * Is our current buffer size (stmtBufLen) big enough to hold the result string? 
    */ 
    size_t newStmtLen = strlen(fmt) + strlen(argument) - 2; 
    if (*stmtBufLen < newStmtLen) 
    { 
    /** 
    * No. Extend the buffer to accomodate the new statement length. 
    */ 
    char *tmp = realloc(*stmt, newStmtLen + 1); 
    if (tmp) 
    { 
     *stmt = tmp; 
     *stmtLen = newStmtLen+1; 
    } 
    else 
    { 
     /** 
     * For now, just write an error message to stderr; the statement 
     * buffer and statement length are left unchanged. 
     */ 
     fprintf(stderr, "realloc failed; stmt was not modified\n"); 
     return; 
    } 
    } 
    /** 
    * Write statement with argument to buffer. 
    */ 
    sprintf(*stmt, fmt, argument); 
} 

int main(void) 
{ 
    char *stmtBuffer = NULL; 
    size_t stmtBufferLen = 0; 
    ... 
    zap(&stmtBuffer, "foo", &stmtBufferLen); 
    ... 
    zap(&stmtBuffer, "blurga", &stmtBufferLen); 
    ... 
    zap(&stmtBuffer, "AReallyLongArgumentName", &stmtBufferLen); 
    ... 
    zap(&stmtBuffer, "AnEvenLongerRidiculouslyLongArgumentName", &stmtBufferLen); 
    ... 
    free(stmtBuffer); 
    return 0; 
} 

Esta versión utiliza asignación dinámica de memoria para cambiar el tamaño de la memoria intermedia según sea necesario, a partir de un puntero de memoria intermedia NULL (realloc (NULL, tamaño) == malloc (tamaño)) De esta forma, no tiene que preocuparse por comenzar con un búfer que sea "lo suficientemente grande".El único inconveniente es que debes recordar desasignar el búfer cuando hayas terminado con él (normalmente no me gusta dividir los deberes de administración de memoria entre la persona que llama y la persona que llama así, si lo pensé durante más de 10 minutos, vengo con algo mejor).

0

La forma en que hago tales manipulaciones está haciendo intermedia local una variable de hilo específico estática:

const int max_pie_cnt = 100; 
const char *zap(char *ar) { 

    static __declspec(thread) char pie[max_pie_cnt]; // use TLS to store buffer 
    strcpy(pie, "INSERT INTO test (nazwa, liczba) VALUES ('nowy wpis', '"); 
    char dru[] = "')"; 
    strcat(pie, ar); 
    strcat(pie, dru); 
    return pie; 
} 

Estoy muy curiosa acerca de los comentarios de los expertos.

Por cierto, olvidemos el problema del desbordamiento del búfer por un momento.