pthread_join seg fault core dump - c

I am getting a seg fault error at my pthread_join line. Below is my thread creation and joining code as well as my my_func thread function that I am calling. The program is supposed to create a variable amount of threads to execute a grep like function.
int
parallelSearchStatic(char **argv)
{
pthread_t worker_thread[NUM_THREADS];
ARGS_FOR_THREAD *args_for_thread;
queue_element_t *element;
int i;
int num_occurrences = 0;
int queue_count = 0;
queue_t *queue = createQueue(); /* Create and initialize the queue data structure. */
DIR *d;
struct dirent *dir;
d = opendir(argv[2]);
if (d)
{
while ((dir = readdir(d)) != NULL)
{
element = (queue_element_t *)malloc(sizeof(queue_element_t));
if(element == NULL){
perror("malloc");
exit(EXIT_FAILURE);
}
strcpy(element->path_name, argv[2]);
strcat(element->path_name, "/");
strcat(element->path_name, dir->d_name);
insertElement(queue, element);
queue_count++;
}
closedir(d);
}
int increment = queue_count/NUM_THREADS;
for(i=0;i<NUM_THREADS;i++){
args_for_thread = (ARGS_FOR_THREAD *)malloc(sizeof(ARGS_FOR_THREAD));
args_for_thread->threadID=i;
args_for_thread->queue=createQueue();
args_for_thread->args=argv;
for(i = 0; i < increment; i++)
{
insertElement(args_for_thread->queue, removeElement(queue));
queue_count--;
}
if(i == (NUM_THREADS - 1) && queue_count != 0)
{
for(i = 0; i < queue_count; i++)
{
insertElement(args_for_thread->queue, removeElement(queue));
}
}
if((pthread_create(&worker_thread[i], NULL, my_func, (void *)args_for_thread))!=0){
printf("Cannot create thread \n");
exit(0);
}
}
for(i=0;i<NUM_THREADS;i++)
{
pthread_join(worker_thread[i], NULL);
}
for(i = 0; i < NUM_THREADS; i++)
num_occurrences += countArray[i];
return num_occurrences;
}
void *my_func(void *this_arg)
{
ARGS_FOR_THREAD *args_for_me = (ARGS_FOR_THREAD *)this_arg; // Typecast the argument passed to this function to the appropriate type
int threadID = args_for_me->threadID;
queue_t *queue = args_for_me->queue;
char** args = args_for_me->args;
int count = 0;
while(queue->head != NULL)
{
queue_element_t *element = removeElement(queue);
char *a[5];
a[0] = args[0];
a[1] = args[1];
a[2] = element->path_name;
a[3] = args[3];
a[4] = args[4];
count += serialSearch(a);
}
countArray[threadID] = count;
free((void *)args_for_me); // Free up the structure
pthread_exit(NULL);
}

You are using re-using i in nested loops within an outer loop that also uses i as its counter variable:
for(i = 0; i < increment; i++)
and
for(i = 0; i < queue_count; i++)
This means that your pthread_create() (which follows these inner loops) is using the wrong value of i to access worker_thread[i], so some values of worker_thread[] remain uninitialised and then cause pthread_join() to crash.
Use a different variable (eg. j) for the inner loops.

Related

Segmentation fault: core dumped during execution of multi-threaded program

