Алгоритм сжатия LZW. Почему в консоль выводится мусор после 256 кода?

Есть такая строка в файле

abacabadabacabae

Я формирую из нее отдельные "слова" по алгоритму сжатия без потерь LZW . Словарь изначально заполнен ASCII кодами и их значениями в виде структуры.

    typedef struct Word {
 
    unsigned int code; 
    char * value; 
    } Word;

Изначально заполняю словарь

    // свободный код 

    unsigned int freeCode = 256;
    // Переменная, где будем хранить текущий код символа из входного файла
    int currentCharCode;

    
    // Словарь состоит из 4096 слов

    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);
 
    // Записываем в префикс с-строку [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 код нового символа

        printf("compressed file codes:\r\n");

    while ((currentCharCode = fgetc(inFile)) != EOF ){
        // формируем суффикс
        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){

                            printf ("%d\t%d\r\n", prefix.code, freeCode);

                   //Если выполнилось условие проверки, то это значит, что расширенного слова нет в нашем словаре, значит
                // Выводим в выходной поток код слова, которое есть в словаре
                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);
    }

Вот вывод в консоль из основного цикла сжатия:

введите сюда описание изображения

Тут я вывел в консоль код "предыдущего" слова в файле и код в "нового" слова в словаре.
Функция корректно сжимает строку abacab дальше в файл почему-то выводится мусор (смотреть первый столбик).

Почему так происходит?

Вот полный код моей программы для тех, кому нетрудно помочь с отладкой. Я постарался снабдить комментариями всю функцию сжатия.

Заранее спасибо.

        #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;
    
    // Начальная инициализация словаря
    // Значения Суффикса и префикса будем хранить в виде С-строк, чтобы иметь возможность использовать функции 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 код нового символа

        printf("compressed file codes:\r\n");

    while ((currentCharCode = fgetc(inFile)) != EOF ){
        // формируем суффикс
        sufix.value = checkNull(malloc(2*sizeof(char)));
        sufix.value[0] = currentCharCode;
        sufix.value[1] = '\0';
        sufix.code = currentCharCode;

        printf ("%d-%s\t", prefix.code, prefix.value);
        
        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;
             // Мы записали расширенное в словарь 
             printf("%d-%s\r\n", dictionary[freeCode]->code, dictionary[freeCode]->value);

                 // Теперь текущим словом должен стать суффикс расширенного слова

                 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, "rw");

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

    int codeInFile =0;
    printf ("%s\r\n", "decompress codes:");
    while (!feof(inFile)){
         fread(&codeInFile, sizeof(int), 1, inFile);

         if (codeInFile < freeCode){
            sufix.value = checkNull(malloc (2* sizeof(char)));
            sufix.value [0] = codeInFile;
            sufix.value [1] ='\0';
            realloc(dictionary[freeCode]->value, strlen(dictionary[freeCode]->value+2));
            if (dictionary[freeCode]->value == NULL){ 
                strcpy(dictionary[freeCode]->value, sufix.value);
                free(sufix.value);

            } 
            else{
                strcat(dictionary[freeCode]->value, sufix.value);
                free(sufix.value);
            }
         }
         else if (freeCode <= codeInFile){
            fprintf(outFile, "%s", dictionary[freeCode++]->value);
         }
         printf("%d-%s\t%d-%s\r\n", codeInFile, dictionary[codeInFile]->value, freeCode, dictionary[freeCode]->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;
    }  

Ответы (0 шт):