-1

I tried to implement huffman algorithm with C using a binary tree and 2 queues :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define L 71/*Letters in the alphabet*/

typedef struct Node Node;

struct Node {

    int frequency;
    char letter;
    Node *left, *right;
};

typedef struct Queue Queue;

struct Queue {

    int front, rear;
    int size;
    int capacity;
    Node **array;
};

void readFile(char letterArray[L], int letterCount[L], const char* filename);
void fill(int *letterCount);
void findLowest(Node* leafNode, char letterArray[L], int letterCount[L]);
char findFrequency(int letterCount[L]);
Queue* newQueue(int capacity);
Node* newInternalNode(char letter, int f);
void addHeapNode(Queue* Q, Node* HeapNode);
void removeHeapNode(Queue* Heap, int indxToDel);
void buildTree(char letterArray[L], int letterCount[L]);
void printCodes(Node* root, int arr[100], int top);
int isLeaf(Node* root);
int cmpfunc (const void * item1, const void * item2);
int isSizeOne(Queue* queue);
int isEmpty(Queue* queue);
int isFull(Queue* queue);
void addLeaves(Queue *Q1, char letterArray[L], int letterCount[L]);
void enQueue(Queue* Q, Node* item);
Node* deQueue(Queue *Q);
Node* findMin(Queue *Q1, Queue *Q2);
Node* getFront(Queue *Q);

void printArr(int arr[], int n, int frequency);