I have realized that my code was too lengthy and rather hard to read.
Can you check over the way I pass in the arguments and constructing the arguments in the main body?
Essentially, provided that I have correct implementation of "produce" and "consume" functions, I want to pass in a shared circular queue and semaphores and mutexes to each produce/consume threads.
typedef struct circularQueue
{
int *items;
int *head;
int *tail;
int numProduced;
int numConsumed;
} circularQueue;
typedef struct threadArg
{
int id;
circularQueue *queue;
pthread_mutex_t *mutex;
sem_t *spaces;
sem_t *itemAvail;
int numItems;
int bufferSize;
int numProducer;
int numConsumer;
} threadArg;
pthread_t *producerThd;
pthread_t *consumerThd;
int main(int argc, char* argv[])
{
pthread_attr_t attr;
// In fo to pass to thread arg
circularQueue *myQueue;
pthread_mutex_t useSharedMem;
sem_t spaces;
sem_t itemAvail;
int numItems;
int bufferSize;
int numProducer;
int numConsumer;
int i, j, k, l;
if(argc != 5)
{
printf("Enter in 4 arguments - N B P C\n");
return -1;
}
numItems = atoi(argv[1]);
bufferSize = atoi(argv[2]);
numProducer = atoi(argv[3]);
numConsumer = atoi(argv[4]);
if(numItems == 0 || bufferSize == 0 || numProducer == 0 || numConsumer == 0)
{
printf("Parameters should not be 0\n");
return -1;
}
// Initialize list of threads
producerThd = malloc(sizeof(pthread_t) * numProducer);
consumerThd = malloc(sizeof(pthread_t) * numConsumer);
// Initialize semaphores
sem_init(&spaces, 0, bufferSize);
sem_init(&itemAvail, 0, 0);
// Initialize mutex
pthread_mutex_init(&useSharedMem, NULL);
// Initialzie thread attributes
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
// Initialize queue
myQueue = (circularQueue*)malloc(sizeof(circularQueue));
myQueue->items = (int*)malloc(sizeof(int)*bufferSize);
myQueue->head = myQueue->items;
myQueue->tail = myQueue->items;
myQueue->numProduced = 0;
myQueue->numConsumed = 0;
// thread arguments
for(i = 0; i < numProducer; i++)
{
// Initialize thraed args
threadArg *args = (threadArg*)malloc(sizeof(threadArg));
args->queue = (circularQueue*)malloc(sizeof(circularQueue));
args->mutex = &useSharedMem;
args->spaces = &spaces;
args->itemAvail = &itemAvail;
args->numItems = numItems;
args->bufferSize = bufferSize;
args->numProducer = numProducer;
args->numConsumer = numConsumer;
args->id = i;
pthread_t thisThread = *(producerThd + i);
pthread_create(&thisThread, &attr, produce, args);
}
for(j = 0; j < numConsumer; j++)
{
// Initialize thraed args
threadArg *args = (threadArg*)malloc(sizeof(threadArg));
args->queue = (circularQueue*)malloc(sizeof(circularQueue));
args->mutex = &useSharedMem;
args->spaces = &spaces;
args->itemAvail = &itemAvail;
args->numItems = numItems;
args->bufferSize = bufferSize;
args->numProducer = numProducer;
args->numConsumer = numConsumer;
args->id = j;
pthread_t thisThread = *(consumerThd + i);
pthread_create(&thisThread, &attr, consume, args);
}
for(k = 0; k < numProducer; k++)
{
pthread_join(*(producerThd+k), NULL);
}
printf("Finished waiting for producers\n");
for(l = 0; l < numConsumer; l++)
{
pthread_join(*(consumerThd+l), NULL);
}
printf("Finished waiting for consumers\n");
free(producerThd);
free(consumerThd);
free(myQueue->items);
free(myQueue);
sem_destroy(&spaces);
sem_destroy(&itemAvail);
fflush(stdout);
return 0;
}
Thank you
There are multiple sources of undefined behavior in your code, you are either compiling without enabling compilation warnings, or what I consider worst you ignore them.
You have the wrong printf() specifier in
printf("cid %d found this item %d as valid item %d\n", myArgs->id, thisItem, validItem);
because validItem is a double, so the last specifier should be %f.
Your thread functions never return a value, but you declare them to return void * which is the signature required for such functions.
You are freeing and dereferencing myQueue in the main() function but you have not initialized it because that code is commented.
Your code is also too hard to read because you have no consistent style and you mix declarations with statements, which make everything very confusing, e.g. determining the scope of a variable is very difficult.
Fixing the code will not only help others read it, but will also help you fix it and find issues quickly.

Context Switching using swap context() and a custom yield function

