2010-03-14 5 views
5

Je fonction:retour char * en fonction

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; 
} 

et principal, il y a:

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

Lors de la compilation je reçois l'avertissement:

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

Comment dois-je retourner char * propertement?

+1

Il semble que vous interagissiez avec une base de données. Dois-tu utiliser du C pur? En outre, la plupart des bases de données ont une API pour construire en toute sécurité les instructions SQL. Pouvez-vous les utiliser? – kennytm

+0

Merci, oui - J'utilise MySQL C API, mais je dois créer une chaîne à utiliser comme requête, car je ne peux pas utiliser de variables dans la requête elle-même. – Devel

Répondre

18

Votre meilleur pari est probablement de ne pas le retourner du tout -, passez le tampon que vous voulez remplir dans la fonction en tant que paramètre.

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); 
} 

Ensuite, appelez comme ceci:

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

Pour l'épreuve des balles cette fonction, vous devez également passer la longueur de la mémoire tampon, puis vérifiez contre chaque fois que vous êtes sur le point d'ajouter un nouvel élément de requête.

+5

débordement de tampon dit bonjour – knittl

+2

S'il y a un dépassement de tampon dans ce code, il y en aurait eu un dans l'original. J'essaie d'illustrer un concept, pas d'écrire du code parfait. –

+1

assez juste. vous pouvez toujours écrire du meilleur code en utilisant strncpy. btw, il vous manque un parent dans la ligne 2;) – knittl

4

Allouer la mémoire pour pie avec malloc

+0

Comme vous l'avez mentionné malloc, pourriez-vous m'aider à écrire un bon malloc pour cette fonction? – 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

Je suggère fortement de changer cette fonction, laissez l'utilisateur passer un tampon et une longueur ainsi et employez ce tampon à la place. Vous pouvez également allouer une nouvelle instance de la valeur de retour, c'est-à-dire malloc, mais veillez à laisser un commentaire à l'utilisateur pour le libérer à nouveau.

1

Déclarez votre tableau de caractères statique

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

Conflits multi-threads disent bonjour, et la possibilité de débordement de tampon est toujours là. –

+0

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

12

Les solutions supplémentaires de travail, mais juste pour répondre à votre question de savoir pourquoi vous obtenez un avertissement:

Lorsque vous déclarez tarte comme tampon dans la fonction, vous n'allouez pas de mémoire de tas, la variable est créée dans la pile. Ce contenu de la mémoire est seulement garanti dans le cadre de cette fonction. Une fois que vous quittez la fonction (après le retour) cette mémoire peut être réutilisée pour n'importe quoi et vous pourriez trouver l'adresse de mémoire que vous pointez à écraser à tout moment. Ainsi, vous êtes averti que vous renvoyez un pointeur vers la mémoire qui n'est pas garanti.

Si vous souhaitez allouer de la mémoire persistante dans une fonction c que vous pouvez référencer en dehors de cette fonction, vous devez utiliser malloc (ou d'autres fonctions de fonctions d'allocation de mémoire). Cela va allouer la mémoire pour cette variable sur le tas et il sera persistant jusqu'à ce que la mémoire soit libérée en utilisant la fonction libre. Si vous n'êtes pas clair sur la pile par rapport à la mémoire de tas, vous pouvez vouloir google dessus, cela rendra votre expérience de C beaucoup plus lisse.

+0

Voici une bonne réponse à [pile vs tas] (https://stackoverflow.com/questions/79923/what-and-where-are-the-stack- et-tas) –

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

C'est OK, mais vous ne voulez généralement pas utiliser assert() pour la vérification d'erreur d'exécution ... – jpalecek

+0

Je sais ... mais c'est si simple ...: -/ –

+0

Bon code, merci! Pouvez-vous lire dans mon esprit? ;) – Devel

0

approche légèrement différente:

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; 
} 

Cette version utilise l'allocation dynamique de la mémoire pour redimensionner le tampon au besoin, en commençant par un pointeur tampon NULL (realloc (NULL, taille) == malloc (taille)). De cette façon, vous n'avez pas à vous soucier de commencer avec un tampon qui est "assez grand".Le seul inconvénient est que vous devez vous rappeler de libérer le tampon quand vous en avez fini (je n'aime pas normalement partager les tâches de gestion de la mémoire entre l'appelant et l'appelé comme ça, si j'y ai réfléchi pendant plus de 10 minutes, d venir avec quelque chose de mieux).

0

La façon dont je fais de telles manipulations rend tampon local une variable de thread spécifique statique:

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; 
} 

Je suis très curieux au sujet des commentaires des experts.

Btw, oublions le problème de débordement de tampon pour un moment.