2009-10-28 3 views
2

J'apprends le C++. J'essaie d'apprendre cette allocation de mémoire dynamique. Dans le code ci-dessous, j'essaie d'allouer de la mémoire en utilisant malloc et realloc.Réallocation de mémoire dynamique à l'aide de realloc

int main (void) { 
    char *g = (char*) malloc (sizeof(char) * 2); 
    g = "ab"; 
    g = (char*) realloc (g, sizeof(char) * 200); 
    strcpy (g, "cdefg"); 
    cout << g << endl; 
    return 0; 
} 

Je reçois erreur de segmentation erreur lorsque j'exécute ce code.

J'ai vu d'autres threads SO recommandant d'utiliser soit vector ou new au lieu d'utiliser l'approche ci-dessus. Depuis, j'essaie d'apprendre cette approche, donc ces réponses ne s'appliquent pas à ma question.

J'ai rencontré un scénario où cette approche serait bien ajustée, par exemple, Si je lis un fichier texte brut en utilisant la fonction ifstream.read et en lisant, disons 1024bytes de celui-ci. Maintenant, si je veux m'assurer que je ne lis pas un mot qui est cassé dû à la taille de 1024bytes je dois lire plus loin de cette position en utilisant ifstream.get pour atteindre jusqu'à ce qu'un caractère d'espace soit trouvé. Dans ce scénario, j'ai besoin d'ajuster légèrement le tampon (qui est de 1024). Mon intention est d'utiliser realloc ici pour lui assigner plus de mémoire.

S'il vous plaît n'hésitez pas à me corriger si je me trompe n'importe où.

+8

Si vous apprenez C++, vous devriez utiliser 'new' et' delete'. –

+0

À TOUS GURUS: S'il vous plaît envisager de répondre à mon approche en lisant la partie fichier? Est-ce logique?Merci à l'avance – learner

+0

voir la réponse par sharptooth, aussi je voudrais mentionner que 2 caractères ne sont pas assez pour tenir "ab" en raison de la terminaison nulle – sellibitze

Répondre

7

Il y a beaucoup de problèmes avec votre code. Tout d'abord, vous ne devriez pas utiliser malloc et vos amis si vous programmez en C++.

char *g = (char*) malloc (sizeof(char) * 2); 
g = "ab"; 

Ooops. Vous venez de perdre les 2 octets de mémoire renvoyés par l'appel malloc parce que maintenant g des points à la lecture peut-être seul endroit où "ab" est stocké.

g = (char*) realloc (g, sizeof(char) * 200); 

realloc ne peut être fait appel à un pointeur renvoyé par un précédent malloc.

Même si vous avez passé un pointeur valide à realloc, realloc peut renvoyer NULL si la réallocation échoue. Dans ce cas, la mémoire allouée précédemment reste allouée mais vous écrasez la seule variable pointant vers cette mémoire, ce qui rend impossible la libération de l'allocation précédente. Voir Having dynamically allocated an array, can I change its size? dans la liste FAQ.

Notez également que "ab" nécessite trois octets de stockage, pas deux. Enfin, sizeof(char) est toujours et partout 1, donc il n'y a pas besoin d'utiliser sizeof(char) dans vos malloc appels.

Une version correcte C de votre programme ressemblerait à ceci:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main (void) { 
    char *tmp; 
    char *g = malloc(3); 
    if (!g) { 
     return EXIT_FAILURE; 
    } 

    strcpy(g, "ab"); 

    tmp = realloc (g, 200); 
    if (!tmp) { 
     return EXIT_FAILURE; 
    } 
    g = tmp; 

    strcpy (g, "cdefg"); 
    puts(g); 
    return 0; 
} 

Dans la version C++, vous pouvez utiliser string plutôt que les anciens régimes des tableaux de caractères de style C.

Voir my answer to another question un exemple de la façon de réattribuer un tampon pour lire des lignes complètes pour la deuxième partie de votre question.

Cependant, notez que le code est également C et je suis sûr qu'il existe de meilleures façons de faire ce que vous voulez en C++. Je ne connais pas assez la bibliothèque standard C++ pour vous donner une solution correcte en C++.

+0

Pouvez-vous m'expliquer la solution pour votre dernier para? Pourquoi realloc ne peut pas être utilisé s'il est manipulé en toute sécurité. – learner

+0

@learner Lien vers C FAQ ajouté. –

+1

Si le code ci-dessus doit être appelé correct, il doit vérifier la valeur de retour de 'malloc' et s'assurer qu'il n'est pas' NULL'. – Idelic

9

Dans

g = "ab"; 

vous faire le point g à un morceau situé dans le stockage statique, pas sur tas, puis dans

g = (char*) realloc (g, sizeof(char) * 200); 

vous essayez d'appeler realloc() avec cette adresse appartenant à l'extérieur du tas. Ceci est un comportement indéfini et bloque votre programme. Vous pouvez appeler realloc() uniquement avec les adresses renvoyées par malloc() ou realloc() (ou null).

Le problème est que vous vouliez dire ceci:

strcpy(g, "ab"); 

mais écrit par erreur ceci:

g = "ab"; 

L'ancien travaillerait Allright - g est d'abord réglée à une adresse renvoyée par malloc().

Il y a un autre problème - vous allouez initialement trop peu de mémoire. Vous devez allouer un octet supplémentaire pour le terminateur null.

3

Le problème est que la ligne:

g = "ab"; 

Déplace le pointeur g à un autre endroit tout à fait. Il ne copie pas le contenu. Vous perdez la trace de l'emplacement d'origine et lorsque vous utilisez g dans realloc, vous serez realloc en utilisant le mauvais pointeur.

Remplacer la ligne avec:

strcpy(g, "ab"); 

Bien sûr, vous aurez besoin de trois octets pour stocker la chaîne et le caractère de fin '\0'.Cela dit, malloc et realloc sont des choses de style C. Par conséquent, malloc et realloc Si vous utilisez C++, vous devriez essayer new et delete et probablement utiliser le type string pour stocker les chaînes.

2

Vous devez augmenter le malloc d'origine à 3 pour inclure le terminateur nul et utiliser strcpy pour définir le contenu de « ab »

char *g = (char*) malloc (sizeof(char) * 3); 
strcpy(g , "ab"); 
+0

Oui. Belle prise. –

0

Re la deuxième partie de votre question:

Tenir compte en utilisant std::vector.

std::vector<char> g; 
g.resize(1024); 
// fill up g 
// decide you need another hundred bytes at the end of g 
g.resize(1124); 
// memory will automatically be released when g goes out of scope 

Notez que pour passer un pointeur vers le début de la mémoire tampon, vous devrez maintenant dire &g[0] au lieu de simplement g.

+0

le problème est, si je dois lire les données d'un fichier ifstream.read prend seulement char * pas std :: string. Donc, vous ne pouvez pas passer l'approche ci-dessus ... Est-ce exact? – learner

+0

? Je suggère d'utiliser un 'std :: vector ', pas un 'std :: string'. '& g [0]' est un 'char *' qui peut être passé à 'ifstream :: read()'. Je ne suis pas sûr de comprendre votre question. – dave4420

Questions connexes