I am writing my own user level thread library and am running into some issues. Below is the code of the library I have written thus far after the edits provided by you guys and also some introspection from my end:
struct tcb {
int thread_id;
int thread_pri;
ucontext_t thread_context;
struct tcb *next;
} *ready_head;
typedef struct tcb tcb;
tcb *running_head;
tcb *tmp,*tmp1,*tmp2,*temp;
// ucontext_t *ready;
// head = NULL;
// running_head = head;
void t_shutdown()
{
free(temp);
free(tmp);
free(tmp1);
free(ready_head);
free(running_head);
}
void t_yield()
{
// tmp2 = ready_head;
tmp1 = running_head;
/* tmp = running_head;
running_head = ready_head;
while(tmp1->next != NULL)
tmp1 = tmp1->next;
tmp1->next = tmp;
*/
insert(tmp1);
running_head = ready_head;
ready_head = ready_head->next;
printf("yield1\n");
swapcontext(&running_head->thread_context, &tmp1->thread_context);
printf("yield2\n");
// setcontext(&ready_head->thread_context);
}
void insert(tcb *a)
{
tcb *b;
if (ready_head == NULL)
{
ready_head = a;
}
else
{
b = ready_head;
while(b->next)
b = b->next;
b->next = a;
}
printf("insert\n");
}
void t_init()
{
tmp = (tcb *)malloc(sizeof(tcb));
getcontext(&tmp->thread_context); /* let tmp be the context of main() */
tmp->next = NULL;
running_head = tmp;
ready_head = NULL;
}
int t_create(void (*fct)(int), int id, int pri)
{
size_t sz = 0x10000;
temp = (tcb *)malloc(sizeof(tcb));
getcontext(&temp->thread_context);
temp->thread_id = id;
temp->thread_pri = pri;
temp->thread_context.uc_stack.ss_sp = malloc(sz); /* new statement */
temp->thread_context.uc_stack.ss_size = sz;
temp->thread_context.uc_stack.ss_flags = 0;
temp->thread_context.uc_link = &tmp->thread_context;
makecontext(&temp->thread_context, fct, 1, id);
insert(temp);
printf("1\n");
}
I am testing this library on the following test program:
void assign(void)
{
int i;
for (i = 0; i < 3; i++)
printf("in assign(1): %d\n", i);
t_yield();
for (i = 10; i < 13; i++)
printf("in assign(2): %d\n", i);
t_yield();
for (i = 20; i < 23; i++)
printf("in assign(3): %d\n", i);
}
int main(int argc, char **argv)
{
t_init();
t_create(assign, 1, 1);
printf("in main(): 0\n");
t_yield();
printf("in main(): 1\n");
t_yield();
printf("in main(): 2\n");
t_yield();
printf("done...\n");
return (0);
}
The expected output is:
in main(): 0
in assign(1): 0
in assign(1): 1
in assign(1): 2
in main(): 1
in assign(2): 10
in assign(2): 11
in assign(2): 12
in main(): 2
in assign(3): 20
in assign(3): 21
in assign(3): 22
done...
However, I am getting:
in main(): 0
in main(): 1
in main(): 2
done...
I now know that there is an issue with the swapcontext() as that does not seem to be working at all. I have tried to use printf statements to debug my program but am still unable to get this to work! Please help ....
It appears to me that in your t_yield() function you are actually swapping the ready_head context with the ready_head context. You might want to try
swapcontext(&tmp->thread_context, &running_head->thread_context);
instead.

passing struct to pthread as an argument

