Segmentation Programme des défauts sur le retour 0 / fclose / gratuit. Je pense avoir des fuites de mémoire mais ne peut pas les trouver. Aide s'il vous plaît!

StackOverflow https://stackoverflow.com/questions/4321236

Question

Je suis en train d'écrire un programme de codage de Huffman pour compresser un fichier texte. À compléter le système, le programme prendra fin à la déclaration de retour, ou lorsque je tente de fermer un dossier que je lisais. Je suppose que j'ai des fuites de mémoire, mais je ne peux pas les trouver. Si vous pouvez les repérer, laissez-moi savoir (et une méthode pour les fixer serait appréciée!).

(note: small1.txt est un fichier texte standard)

Voici le programme principal

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define ASCII 255

struct link {
 int freq;
 char ch[ASCII];
 struct link* right;
 struct link* left;
};

typedef struct link node;
typedef char * string;
FILE * ofp;
FILE * ifp;
int writebit(unsigned char);
void sort(node *[], int);
node* create(char[], int);
void sright(node *[], int);
void Assign_Code(node*, int[], int, string *);
void Delete_Tree(node *);

int main(int argc, char *argv[]) {
 //Hard-coded variables
 //Counters

 int a, b, c = 0;
 //Arrays
 char *key = (char*) malloc(ASCII * sizeof(char*));
 int *value = (int*) malloc(ASCII * sizeof(int*));

 //File pointers

 FILE *fp = fopen(argv[1], "r");
 if (fp == NULL) {
  fprintf(stderr, "can't open %s\n", argv[1]);
  return 0;
 }
 //Nodes
 node* ptr;//, *head;
 node* array[ASCII];

 //
 int u, carray[ASCII];
 char str[ASCII];

 //Variables
 char car = 0;
 int inList = 0;
 int placeinList = -1;
 int numofKeys;

 if (argc < 2) {
  printf("Usage: huff <.txt file> \n");
  return 0;
 }

 for (a = 0; a < ASCII; a++) {
  key[a] = -1;
  value[a] = 0;
 }

 car = fgetc(fp);
 while (!feof(fp)) {
  for (a = 0; a < ASCII; a++) {
   if (key[a] == car) {
    inList = 1;
    placeinList = a;
   }
  }
  if (inList) {
   //increment value array
   value[placeinList]++;
   inList = 0;
  } else {
   for (b = 0; b < ASCII; b++) {
    if (key[b] == -1) {
     key[b] = car;
     break;
    }
   }
  }
  car = fgetc(fp);
 }
 fclose(fp);
 c = 0;
 for (a = 0; a < ASCII; a++) {
  if (key[a] != -1) {
   array[c] = create(&key[a], value[a]);
   numofKeys = c;
   c++;
  }
 }

 string code_string[numofKeys];

 while (numofKeys > 1) {
  sort(array, numofKeys);
  u = array[0]->freq + array[1]->freq;
  strcpy(str, array[0]->ch);
  strcat(str, array[1]->ch);
  ptr = create(str, u);
  ptr->right = array[1];
  ptr->left = array[0];
  array[0] = ptr;
  sright(array, numofKeys);
  numofKeys--;
 }

 Assign_Code(array[0], carray, 0, code_string);

 ofp = fopen("small1.txt.huff", "w");

 ifp = fopen("small1.txt", "r");

 car = fgetc(ifp);
 while (!feof(ifp)) {
  for (a = 0; a < ASCII; a++) {
   if (key[a] == car) {
    for (b = 0; b < strlen(code_string[a]); b++) {
     if (code_string[a][b] == 48) {
      writebit(0);
     } else if (code_string[a][b] == 49) {
      writebit(1);
     }
    }
   }
  }
  car = fgetc(ifp);
 }
 writebit(255);
 fclose(ofp);
 ifp = fopen("small1.txt", "r");
 fclose(ifp);
 free(key);
 //free(value);
 //free(code_string);
 printf("here1\n");
 return 0;
}

int writebit(unsigned char bitval) {

 static unsigned char bitstogo = 8;
 static unsigned char x = 0;

 if ((bitval == 0) || (bitval == 1)) {
  if (bitstogo == 0) {
   fputc(x, ofp);
   x = 0;
   bitstogo = 8;
  }
  x = (x << 1) | bitval;
  bitstogo--;
 } else {
  x = (x << bitstogo);
  fputc(x, ofp);
 }

 return 0;
}
void Assign_Code(node* tree, int c[], int n, string * s) {
 int i;
 static int cnt = 0;
 string buf = malloc(ASCII);
 if ((tree->left == NULL) && (tree->right == NULL)) {
  for (i = 0; i < n; i++) {
   sprintf(buf, "%s%d", buf, c[i]);
  }
  s[cnt] = buf;
  cnt++;
 } else {
  c[n] = 1;
  n++;
  Assign_Code(tree->left, c, n, s);
  c[n - 1] = 0;
  Assign_Code(tree->right, c, n, s);
 }
}
node* create(char a[], int x) {
 node* ptr;
 ptr = (node *) malloc(sizeof(node));
 ptr->freq = x;
 strcpy(ptr->ch, a);
 ptr->right = ptr->left = NULL;
 return (ptr);
}

