Ошибка в кодах хаффмана

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Sobakaa
Сообщения: 16
Зарегистрирован: 04 сен 2009, 14:36

Код: Выделить всё

#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#define SIZE 256

struct SYM
{
	unsigned char ch; //ascii
	float freq; //symbol frequency
	char code[SIZE]; //new huffman code
	SYM *left; //left hand of tree
	SYM *right; //right hand of tree
};

SYM* huffTree(SYM *syms[], int N) //array of SYM structs and size N
{
	SYM *temp=(SYM*)malloc(sizeof(SYM));

	temp->freq=syms[N-1]->freq+syms[N-2]->freq;
	temp->code[0]=0;
	temp->left=0;
	temp->right=0;

	temp->left=syms[N-2];
	temp->right=syms[N-1];

	if(N==2)
		return temp;
	else
	{
		for(int i=0;i<N;i++)
		{
			if(temp->freq>syms[i]->freq)
			{
				syms[N-1]=syms[i];
				syms[i]=temp;
				temp=syms[N-1];
			}
		}
		return huffTree(syms, N-1);
	}
}

void makeCodes(SYM *root)
{
	if (root->left)
	{
		strcpy(root->left->code,root->code);
		strcat(root->left->code,"0");
		makeCodes(root->left);
	}
	if (root->right)
	{
		strcpy(root->right->code,root->code);
		strcat(root->right->code,"1");
		makeCodes(root->right);
	}
}

int main()
{
	int i=5;

	SYM *syms[SIZE];
	SYM arr[SIZE];

	arr[0].ch='a';
	arr[0].freq=0.4;
	arr[1].ch='b';
	arr[1].freq=0.3;
	arr[2].ch='c';
	arr[2].freq=0.1;
	arr[3].ch='d';
	arr[3].freq=0.1;
	arr[4].ch='e';
	arr[4].freq=0.1;
	syms[0]=&arr[0];
	syms[1]=&arr[1];
	syms[2]=&arr[2];
	syms[3]=&arr[3];
	syms[4]=&arr[4];

	SYM* root=huffTree(syms, i);
	makeCodes(root);
}
Не могу понять, в чём ошибка. Отладчик вылетает при первом обращении к strcpy, помещая в корень букву b.
_SG
Сообщения: 53
Зарегистрирован: 28 фев 2009, 10:43
Откуда: Севастополь

а как память под *syms[SIZE] выделяется?
Sobakaa
Сообщения: 16
Зарегистрирован: 04 сен 2009, 14:36

а как память под *syms[SIZE] выделяется?
Так это, статически. Под структурки в первой функции.

Не работает именно создание кодов.
_SG
Сообщения: 53
Зарегистрирован: 28 фев 2009, 10:43
Откуда: Севастополь

Статически? Я вижу лишь указатель на массив. А где под сам массив память выделяется? Я действительно не понимаю( Я не великий эксперт и просто не понимаю, что в итоге попадает в huffTree.
Sobakaa
Сообщения: 16
Зарегистрирован: 04 сен 2009, 14:36

Ммм, это массив указателей на структуру. Т.е. стоит читать SYM *syms[SIZE]. если по анси, то было бы
struct SYM *syms[SIZE].
В обращении же к левым-правым ветвям не знаю что происходит - не силён в структурах.
_SG
Сообщения: 53
Зарегистрирован: 28 фев 2009, 10:43
Откуда: Севастополь

Тьфу! Даже это забыл(
L.A.V.
Сообщения: 20
Зарегистрирован: 16 авг 2009, 23:37
Откуда: Солнечный Крым
Контактная информация:

А происходит следующее:
На третьей рекурсии функции makeCodes() условие

Код: Выделить всё

    if (root->left)
срабатывает не так как того хотелось бы, от того что root->left содержит указатель на мусор, а не нулевой адрес. А то что не ноль - все правда ;)
Далее функция strcpy() обращается к неинециализированному или недоступному участку памяти, что ни к чему хорошому не приводит.

Решение проблемы:
ограничить все висячие вершины дерева нулевыми указателями.
Сделать это нужно при посторении дерева, как я понимаю в huffTree().

Это относительно того, что ты спрашивал, а вобще не совсем уверен что дерево строится правильно, хотя могу ошибаться, особо в алгоритме не разбирался.
Sobakaa
Сообщения: 16
Зарегистрирован: 04 сен 2009, 14:36

Господа, вы не поверите - стоило мне воспользоваться режимом совместимости с предыдущей версией вижуал студио, с которой я перенёс исходник, как оно заработало!
>_< i'm going to Redmond and i'm going to kill!
Спасибо за советы, теперь лишних связей в дереве нет.
L.A.V.
Сообщения: 20
Зарегистрирован: 16 авг 2009, 23:37
Откуда: Солнечный Крым
Контактная информация:

Ну вот, а я как раз разобрался в алгоритме и даже нашел багу.

Но на счет зануления все же напишу, мож пригодится.
В момент инициализации массива буквами и вероятностями можно сделать следующее.

Код: Выделить всё

int main()
{
    ...
    arr[4].ch='e';
    arr[4].freq=0.1;
    
    for(int i = 0; i < SIZE; ++i)
    {
	arr[i].left = 0;
	arr[i].right = 0;
    }

    syms[0]=&arr[0];
    syms[1]=&arr[1];
    ...
}
после этого тоже все работает. Безо всяких переключений совместимости. :)
Теперь на счет бага.
Само дерево строится в принципе правильно, но с одним минусом - буква 'c' теряется, в место этого появляютя две буквы 'd'.
По моему все дело в сортировкое в haffTree().
Sobakaa
Сообщения: 16
Зарегистрирован: 04 сен 2009, 14:36

Ага, за зануление спасибо. В принципе штука не необходимая, но мусора нет - нет и опасности его куда-нибудь записать. Да и аксесс виолэйшн, который раньше один раз на 10 появлялся, кажется, пропал.

Что касается баги - у себя повторить не смог. Все символы файла в дереве, всё как надо. Возможно я выложил сюда код с багом, там пузырёк был так себе, я его переписал.
Ответить