Ok I am trying to pass pair of numbers through struct to pthread_create function in pthread. But the numbers i am passing and numbers i am getting when the function is called are different and random
Here is the struct
struct Pairs {
long i,j;
};
And inside main
void main()
{
long thread_cmp_count = (long)n*(n-1)/2;
long t,index = 0;
struct Pairs *pair;
pair = malloc(sizeof(struct Pairs));
cmp_thread = malloc(thread_cmp_count*sizeof(pthread_t));
for(thread = 0;(thread < thread_cmp_count); thread++){
for(t = thread+1; t < n; t++){
(*pair).i = thread;
(*pair).j = t;
pthread_create(&cmp_thread[index++], NULL, Compare, (void*) pair);
}
}
for(thread= 0;(thread<thread_cmp_count); thread++){
pthread_join(cmp_thread[thread], NULL);
}
free(cmp_thread);
}
And function Compare
void* Compare(void* pair){
struct Pairs *my_pair = (struct Pairs*)pair;
printf("\nThread %ld, %ld", (*my_pair).i, (*my_pair).j);
return NULL;
}
Number I am getting and it is also random.
Thread 0,2
Thread 1,2
Thread 2,3
Thread 2,3
Thread 2,3
Thread 2,3
am i passing the struct wrong ?
That is because you are passing the same pointer to all pthreads.
When you invoke pthread_create(..., (void*) pair) you are passing the pointer to the new thread, but in the next iteration you are overwriting that memory (potentially before the new thread has extracted those values).
long thread_cmp_count = (long)n*(n-1)/2;
long t,index = 0;
struct Pairs *pair;
cmp_thread = malloc(thread_cmp_count*sizeof(pthread_t));
for(thread = 0;(thread < thread_cmp_count); thread++){
for(t = thread+1; t < n; t++){
// allocate a separate pair for each thread
pair = malloc(sizeof(struct Pairs));
(*pair).i = thread;
(*pair).j = t;
pthread_create(&cmp_thread[index++], NULL, Compare, (void*) pair);
}
}
for(thread= 0;(thread<thread_cmp_count); thread++){
pthread_join(cmp_thread[thread], NULL);
}
free(cmp_thread);
.
void* Compare(void* pair){
struct Pairs *my_pair = (struct Pairs*)pair;
printf("\nThread %ld, %ld", (*my_pair).i, (*my_pair).j);
// free that memory after it has been used
free (pair);
return NULL;
}
Problem solved. Problem was with overlap. using pointer as an array of type struct Pairs it is solved
Here is the correct code
long thread_cmp_count = (long)n*(n-1)/2;
long t,index = 0;
Pair * pair;
pair = malloc(thread_cmp_count*sizeof(Pair));
free(thread_handles);
thread_handles = malloc(thread_cmp_count*sizeof(pthread_t));
for(thread = 0;(thread < n-1); thread++){
for(t = thread+1; t < n; t++){
(pair+index)->i = thread;
(pair+index)->j = t;
pthread_create(&thread_handles[index], NULL, Compare, (void*) (pair+index));
index++;
}
}
for(thread= 0;(thread<thread_cmp_count); thread++){
pthread_join(thread_handles[thread], NULL);
}
free(thread_handles);
And the function Compare
void* Compare(void* pair){
long t,i,j;
Pair *my_pair = (Pair*)pair;
i = my_pair->i;
j = my_pair->j;
printf("\n..................................................................");
if((x_array[i] < x_array[j])&&(x_array[i] != x_array[j])){
w_array[i] = 0;
printf(
"\nThread T(%ld,%ld)"
" compares x[%ld] = %ld and x[%ld] = %ld,"
" and writes 0 to w[%ld]", i, j,
i,x_array[i],
j,x_array[j],
i);
}
else if((x_array[i] > x_array[j])&&(x_array[i] != x_array[j])){
w_array[j] = 0;
printf(
"\nThread T(%ld,%ld)"
" compares x[%ld] = %ld and x[%ld] = %ld,"
" and writes 0 to w[%ld]", i, j,
i,x_array[i],
j,x_array[j],
j);
}
else
return NULL;
return NULL;
}

Having trouble when allocating memory when passing a double pointers address into a triple pointer

