29 votes

Mon programme est assez bon pour mon affectation mais je sais que ce n'est pas bon

Je viens juste de commencer une mission pour l'uni et il a soulevé une question pour moi.

Je ne comprends pas comment faire pour retourner une chaîne de caractères à partir d'une fonction sans avoir une fuite de mémoire.

char* trim(char* line)  {
    int start = 0;
 int end = strlen(line) - 1;

 /* find the start position of the string */
 while(isspace(line[start]) != 0)  {
     start++;
 }
 //printf("start is %d\n", start);

 /* find the position end of the string */
 while(isspace(line[end]) != 0)  {
     end--;
 }
 //printf("end is %d\n", end);

 /* calculate string length and add 1 for the sentinel */
 int len = end - start + 2;

 /* initialise char array to len and read in characters */
 int i;
 char* trimmed = calloc(sizeof(char), len);

 for(i = 0; i < (len - 1); i++)  {
     trimmed[i] = line[start + i];
 }
 trimmed[len - 1] = '\0';

    return trimmed;
}

comme vous pouvez le voir je suis de retour d'un pointeur de char qui est un tableau. J'ai trouvé que si j'ai essayé de faire de la " garni de tableau par quelque chose comme:

char trimmed[len];

ensuite, le compilateur pourrait lancer un message disant qu'une constante a été prévu sur cette ligne. Je suppose que cela signifie que, pour une raison quelconque vous ne pouvez pas utiliser des variables comme la longueur du tableau lors de l'initialisation d'un tableau, bien que quelque chose me dit que peut ne pas être juste.

Donc à la place j'ai fait mon tableau par l'allocation de la mémoire pour un pointeur de char.

Je comprends que cette fonction est probablement waaaaay sous-optimale pour ce qu'il est en train de faire, mais ce que je veux vraiment savoir, c'est:

  1. Pouvez-vous normalement l'initialisation d'un tableau à l'aide d'une variable à déclarer la longueur comme:

    char garni[len];

  2. Si j'avais un tableau qui a été de ce type (char garni[]) aurait-il le même type de retour comme un pointeur sur char (ie char*).

  3. Si je fais mon tableau par l'allocation de la mémoire et de l'allouer à un pointeur de char, comment puis-je libérer cette mémoire. Il me semble qu'une fois j'ai retourné ce tableau, je ne peux pas accéder à la libre car il est une variable locale.

15voto

Justin Ethier Points 57486

Pour adresse (3) - Vous pouvez - free la nouvelle chaîne alloué à partir de votre code d'appel, une fois que vous avez fini avec elle:

char* tmp = trim(myline);

if (tmp != NULL) {
    ....
    free( tmp );
}

Mais cela impose un fardeau sur l'appelant n'oubliez pas de libérer la mémoire. Donc, au lieu de cela, vous pourriez envisager l'adoption d'un tampon alloué et de la taille du tampon d' trim(), par exemple:

void trim(char* line, char *trimmed_buf, int trimmed_buf_len){ ... }

Neil a fait un excellent travail pour répondre à votre autre question. Fondamentalement, un tableau de déclaration d' char trimmed[len]; va déclarer une variable locale sur la pile, alors, s'il est syntaxiquement correct pour retourner un char * de ce mémoire, l'emplacement de la mémoire qu'il indique n'est plus valide.

1voto

hlovdal Points 11039

Concernant la dynamique de dimensionnement d'une déclaration de tableau comme char trimmed[len]; la version la plus récente de la norme (ISO/IEC 9899:1999) permet, mais pour cette fonction, il ne serait pas utile à tous. L' trimmed variable a son champ d'application au sein de l' trim fonction et il est alloué sur la pile. Donc, si vous mettez de l' return trimmed; dans votre code, vous retourner un pointeur vers une variable sur la pile, et la partie de la pile où cette variable vies seront publiés au point où la fonction renvoie, donc, ça va pas très bien...

1voto

Edwin Buck Points 33097

Demander à l'appelant de lui passer un pointeur vers une zone mémoire (d'une longueur maximale) à la fonction. De cette façon, l'appelant sera responsable de l'allocation (et en libérant de l') la mémoire et de la fonction ne fournissent une sortie limitée de la mémoire tampon transmis à la fonction.

Assurez vous que la personne à l'aide de la fonction pourrait encore gâcher les choses (en spécifiant une durée qui n'a rien à voir avec réelle de la taille de la mémoire tampon, mais ensuite, vous pouvez correctement soutiennent que c'est l'appelant de la faute, non pas de ce les fonctions de faute.

0voto

Tom J Nowell Points 1915

De côté à partir de C++ solutions comme l'utilisation d' std::string, vous pouvez toujours allouer un tableau d'une taille de l'ensemble, et de passer la taille comme un paramètre, et le tableau comme paramètre par référence ou un pointeur?

De cette façon, les données sont affectées dans le même champ d'application et il n'y a pas de fuite de mémoire.

Puis à nouveau, vous pouvez toujours libérer la mémoire après l'appel. Cela signifie que le code responsable de la création et le code responsable de la destruction de données ne sont pas les mêmes, ce qui peut être un précurseur de fautes et d'erreurs.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X