Ошибки сегментации программы при возврате 0 / fclose / free. Я думаю, что у меня есть утечки памяти, но я не могу их найти. Пожалуйста помоги! - PullRequest
0 голосов
/ 01 декабря 2010

Я пытаюсь написать программу кодирования Хаффмана для сжатия текстового файла. По завершении программа завершит работу в операторе возврата или при попытке закрыть файл, из которого я читала. Я предполагаю, что у меня есть утечки памяти, но я не могу их найти. Если вы можете их обнаружить, дайте мне знать (и метод их исправления будет признателен!).

(примечание: small1.txt - это любой стандартный текстовый файл)

Вот основная программа

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

Ответы [ 5 ]

3 голосов
/ 01 декабря 2010

Если ваша программа завершается с ошибкой в ​​том, что в противном случае является допустимой операцией (например, возврат из функции или закрытие файла), я почти гарантирую, что это проблема переполнения буфера, а не утечки памяти.

Утечки памяти обычно означают, что ваши mallocs в конечном итоге потерпят неудачу, они не означают, что будут затронуты другие операции.Переполнение буфера элемента в стеке (например), скорее всего, повредит другие элементы в стеке рядом с ним (например, переменная дескриптора файла или адрес возврата из main).

Вероятно, ваш лучшийСтавка изначально заключается в том, чтобы установить условную точку останова при записи в дескрипторы файла.Это должно происходить при звонках на fopen и больше нигде.Если вы обнаружите запись после того, как вызовы fopen будут завершены, именно там возникла ваша проблема, поэтому просто изучите стек и строку выполнения, чтобы выяснить причину.


Ваша первая проблема (это не обязательно единственная) лежит здесь:

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

Вы можете видеть, что вы устанавливаете количество клавиш до увеличения c.Это означает, что количество ключей на один меньше, чем вам нужно на самом деле, поэтому при доступе к последнему элементу code_string вы на самом деле получаете доступ к что-то еще (что вряд ли будет правильным указателем).

Поменяйте местами numofKeys = c; и c++;.Когда я это делаю, я по крайней мере добираюсь до битовой печати here1 и выхожу без дампа памяти.Я не могу ручаться за правильность остальной части вашего кода, но это решает нарушение сегментации, поэтому, возможно, все остальное должно идти в вашем следующем вопросе (если необходимо).

1 голос
/ 01 декабря 2010

Я вижу одну проблему:

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

ch поле struct link представляет собой char массив размером 255.Это не NUL прекращено.Поэтому вы не можете скопировать его, используя strcpy.

Также у вас есть:

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

Если small1.txt.huff не существует, он будет создан.Но если small1.txt он не будет создан и fopen вернет NULL, вы должны проверить возвращаемое значение fopen, прежде чем идти и читать из файла.

0 голосов
/ 01 декабря 2010

У вас есть различные проблемы в вашем коде:

1.- mallocs (должно быть):

//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).

2.- Размер буфера 255 (ASCII) слишком мал для приема содержимого массива [0] -> ch + array [1] -> ch + '\ 0'.

3.- Используйте strncpy вместо strcpy и strncat вместо strcat.

4.- ключ - это массив отдельных символов или строка с нулевым символом в конце? Потому что вы используете эту переменную в своем коде обоими способами. В цикле подсчета символов вы используете эти переменные в качестве массива отдельных символов, но при создании узлов вы передаете указатель массива и копируете его как массив с нулевым символом в конце.

5.- Наконец, всегда проверяйте ваши параметры перед использованием, вы проверяете, есть ли argc <2 после попытки открыть argv [1]. </p>

0 голосов
/ 01 декабря 2010

Я скомпилировал программу и запустил ее с исходным кодом в виде этого small1.txt файла и получил сообщение «невозможно открыть (ноль)», если файл не существует или файл существует, и вы передаете его по команде как ./huf small1.txt программа аварийно завершает работу с:

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

, чтобы получить это из gdb, который вы запускаете

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

и набираете backtrace

0 голосов
/ 01 декабря 2010

Только из подсчета у вас есть 4 отдельных malloc звонка, но только один free звонок.

Я бы также опасался вашего sprintf звонка и того, как вы на самом деле malloc инг.

Вы делаете sprintf(buf, "%s%d", buf, c[i]), но это может привести к переполнению буфера, если ваша последняя строка длиннее ASCII байтов.

Я советую вам пройтись с отладчиком, чтобы увидеть, где он выдает ошибку сегментации, а затем отладить оттуда.

...