Почему в файл копируются непечатные символы? Помогите в отладке программы
Я пытаюсь реализовать алгоритм lzw
Прошу помочь в отладке программы. Суть проблемы такая:
Есть текстовый файл со строкой
abacabadabacabae
Сжать его у меня (вроде как) получилось. Я получил файл с бинарным кодом сжатой строки. Вот его содержимое:
6100 0000 6200 0000 6100 0000 6300 0000
6162 0000 0101 0000 6100 0000 6400 0000
0401 0000 0501 0000 0201 0000 0301 0000
0801 0000 0901 0000 6100 0000
По моему там не хватает кода последней буквы e, но это не суть. Теперь из этого файла с бинарным кодом мне нужно получить исходную строку (или пока строку без e). Но в результате работы функции я получаю текст с большим количеством непечатных символов
abacabaadabac<0x01>aabac<0x01>adabacabac<0x01>abac<0x01>ad<0x04><0x05><0x02>abac<0x01>ad<0x04><0x05><0x02><0x03>aa
Уже смотрел ASCII таблицу. Это символы:
0x01 — START OF HEADING (Начало С-строки?)
0x02 — START OF TEXT (Начало текста в С-строке?)
0x03 — END OF TEXT (Конец С-строки?)
0x04 — END OF TRANSMISSION (Конец передачи данных (был достигнут конец входного файла?))
0x05 — Enquiry (Вообще не могу предположить, что он означает в моем случае)
Хотя непечатных символов ни в промежуточном файле, ни в итоговом, быть в файле вообще не должно! (Я прописал для этого условие в обоих функциях) Помогите разобраться, в чем причина такого поведения программы! Заранее всем огромное спасибо. Вот весь код Снабдил комментариями насколько мог.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lzwlib.h"
// слова будем хранить в структуре
typedef struct Word {
unsigned int code;
char* value;
} Word;
void* checkNull(void* ptr) {
if (ptr == 0) {
printf("%s", "out of memory");
exit(37);
}
return ptr;
}
// функция сжатия принимает на вход путь к файлу, который надо сжать
FILE* compress(const char* inputFileName) {
// Далее идет код, в котором формирую имя файла с расширением .lzw, наш выходной поток
//...
char* outputFileName = checkNull(malloc(strlen(inputFileName) + 5));
strcpy(outputFileName, inputFileName);
char* ex = strchr(outputFileName, '.');
if (ex) strcpy(ex, ".lzw");
else strcat(outputFileName, ".lzw");
// Теперь открываем наши файлы
FILE* outFile;
outFile = fopen(outputFileName, "wb");
FILE* inFile;
inFile = fopen(inputFileName, "r");
free(outputFileName);
// свободный код
unsigned int freeCode = 256;
// Переменная, где будем хранить текущий код символа из входного файла
int currentCharCode;
// Словарь состоит из 4096 слов
Word* dictionary[4096];
// Префикс и суффикс текущего слова
Word prefix;
Word sufix;
// очистка словаря от мусора
for (int i = 0; i < 4096; i++) {
sufix.value = checkNull(malloc(2 * sizeof(char)));
sufix.value[0] = 0;
sufix.value[1] = '\0';
dictionary[i] = checkNull(malloc(sizeof(Word)));
dictionary[i]->value = checkNull(malloc(2 * sizeof(char)));
strcpy(dictionary[0]->value, sufix.value);
dictionary[i]->code = 0;
}
// Начальная инициализация словаря
// Значения Суффикса и префикса будем хранить в виде С-строк, чтобы иметь возможность использовать функции strcat() strcpy()
// значению суффикса выделяем 2 байта
sufix.value = checkNull(malloc(2 * sizeof(char)));
sufix.value[0] = 0;
sufix.value[1] = '\0';
dictionary[0] = checkNull(malloc(sizeof(Word)));
dictionary[0]->value = checkNull(malloc(2 * sizeof(char)));
strcpy(dictionary[0]->value, sufix.value);
dictionary[0]->code = 0;
sufix.value = checkNull(malloc(2 * sizeof(char)));
for (int i = 0; i < 256; i++) {
// Переводим ASCII В C-строку, записываем ее в словарь
sufix.value[0] = i;
sufix.value[1] = '\0';
dictionary[i] = checkNull(malloc(sizeof(Word)));
dictionary[i]->value = checkNull(malloc(2 * sizeof(char)));
strcpy(dictionary[i]->value, sufix.value);
dictionary[i]->code = i;
}
// После инициализации в словаре хранятся строки "[ASCII-код]\0"
free(sufix.value);
// Записываем в префикс с-строку [ASCII-код]\0 первого символа из входного потока
currentCharCode = fgetc(inFile);
prefix.value = checkNull(malloc(2 * sizeof(char)));
prefix.value[0] = currentCharCode;
prefix.value[1] = '\0';
prefix.code = currentCharCode;
// будем использовать переменную для проверки есть ли слово в словаре
int inDictionary = 1;
// пока не конец файла Переприсваиваем currenCharCode код нового символа
while ((currentCharCode = fgetc(inFile)) != EOF) {
// формируем суффикс
if (currentCharCode > 31) {
sufix.value = checkNull(malloc(2 * sizeof(char)));
sufix.value[0] = currentCharCode;
sufix.value[1] = '\0';
sufix.code = currentCharCode;
}
if (strlen(prefix.value) <= strlen(dictionary[freeCode - 1]->value) && inDictionary == 1) realloc(prefix.value,
strlen(prefix.value) +
2);
if (prefix.value == NULL) prefix.value = strcpy(prefix.value, sufix.value);
// К нашему текущему префиксу добавляем суффикс Теперь слово у нас расширилось на один символ
else prefix.value = strcat(prefix.value, sufix.value);
// Проверяем словарь
for (int i = 0; i < freeCode; i++) {
// если мы найдем в словаре наш префикс, то коду префикса назначаем соответствующий код из словаря
if (strcmp(prefix.value, dictionary[i]->value) == 0) {
prefix.code = dictionary[i]->code;
inDictionary = 1;
} else {
inDictionary = 0;
}
if (inDictionary == 0 && i == freeCode - 1 && strlen(prefix.value + 1) != 0) {
//Если выполнилось условие проверки, то это значит, что расширенного слова нет в нашем словаре, значит
// Выводим в выходной поток код слова, которое есть в словаре
fwrite(&prefix.code, sizeof(int), 1, outFile);
// выделяем память под слово с первым свободным кодом
dictionary[freeCode] = checkNull(malloc(sizeof(Word)));
// выделяем память под значение нового слова в словаре
dictionary[freeCode]->value = checkNull(malloc(strlen(prefix.value) + 1));
// копируем новое слово в словарь
dictionary[freeCode]->value = strcpy(dictionary[freeCode]->value, prefix.value);
// Назначаем ему код
prefix.code = freeCode;
dictionary[freeCode]->code = prefix.code;
// Мы записали расширенное в словарь
// Теперь текущим словом должен стать суффикс расширенного слова
strcpy(prefix.value, sufix.value);
prefix.code = sufix.code;
free(sufix.value);
// и увеличиваю код свободного слова
++freeCode;
inDictionary = 1;
}
}
}
fclose(inFile);
fclose(outFile);
}
FILE* decompress(const char* inputFileName) {
const char* ex2 = ".lzw";
if (strstr(inputFileName, ex2) == 0 || strchr(inputFileName, '.') == 0) {
printf("%s", "incorrect file");
exit(38);
}
char* outputFileName = checkNull(malloc(strlen(inputFileName) + 1));
strcpy(outputFileName, inputFileName);
char* ex = strchr(outputFileName, '.');
if (ex) strcpy(ex, "2.txt");
else strcat(outputFileName, "2.txt");
// Теперь открываем наши файлы
FILE* outFile;
outFile = fopen(outputFileName, "w");
FILE* inFile;
inFile = fopen(inputFileName, "r");
free(outputFileName);
unsigned int freeCode = 256;
int currentCharCode;
Word* dictionary[4096];
Word prefix;
Word sufix;
// Начальная инициализация словаря
// Значения Суффикса и префикса будем хранить в виде С-строк, чтобы иметь возможность использовать функции strcat() strcpy()
// значению суффикса выделяем 2 байта
sufix.value = checkNull(malloc(2 * sizeof(char)));
sufix.value[0] = 0;
sufix.value[1] = '\0';
dictionary[0] = checkNull(malloc(sizeof(Word)));
dictionary[0]->value = checkNull(malloc(2 * sizeof(char)));
strcpy(dictionary[0]->value, sufix.value);
dictionary[0]->code = 0;
sufix.value = checkNull(malloc(2 * sizeof(char)));
for (int i = 0; i < 256; i++) {
// Переводим ASCII В C-строку, записываем ее в словарь
sufix.value[0] = i;
sufix.value[1] = '\0';
dictionary[i] = checkNull(malloc(sizeof(Word)));
dictionary[i]->value = checkNull(malloc(2 * sizeof(char)));
strcpy(dictionary[i]->value, sufix.value);
dictionary[i]->code = i;
}
// После инициализации в словаре хранятся строки "[ASCII-код]\0"
free(sufix.value);
sufix.value = checkNull(malloc(2 * sizeof(char)));
prefix.value = checkNull(malloc(2 * sizeof(char)));
int codeInFile = 0;
while (!feof(inFile)) {
fread(&codeInFile, sizeof(int), 1, inFile);
if (codeInFile < freeCode && codeInFile > 31) {
sufix.value[0] = codeInFile;
sufix.value[1] = '\0';
if (prefix.value == NULL) {
strcpy(prefix.value, sufix.value);
} else {
strcat(prefix.value, sufix.value);
// Проверяем есть ли в словаре получившаяся строка
for (int i = 0; i < freeCode; i++) {
// Если нет — добавляем ее в словарь, увеличиваем freeCode и обнуляем, выходим из цикла проверки
if (i == (freeCode - 1) && strcmp(dictionary[i]->value, prefix.value) != 0) {
dictionary[freeCode] = checkNull(malloc(sizeof(Word)));
dictionary[freeCode]->value = checkNull(malloc(strlen(prefix.value) + 1));
strcpy(dictionary[freeCode]->value, prefix.value);
dictionary[freeCode]->code = freeCode;
++freeCode;
free(prefix.value);
prefix.value = checkNull(malloc(sizeof(char) * 2));
break;
} else if (strcmp(dictionary[i]->value, prefix.value) == 0) break;
}
}
for (int i = 0; i < freeCode; i++) {
if (codeInFile == dictionary[i]->code) {
fprintf(outFile, "%s", dictionary[i]->value);
printf("%s", dictionary[i]->value);
}
}
}
}
fclose(inFile);
fclose(outFile);
}
// тестирую сжатие
int main() {
char* s = "toCompress.txt";
char* s2 = "toCompress.lzw";
FILE* compressed = compress(s);
FILE* decompressed = decompress(s2);
return 0;
}