int main(int argc, char const* argv[]) {

    if (argc != 2) {
        printf("Enter a file");
        return 1;
    }
    char letterArray[L] = {'"', '\'', '(', ')', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                       ':', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
                       'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
                       'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
    int letterCount[L];
    fill(letterCount);
    readFile(letterArray, letterCount, argv[1]);
    buildTree(letterArray, letterCount);
    return 0;
}

Queue* newQueue(int capacity) {

    Queue* newQueue = malloc(sizeof(Queue));
    newQueue->front = newQueue->rear = -1;
    newQueue->capacity = capacity;
    newQueue->size = 0;
    newQueue->array = (Node**) malloc(newQueue->capacity * sizeof(Node*));
    return newQueue;
}

Node* newInternalNode(char letter, int f) {

    Node* LeafNode = malloc(sizeof(Node));
    LeafNode->frequency = f;
    LeafNode->letter = letter;
    LeafNode->left = LeafNode->right = NULL;
    return LeafNode;
}

void fill(int *letterCount) {

    int i;

    for (i = 0; i < L; i++) {
        *letterCount = 0;
        letterCount++;
    }
}

void readFile(char letterArray[L], int letterCount[L], const char* filename) {

    FILE *fp;
    int c = 0;
    int i;

    fp = fopen(filename, "r");

    if (fp == NULL) {
        fprintf(stderr, "failure\n");
        exit(1);
    }
    for (;;) {
        c = fgetc(fp);
        if (feof(fp)) {
            break;
        }
        for (i = 0; i < L; i++) {
            if (letterArray[i] == c) {
                letterCount[i] += 1;
            }
        }
    }
    fclose(fp);
}

void addLeaves(Queue *Q1, char letterArray[L], int letterCount[L]) {

    int i = 0;

    for (i = 0; i < L; i++) {
        if (letterCount[i] > 0) {
            Node* LeafNode = malloc(sizeof(Node));
            LeafNode->frequency = letterCount[i];
            LeafNode->letter = letterArray[i];
            LeafNode->left = LeafNode->right = NULL;
            enQueue(Q1, LeafNode);
        }
    }
}

void buildTree(char letterArray[L], int letterCount[L]) {

    int array[100];
    int t = 0;
    Node *left, *right, *top;
    Queue *Q1, *Q2;
    int size = 0;
    Q1 = newQueue(L);
    Q2 = newQueue(L);

    addLeaves(Q1, letterArray, letterCount);
    qsort(Q1->array, Q1->size, sizeof(int), cmpfunc);

    // Run while Queues contain more than one node. Finally, first queue will
    // be empty and second queue will contain only one node
    while (!(isEmpty(Q1) && isSizeOne(Q2))) {
        // Step 3: Dequeue two nodes with the minimum frequency by examining
        // the front of both queues
        left = findMin(Q1, Q2);
        right = findMin(Q1, Q2);
        // Step 4: Create a new internal node with frequency equal to the sum
        // of the two nodes frequencies. Enqueue this node to second queue.
        top = newInternalNode('$', left->frequency+ right->frequency);
        top->left = left;
        top->right = right;
        enQueue(Q2, top);
        }
        Node* root = (Node*)malloc(sizeof(Node));
        root = deQueue(Q2);
        printCodes(root, array, t);
}

// A utility function to check if size of given queue is 1
int isSizeOne(Queue* queue)
{
    return queue->front == queue->rear && queue->front != -1;
}

// A utility function to check if given queue is empty
int isEmpty(Queue* queue)
{
    return queue->front == -1;
}

// A utility function to check if given queue is full
int isFull(Queue* queue)
{
    return queue->rear == queue->capacity - 1;
}

// A utility function to add an item to queue
void enQueue(Queue* Q, Node* item) {

    if (isFull(Q)) return;
    Q->array[++Q->rear] = item;
    Q->size++;
    if (Q->front == -1)
        ++Q->front;
}

// A utility function to remove an item from queue
Node* deQueue(Queue *Q) {
    if (isEmpty(Q)) return NULL;
    Node* temp = Q->array[Q->front];
    if (Q->front == Q->rear)  // If there is only one item in queue
        Q->front = Q->rear = -1;
    else
        ++Q->front;
    return temp;
}

// A utility function to get from of queue
Node* getFront(Queue *Q) {
    if (isEmpty(Q)) return NULL;
    return Q->array[Q->front];
}

/* A function to get minimum item from two queues */
Node* findMin(Queue *Q1, Queue *Q2) {
    // Step 3.a: If second queue is empty, dequeue from first queue
    if (isEmpty(Q1)) {
        return deQueue(Q2);
    }

    // Step 3.b: If first queue is empty, dequeue from second queue
    if (isEmpty(Q2)) {
        return deQueue(Q1);
    }

    // Step 3.c:  Else, compare the front of two queues and dequeue minimum
    if (getFront(Q1)->frequency < getFront(Q2)->frequency) {
        return deQueue(Q1);
    }

    return deQueue(Q2);
}

int cmpfunc (const void * item1, const void * item2) {

    struct Node *a = *(struct Node **)item1; // first dereference gets the pointer to the struct
    struct Node *b = *(struct Node **)item2;
    return( a->frequency - b->frequency ); // second dereference using -> notation gets the id
}

void printCodes(Node* root, int arr[100], int top) {

    if (root->left) {
        arr[top] = 0;
        printCodes(root->left, arr, top + 1);
    }

    if (root->right) {
        arr[top] = 1;
        printCodes(root->right, arr, top + 1);
    }

    if (isLeaf(root)) {
        printf("'%c' : ", root->letter);
        printArr(arr, top, root->frequency);
        printf("\n");
    }
}

int isLeaf(Node* root) {
    return !(root->left) && !(root->right);
}

void printArr(int arr[], int n, int frequency) {

    int i;
    for (i = 0; i < n; ++i) {
        printf("%1d", arr[i]);
    }
    printf(" (%d * %d)", n, frequency);
}

When I compile and execute this code I get this error :

Segmentation fault (core dumped)

segmentation fault line 237 return( a->frequency - b->frequency ); // >second dereference using -> >notation gets the id

Any help will be greatly appreciated ^^

akram1rekik
  • 153
  • 1
  • 1
  • 7
  • 2
    Some details ( trace prints, debugging runs, minimal test cases, compiler brand and settings ) might be useful to helpful minds ... at first glance, some function signatures might be a problem, specifically the array dimensions in formal parameters ( eg.`int arr[100]`in `void printCodes(Node* root, int arr[100], int top)` ). – collapsar Dec 09 '15 at 22:58
  • Run your program in a debugger. At a minimum it will tell you where the seg fault is occuring. – kaylum Dec 09 '15 at 23:02
  • Note: in `newQueue()`, the node(s) pointed to by `newQueue->array` is(are) not initialized. – chux - Reinstate Monica Dec 09 '15 at 23:06
  • It's asking a lot to dump that much code into a question with very little information asking where your segmentation fault is. You need to do some debugging to narrow it down. You can't expect other people to do that work for you. The segmentation fault means you've probably got a bad pointer somewhere. – lurker Dec 09 '15 at 23:29
  • segmentation fault line 237 return( a->frequency - b->frequency ); // second dereference using -> notation gets the id – akram1rekik Dec 09 '15 at 23:52

1 Answers1

1

It is blowing up deep inside qsort, so it is a little tricky to debug. Try stopping in buildTree before calling qsort.

For starters:

qsort(Q1->array, Q1->size, sizeof(int), cmpfunc);

Should be:

qsort(Q1->array, Q1->size, sizeof(Node *), cmpfunc);

On Linux x86_64, sizeof(int) is 4, but pointers are 8. This stopped the crash and I got some kind of output after that.

I'd suggest carefully stepping through with printf or gdb one step at a time to make sure its all right each step.

Anders
  • 2,270
  • 11
  • 19