void sort(node* a[], int n) {
 int i, j;
 node* temp;
 for (i = 0; i < n - 1; i++)
  for (j = i; j < n; j++)
   if (a[i]->freq > a[j]->freq) {
    temp = a[i];
    a[i] = a[j];
    a[j] = temp;
   }
}

void sright(node* a[], int n) {
 int i;
 for (i = 1; i < n - 1; i++)
  a[i] = a[i + 1];
}
Était-ce utile?

La solution

Si votre programme crashe sur ce qui est autrement une opération valide (comme le retour d'une fonction ou la fermeture d'un fichier), je vous rapprocherez garantie c'est un problème de dépassement de mémoire tampon plutôt que d'une fuite de mémoire.

Fuites de mémoire signifie généralement que votre mallocs finira par échouer, ils ne signifient pas que d'autres opérations seront affectées. Un débordement de la mémoire tampon d'un article sur la pile (par exemple) sera très probablement d'autres éléments corrompus sur la pile près de lui (comme une variable de descripteur de fichier ou l'adresse de retour de main).

Probablement votre meilleur pari est d'abord de mettre en place un point d'arrêt conditionnel à écrit aux descripteurs de fichiers. Cela devrait se faire dans les appels à fopen et nulle part ailleurs. Si vous détectez une écriture après les appels fopen sont terminés, ce sera où votre problème est survenu, afin d'examiner simplement la pile et la ligne d'exécution pour savoir pourquoi.


Votre premier problème (ce n'est pas nécessairement le seul) se trouve ici:

c = 0;
for (a = 0; a < ASCII; a++) {
    if (key[a] != -1) {
        array[c] = create(&key[a], value[a]);
        numofKeys = c;  // DANGER,
        c++;            //   WILL ROBINSON !!
    }
}

string code_string[numofKeys];

Vous pouvez voir que vous définissez le nombre de touches avant c incrément. Cela signifie que le nombre de touches est un de moins que vous avez réellement besoin pour que, lorsque vous accédez au dernier élément de code_string, vous accédez en fait quelque chose d'autre (ce qui est peu susceptible d'être un pointeur valide).

Remplacez le numofKeys = c; et c++; autour. Quand je fais cela, je reçois au moins au bit d'impression here1 et sortir sans une décharge de base. Je ne peux pas garantir l'exactitude du reste de votre code, mais cela résout la violation de segmentation donc tout le reste va probablement dans votre suivant question (le cas échéant).

Autres conseils

Je peux voir un problème:

strcpy(str, array[0]->ch);
strcat(str, array[1]->ch);

le champ ch de struct link est une matrice de taille char de 255. Il n'est pas NUL fin. Donc, vous ne pouvez pas copier à l'aide strcpy.

Vous avez également:

ofp = fopen("small1.txt.huff", "w");
ifp = fopen("small1.txt", "r");

Si small1.txt.huff n'existe pas, il sera créé. Mais si small1.txt il ne sera pas créé et fopen retournera NULL, vous devez vérifier la valeur de retour de fopen avant de partir et lecture du fichier.

Juste de comptage, vous avez 4 appels malloc séparés, mais seulement un appel free.

Je serais aussi méfiant de votre appel sprintf, et comment vous êtes réellement mallocing.

Vous faites un sprintf(buf, "%s%d", buf, c[i]) mais qui peut potentiellement être un dépassement de mémoire tampon si votre chaîne finale est plus longue que les octets de ASCII.

Je vous conseille de pas dans un débogueur pour voir où il est lancer une erreur de segmentation, puis débogage à partir de là.

i compilé le programme et a couru avec sa source que ce fichier small1.txt et obtenu « ne peut pas ouvrir (null) » si le fichier n'existe pas ou le exist de fichier et vous donner la commande comme ./huf small1.txt le programme plante avec:

Program terminated with signal 11, Segmentation fault.
#0  0x08048e47 in sort (a=0xbfd79688, n=68) at huf.c:195
195    if (a[i]->freq > a[j]->freq) {
(gdb) backtrace
#0  0x08048e47 in sort (a=0xbfd79688, n=68) at huf.c:195
#1  0x080489ba in main (argc=2, argv=0xbfd79b64) at huf.c:99

pour obtenir ce gdb vous exécutez

ulimit -c 100000000
./huf
gdb --core=./core ./huf

et le type backtrace

Vous avez plusieurs problèmes dans votre code:

1.- mallocs (doit être):

//Arrays
char *key = (char*) malloc(ASCII * sizeof(char));
int *value = (int*) malloc(ASCII * sizeof(int));

sizeof(char) == 1, sizeof(char *) == 4 or 8 (if 64 bits compiler is used).

tailles Tampon 255 2.- (ASCII) est trop court pour recevoir le contenu du tableau [0] -> ch + tableau [1] -.> Ch + '\ 0'

Utilisez strncpy au lieu 3.- de strcpy et strncat au lieu de strcat.

4.- clé est un tableau de personnes ou une caractères chaîne terminée par null?, Parce que vous utilisez cette variable dans les deux sens dans votre code. Dans la boucle de comptage des caractères que vous utilisez cette variable comme un tableau de caractères individus, mais dans la création de nœuds que vous passez le pointeur de la matrice et la copie sous forme de tableau terminée par un NULL.

5.- Enfin toujours vérifier vos paramètres avant utilisé, vous vérifiez si argc <2 après avoir essayé de argv ouvert [1].

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top