I'm creating a double pointer and sending in the address to allocate memory, which requires a triple pointer. Also, i am creating single pointers (goals and assists) and sending their addresses to allocate memory, which requires double pointers. I think the problem lies in allocation of memory, but i cant figure it out. I keep seg faulting whenever i run the readLinesFromFile function. It does not segfault when I try running allocateMemory function by itself. The problem could also be in the readLinesFromFile function
int main (int argc, char **argv)
{
int numPlayers = 0;
if (argc != 3)
{
printf("Missing text file");
return 0;
}
char **playerNames;
int *goals, *assists;
FILE *filePtr = fopen(argv[1],"r");
if(filePtr == NULL)
{
printf("\nFile is empty");
return 0;
}
numPlayers = countLinesInFile(filePtr);
allocateMemory(&goals,&assists,&playerNames,numPlayers);
readLinesFromFile(filePtr,goals,assists,playerNames,numPlayers);
}
void allocateMemory(int **goals, int **assists, char *** names, int size)
{
int i = 0;
*goals = malloc(MAX_NAME * sizeof(int));
*assists = malloc(MAX_NAME * sizeof(int));
*names = malloc(MAX_NAME * sizeof(char*));
for (i = 0; i < size; i++)
{
(names[i]) = malloc(MAX_NAME * sizeof(char*));
}
}
void readLinesFromFile(FILE *fptr, int *goals, int *assists, char **names, int numLines)
{
int i = 0, j = 0, x = 0;
char players[MAX_LINE];
char *tokenPtr;
fptr = fopen(INPUT,"r");
for(i = 0; i < numLines; i++)
{
fgets(players,MAX_LINE, fptr);
tokenPtr = strtok(players," ");
strcpy((*(names+i)), tokenPtr);
while (tokenPtr != NULL)
{
tokenPtr = strtok(NULL," ");
if (x = 0)
{
goals[i] = atoi(tokenPtr);
x = 1;
}
else
{
assists[i] = atoi(tokenPtr);
x = 0;
}
}
}
}
Assuming MAX_NAME is the maximum length of a player's name, this should work:
void AllocateMemory(char *** pppNames, int ** ppGoals, int ** ppAssists, size_t sizePlayersMax)
{
*pppNames = malloc(sizePlayersMax * sizeof **pppNames);
*ppGoals = malloc(sizePlayersMax * sizeof **ppGoals);9
*ppAssists = malloc(sizePlayersMax * sizeof **ppAssists);
{
size_t sizePlayersCount = 0;0
for (; sizePlayersCount < sizePlayersMax; ++sizePlayersCount)
{
(*pppNames)[sizePlayersCount] = calloc(MAX_NAME + 1, sizeof *((*pppNames)[sizePlayersCount]));
}
}
}
To prevent the app from overwriting memory in case of really long player names you might like to change this line:
strcpy((*(names+i)), tokenPtr);
to become:
if (tokenPtr)
strncpy((*(names+i)), tokenPtr, MAX_NAME);
This would truncate the player names stored to a maximum of MAX_NAME characters. The latter is the size AllocateMemory() use minus 1. This one spare character is needed for the 0/NUL to terminate the character-array so it could be used as a "string".
Finally also this is dangerous:
while (tokenPtr != NULL)
{
tokenPtr = strtok(NULL," ");
if (x = 0)
{
Better do like this:
while (NULL != (tokenPtr = strtok(NULL," ")))
{
if (x = 0)
{

Program Segmentation Faults on return 0/fclose/free. I think I have memory leaks but can't find them. Please help!

I am trying to write a Huffman encoding program to compress a text file. Upon completetion, the program will terminate at the return statement, or when I attempt to close a file I was reading from. I assume I have memory leaks, but I cannot find them. If you can spot them, let me know (and a method for fixing them would be appreciated!).
(note: small1.txt is any standard text file)
Here is the main program
#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];
}
If your program is crashing on what is otherwise a valid operation (like returning from a function or closing a file), I'll near-guarantee it's a buffer overflow problem rather than a memory leak.
Memory leaks just generally mean your mallocs will eventually fail, they do not mean that other operations will be affected. A buffer overflow of an item on the stack (for example) will most likely corrupt other items on the stack near it (such as a file handle variable or the return address from main).
Probably your best bet initially is to set up a conditional breakpoint on writes to the file handles. This should happen in the calls to fopen and nowhere else. If you detect a write after the fopen calls are finished, that will be where your problem occurred, so just examine the stack and the executing line to find out why.
Your first problem (this is not necessarily the only one) lies here:
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];
You can see that you set the number of keys before you increment c. That means the number of keys is one less than you actually need so that, when you access the last element of code_string, you're actually accessing something else (which is unlikely to be a valid pointer).
Swap the numofKeys = c; and c++; around. When I do that, I at least get to the bit printing here1 and exit without a core dump. I can't vouch for the correctness of the rest of your code but this solves the segmentation violation so anything else should probably go in your next question (if need be).
I can see one problem:
strcpy(str, array[0]->ch);
strcat(str, array[1]->ch);
the ch field of struct link is a char array of size 255. It is not NUL terminated. So you cannot copy it using strcpy.
Also you have:
ofp = fopen("small1.txt.huff", "w");
ifp = fopen("small1.txt", "r");
If small1.txt.huff does not exist, it will be created. But if small1.txt it will not be created and fopen will return NULL, you must check the return value of fopen before you go and read from the file.
Just from counting, you have 4 separate malloc calls, but only one free call.
I would also be wary of your sprintf call, and how you are actually mallocing.
You do an sprintf(buf, "%s%d", buf, c[i]) but that can potentially be a buffer overflow if your final string is longer than ASCII bytes.
I advise you to step through with a debugger to see where it's throwing a segmentation fault, and then debug from there.
i compiled the program and ran it with it's source as that small1.txt file and got "can't open (null)" if the file doesn't exist or the file exist and you give it on the command like ./huf small1.txt the program crashes with:
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
to get this from gdb you run
ulimit -c 100000000
./huf
gdb --core=./core ./huf
and type backtrace
You have various problems in your Code:
1.- mallocs (must be):
//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.- Buffer sizes 255 (ASCII) is too short to receive the contents of array[0]->ch + array[1]->ch + '\0'.
3.- Use strncpy instead of strcpy and strncat instead of strcat.
4.- key is an array of individuals chars or is a null terminated string ?, because you are using this variable in both ways in your code. In the characters counting loop you are using this variables as array of individuals chars, but in the creation of nodes you are passing the pointer of the array and copying as null terminated array.
5.- Finally always check your parameters before used it, you are checking if argc < 2 after trying to open argv[1].

Resources