Leaking memory in word frequency program - c

I'm leaking a very small amount of memory in a wf function I'm writing, and I can't seem to exactly locate it. I'm using a hash table to hold freqency, but my testing makes it look like it's not in the hashing functions. Here are my functions to open/read files and free the data at the end. I'm sure it's a simple bug, but I've been looking at this code too long to be able to see it.
typedef struct {
int noInFiles, numFiles, numToPrint;
char** fileNames;
FILE** files;
Hash hash;
} Freq;
void handleInput(int argc, char* argv[], Freq* freq) {
int num = 0, i, j = 0;
char* crap;
printf("memcurrent pre fileName alloc: %d\n\n", memCurrent());
freq->fileNames = calloc(argc - 1, sizeof(char**));
printf("memcurrent post filename alloc: %d\n\n", memCurrent());
freq->numToPrint = 10;
if(argc < 2) {
freq->noInFiles = 1;
freq->numFiles = 0;
return;
}
for(i = 1; i < argc; i++) {
if(argv[i][0] == '-') {
if(argv[i][1] == 'n') {
num = strtol(argv[i] + 2, &crap, 10);
freq->numToPrint = num;
}
else {
fprintf(stderr, "Usage: wf [-nX] [file...]\n");
exit(EXIT_FAILURE);
}
}
else {
freq->fileNames[j] = calloc(strlen(argv[i]) + 1 ,sizeof(char));
strcpy(freq->fileNames[j], argv[i]);
j++;
freq->numFiles++;
}
}
}
void openFiles(Freq* freq) {
int i;
char* str;
printf("Memcurrent pre open: %d\n",memCurrent());
freq->files = calloc(freq->numFiles,sizeof(FILE**));
printf("Memcurrent post open: %d\n",memCurrent());
for(i = 0; i < freq-> numFiles; i++) {
freq->files[i] = fopen(freq->fileNames[i],"r");
if(freq->files[i] == NULL) {
str = malloc(strlen(freq->fileNames[i]) + 5);
sprintf(str,"wf: %s",freq->fileNames[i]);
perror(str);
free(str);
exit(EXIT_FAILURE);
}
}
}
void freeFreq(int argc, Freq* freq) {
int i;
for(i = 0; i < argc - 1 ; i++) {
free(freq->fileNames[i]);
}
free(freq->fileNames);
free(freq->files);
}
Hash functions
typedef struct {
Entry* arr;
int size, numValid;
} Hash;
void initHash(Hash* hash) {
hash->arr = calloc(BASESIZE, sizeof(Entry));
TOTALALLOC =+ (BASESIZE * sizeof(Entry));
hash->size = BASESIZE;
hash->numValid = 0;
}
void freeTable(Hash* hash) {
int i;
for(i = 0; i < hash->numValid - 1; i++) {
if(hash->arr[i].correct == 1 && hash->arr[i].valid == 1) {
wordsFreed++;
free(hash->arr[i].word);
}
}
free(hash->arr);
}

This might be it:
for(i = 0; i < hash->numValid - 1; i++) {
If you have numValid set to 0 at start, I'm presuming that you increment it each time you add an entry to the array.
So if numValid is 1, then you will never loop, which means you will leak one of your entries. It seems that each time you free the hash, you will leak one entry, unless the hash has no entries at all.

This may not fix your problem, but ..
There is a mismatch between the number of allocations and deallocations for freq->fileNames.
Allocation:
else {
freq->fileNames[j] = calloc(strlen(argv[i]) + 1 ,sizeof(char));
strcpy(freq->fileNames[j], argv[i]);
j++;
freq->numFiles++;
}
Deallocation:
for(i = 0; i < argc - 1 ; i++) {
free(freq->fileNames[i]);
}
Assuming the logic for allocation is correct, the logic for deallocation needs to be:
for(i = 0; i < freq->numFiles ; i++) {
free(freq->fileNames[i]);
}
PS
I noticed that you have calls to fopen but no calls to fclose in your posted code.

Related

double free or corruption when using char**

I'm allocating memory for my int *occurrences int *wordCounts and char **uniqueWords pointers and then at the end of the function that allocates the memory, i free them. However, when i compile the program i get an double free or corruption (!prev) aborting error. Is it caused by malloc,free or could it be due to how i initialize them inside the for loop ?
PS: I'm talking about the sortedCount() method, located towards the end
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#define MAX_STRING_SIZE 512 /* each line in the file can have up to 512 chars */
void populateWordsArray(int);
void reverse(int);
void first(int);
void middle(int);
void last(int);
int count(int, char*, int);
void sortedCount(int);
void determineUniqueWords(int *,char **, int);
void *malloc_or_end(size_t);
void* malloc_or_end(size_t sz) {
void *pointer;
pointer = malloc(sz);
if(pointer == NULL) {
printf("Out of memory, terminating.\n");
exit(-1);
}
return pointer;
}
/* turn into local */
FILE *file;
char **wordList;
void determineUniqueWords(int *occurrences, char **word, int N) {
int i = 0;
int j = 0;
for(i = 0; i < N; i++) {
if(occurrences[i] < 1) {
continue;
}
for(j = i + 1; j < N; j++) {
if(occurrences[j] == 1 && (strcmp(word[i],word[j])) == 0) {
occurrences[i]++;
occurrences[j] = 0;
}
}
}
}
/**
* Function populateWordsArray: reads N words from
* the given file and populates the wordList array with them.
* Has one argument: int N - the number of words to read.
* */
void populateWordsArray(int N) {
int i = 0;
while(i < N && (fscanf(file,"%s",wordList[i]) == 1)) { /* fscanf returns the number of successfully read items. If it's not 1, the read failed. Same as checking if fscanf reads the eof char. */
i++;
}
}
/**
* Function reverse: prints the words of the
* text file in reverse order.
* */
void reverse(int N) {
int i = 0;
for(i = N-1; i >= 0; i--) {
if(i == 0) {
printf("%s \n",wordList[i]);
} else if(strcmp(wordList[i],"") == 0) { /* improve this in main-> memory allocation */
continue;
}else {
printf("%s ",wordList[i]);
}
}
return;
}
/**
* Function first: Prints the first char of each
* word in the file.
* */
void first(int N) {
char firstChar;
int i = 0;
for(i = 0; i < N; i++) {
firstChar = *wordList[i];
printf("%c",firstChar);
}
printf("\n");
return;
}
/**
* Function middle: Prints the middle char of each word
* from the given file.
* */
void middle(int N) {
int middleIndex = 0;
int i = 0;
char midChar;
for(i = 0; i < N; i++) {
if((strlen(wordList[i]) % 2) == 0) { /* artios */
middleIndex = ((strlen(wordList[i]) / 2) - 1);
midChar = wordList[i][middleIndex];
}
else { /* peritos */
middleIndex = (int) ceil((strlen(wordList[i]) / 2));
midChar = wordList[i][middleIndex];
}
printf("%c",midChar);
}
printf("\n");
return;
}
/**
* Function last: Prints the last char of each
* word from the given file.
* */
void last(int N) {
int i = 0;
char lastChar;
int lastPos;
for(i = 0; i < N; i++) {
lastPos = strlen(wordList[i]) - 1;
lastChar = wordList[i][lastPos];
printf("%c",lastChar);
}
printf("\n");
return;
}
/**
* Function count: Prints the number of times
* that the selected word is found inside the N first words
* of the file.
* */
int count(int N, char *word, int callID) {
int i = 0;
int count = 0;
for(i = 0; i < N; i++) {
if(strcmp(word,wordList[i]) == 0) {
count++;
}
}
if(callID == 0) { /* if callID == 0 (main called count and we want the output) */
printf("%d",count);
printf("\n");
}
return count;
}
void sortedCount(int N) {
int i,j = 0;
int *occurrences;
int *wordCounts;
char **uniqueWords;
/* mem allocation */
uniqueWords = malloc_or_end(N * sizeof(char*)); /* worst case: every word is unique */
wordCounts = malloc_or_end(N * sizeof(int));
occurrences = malloc_or_end(N * sizeof(int));
/* initialize rootWord and occurrences for the "each word is unique and occurs only once" scenario */
for(i = 0; i < N; i++) {
uniqueWords[i] = malloc_or_end(MAX_STRING_SIZE * sizeof(char));
occurrences[i] = 1;
}
determineUniqueWords(occurrences,wordList,N);
/* populate the wordCounts & uniqueWords "arrays" with the appropriate data in order to sort them successfully */
for(i = 0; i < N; i++) {
if(occurrences[i] > 0) {
wordCounts[i] = count(N,wordList[i],1);
uniqueWords[i] = wordList[i];
}
}
for(i = 0; i < N; i++) {
free(uniqueWords[i]);
}
free(uniqueWords);
free(occurrences);
free(wordCounts);
return;
}
int main(int argc,char *argv[]) { /* argv[1] = op argv[2] = name argv[3] = <word> */
int N = -1;
int i = 0;
int spaceNum,nlNum = -1;
file = fopen(argv[2],"r");
if(file == (FILE *) NULL) { /* check if the file opened successfully */
fprintf(stderr,"Cannot open file\n");
}
fscanf(file,"%d",&N); /* get the N number */
wordList = malloc_or_end(N * sizeof(char *)); /* allocate memory for pointers */
for(i = 0; i < N; i++) {
wordList[i] = malloc_or_end(MAX_STRING_SIZE * sizeof(char)); /* allocate memory for strings */
}
populateWordsArray(N);
if(strcmp(argv[1],"-reverse") == 0) {
reverse(N);
} else if(strcmp(argv[1],"-first") == 0) {
first(N);
} else if(strcmp(argv[1],"-middle") == 0) {
middle(N);
} else if(strcmp(argv[1],"-last") == 0) {
last(N);
} else if((strcmp(argv[1],"-count") == 0) && argv[3] != NULL) {
i = count(N,argv[3],0);
} else if((strcmp(argv[1],"-sorted") == 0) && (strcmp(argv[3],"-count") == 0)) {
sortedCount(N);
} else {
/* i only wish i could print something here */
}
/* End of program operations */
for(i = 0; i < N; i++) {
free(wordList[i]);
}
free(wordList);
fclose(file);
return 0;
}
You are overwriting the value of a pointer to heap memory on line 185:
uniqueWords[i] = wordList[i];
This means that when you free it later, you are actually freeing the allocated rows in wordList. Now you have two problems:
When you free the wordList rows on lines 244-246, it will be a double-free
You are losing your reference to the uniqueWords rows.
Use strcpy to assign to a dynamically-allocated string rather than the = operation.

Checking if an array contains all the elements

I wrote a Code that reads from a txt.file stores it into an array , remove the spaces then print them out.
I want to add another functionality. This time is to check if the user provided the right input file.
I want to compare the array reds with the array stringcard and see if the array red contains all the elements of the array stringcard.
I have been searching on the internet for a while but I don't know how to solve this problem.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define max 13
#define stringlength 8
const char *stringcard[] = {
"REDA",
"RED2",
"RED3",
"RED4",
"RED5",
"RED6",
"RED7",
"RED8",
"RED9",
"RED10",
"REDJ",
"REDQ",
"REDK",
};
char * removechar(char str[], int ch) {
char * cpos = str;
while ((cpos = strchr(cpos, ch))) {
strcpy(cpos, cpos + 1);
}
return str;
}
int main(int argc, char ** argv) {
char * reds[max];
int i;
FILE * file = argc > 1 ? fopen(argv[1], "r") : stdin;
if (file == NULL)
return 1;
if (argc != 2) {
printf("[ERR]");
return 0;
}
for (i = 0; i < max; i++) {
reds[i] = malloc(stringlength);
fgets(reds[i], stringlength, file);
}
for (i = 0; i < max; i++) {
printf("%s", reds[i]);
}
// removes spaces
for (i = 0; i < max; i++) {
removechar(reds[i], ' ');
}
for (i = 0; i < max; i++) {
printf("%s", reds[i]);
}
int success = 1;
size_t size = sizeof(stringcard)/sizeof(stringcard[0]);
size_t size2 = sizeof(reds)/sizeof(reds[0]);
if(size == size2)
{
for(int i = 0; i<size;i++)
{
if(strcmp(stringcard[i], reds[i]) != 0){
success = 0;
printf("nope");
break;
}
}
}
return 0;
}
Input:
RED A
RED 2
RED 3
RED 4
RED 5
RED 6
RED 7
RED 8
RED 9
RED 10
RED J
RED Q
RED K
This is prefaced by my top comments.
This should work for cards in any order:
size_t size = sizeof(stringcard) / sizeof(stringcard[0]);
size_t size2 = sizeof(reds) / sizeof(reds[0]);
int allmatch = 0;
if (size == size2) {
allmatch = 1;
for (int i = 0; i < size; ++i) {
int curmatch = 0;
const char *curcard = &stringcard[i];
for (int j = 0; j < size; ++j) {
if (strcmp(curcard, reds[j]) == 0) {
curmatch = 1;
break;
}
}
if (! curmatch) {
allmatch = 0;
break;
}
}
}
printf("RESULT: %s\n",allmatch ? "MATCH" : "NOMATCH");
UPDATE:
if we know reds is sorted compare the result of strcmp with -1 or 1 rather than 0 depending on the order of the sorted elements. If stringcard is sorted of course exchange the roles
Okay, if we assume stringcard is always sorted [or we choose to pre-sort it], we can add an early escape to the inner loop that can save a small amount of time for the failed case:
size_t size = sizeof(stringcard) / sizeof(stringcard[0]);
size_t size2 = sizeof(reds) / sizeof(reds[0]);
int allmatch = 0;
if (size == size2) {
allmatch = 1;
for (int i = 0; i < size; ++i) {
int curmatch = 0;
char *redcard = reds[i];
for (int j = 0; j < size; ++j) {
int cmpflg = strcmp(redcard,stringcard[j]);
if (cmpflg == 0) {
curmatch = 1;
break;
}
if (cmpflg > 0)
break;
}
if (! curmatch) {
allmatch = 0;
break;
}
}
}
printf("RESULT: %s\n",allmatch ? "MATCH" : "NOMATCH");
Always try to use functions when possible.
int all_match(const char **table1, const char **table2, size_t t1size, size_t t2size)
{
for(size_t t1index = 0; t1index < t1size; t1index++)
{
int match = 0;
for(size_t t2index = 0; t2index < t2size; t2index++)
{
match = match || !strcmp(table1[t1index], table2[t2index]);
if(match) break;
}
if(!match) return 0;
}
return 1;
}
Given your other array is defined similarly, say inputArray, and both arrays are sorted before executing the following, then you could use code similar to: (including number of elements
//Assumes both arrays are sorted before executing the following
char success = 1;
size_t size = sizeof(stringcard)/sizeof(stringcard[0]);
size_t size2 = sizeof(inputArray)/sizeof(inputArray[0]);
if(size == size2)
{
for(int i = 0; i<size;i++)
{
if(strcmp(stringcard[i], inputArray[i]) != 0)
{
success = 0;
break;
}
}
{
else
{
success = 0;
}
//Proceed according to the value of success,
...

Merging and Sorting struct array in c

I am trying to make a c99 program that reports the number of bytes downloaded by devices using WiFi.
It takes in a packet file as input, and each packet is sorted into an array of structs that contain the mac id and size of packet.
Now I am trying to sort out the array of structs in ascending order, and add the bytes of the same mac address and delete the added record.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PACKETS "sample-packets"
#define MAXMACADD 500
struct packetStruct {
char mac[17];
int size;
} packetStruct[MAXMACADD];
struct output {
char mac[17];
int size;
} output[MAXMACADD];
void sortSize(struct packetStruct* macadd, int n) {
int j, i;
for (i = 1; i < n; i++) {
for (j = 0; j < n - i; j++) {
if (macadd[j].size < macadd[j + 1].size) {
struct packetStruct temp = macadd[j];
macadd[j] = macadd[j + 1];
macadd[j + 1] = temp;
}
}
}
}
void mergeMac2(struct packetStruct* macadd, struct output* output, int n) {
int i, j, k=0;
for (i = 0; i < n; i++) {
if (strcmp(macadd[i].mac, "\0") != 0) {
for (j = 0; j < n; j++) {
if (strcmp(macadd[j].mac, "\0") != 0) {
if (strcmp(macadd[i].mac, macadd[j].mac) == 0){
strcpy(output[k].mac, macadd[i].mac);
output[k].size += macadd[i].size;
macadd[i].size = 0;
}
} else j++;
}
} else i++;
k++;
}
}
int readpacket() {
char *token;
char buf[60];
int size;
FILE *packet = fopen(PACKETS, "r"); //open packet file in read mode
int i = 0;
int j = 0; //loop control variables
int k = 0;
while (fgets(buf, sizeof (buf), packet) != '\0') {
token = strtok(buf, "\t"); //tokenize buf and point to time
token = strtok(NULL, "\t"); //point to sender mac add
token = strtok(NULL, "\t"); //point to dest mac add
strcpy(packetStruct[i].mac, token);
token = strtok(NULL, "\t"); //point to byte size
packetStruct[i].size += atoi(token);
//printf("%i. %s\t%d\n", i, packetStruct[i].mac, packetStruct[i].size);
i++;
}
fclose(packet); //close packet file
sortSize(packetStruct, i);
mergeMac2(packetStruct, output, i);
for (i = 0; i < 20; i++) {
printf("%i. %s\t%d\n", i, packetStruct[i].mac, packetStruct[i].size);
}
for (i=0; i < 20; i++){
printf("%i. %s\t%d\n", i+1, output[i].mac, output[i].size);
}
return 0;
}
void main(int argc, char *argv[]) {
if (argc != 2) {
printf("%s: program needs 1 argument, but there was %d\n", argv[0], argc - 1);
exit(EXIT_FAILURE);
} else {
if (strcmp(argv[1], "packets") != 0) {
printf("%s: program expected command 'packets', but you wrote %s\n", argv[0], argv[1]);
} else {
if (readpacket() != 0) {
exit(EXIT_FAILURE);
}
}
}
}
You can compile in command line using:
$: gcc main.c
run using:
$: ./a.out packets
It is sorting it fine but the merging is the issue. Should i use another struct called output and store the values in there or should i just merge up the current array? time-efficiency is not necessary.
I can provide the sample input file if it would be useful.
If I have understood you correctly you want to add all sizes from the same mac address. Then mergeMac2() should be like that (edit: now it's a version that completely preserves the original macadd array):
// return number of elements in output
int mergeMac2(struct packetStruct* macadd, struct output* output, int n) {
int i, j, k=0;
for (i = 0; i < n; i++) {
// '"\0" makes no difference to "" here
//if (strcmp(macadd[i].mac, "\0") != 0) {
if (strcmp(macadd[i].mac, "") != 0) {
// search in putput;
for( j=0; j<k && strcmp( macadd[i].mac, output[j].mac ) != 0; j++ ) ;
if( j == k ) {
// not yet created in output
strcpy( output[k].mac, macadd[i].mac );
output[k].size = macadd[i].size;
k++;
} else {
output[j].size += macadd[i].size;
}
}
}
return k;
}
Now you have added all sizes for each mac address to the first struct element that originally contained that address. Your second printf() loop should now be:
int j, n;
...
n = mergeMac2( packetStruct, output, i );
for( j=0; j<n; j++ ) {
...
}
At least I think you should first merge and then sort but that depends on what you want to achieve, of course.
void mergeMac2(struct packetStruct* macadd, struct output* output, int n)
{
int i, j, k = 0;
for (i = 0; i < n; i++) {
/*
* If size is 0, the packet has already been processed.
*/
if (macadd[i].size == 0)
continue;
memcpy(&output[k], &macadd[i], sizeof(struct packetStruct));
for (j = i+1; j < n; j++) {
/*
* If size is 0, the packet has already been processed.
*/
if (macadd[j].size == 0)
continue;
if (strcmp(macadd[i].mac, macadd[j].mac) == 0) {
output[k].size += macadd[j].size;
/*
* Set size to 0 so that these packets won't be
* processed in the next pass.
*/
macadd[j].size = 0;
}
}
k++;
}
}

using strcmp with an array

Here is the full code. it keeps freezing now
typedef struct {
char *name;
} NAME;
setting the array to be null and then later on i expand it depending on how many entries i need to add.
NAME *array = NULL;
int itemCount = 0; // items inserted
int arraySize = 0; // size of array
int arrayCount; //gets size of file.
int found = 0;
int Add(NAME item)
{
if(itemCount == arraySize) {
if (arraySize == 0)
arraySize = 3;
else
arraySize *= 2; // double size of array
//relocate memory
void *tempMemory = realloc(array, (arraySize * sizeof(NAME)));
//error relocating memory
if (!tempMemory)
{
printf("Couldn't relocate the memory \n");
return(-1);
}
array = (NAME*)tempMemory;
}
array[itemCount] = item;
itemCount++;
return itemCount;
}
void printStruct()
{
int i;
for(i = 0; i < arrayCount; i++)
{
printf("%s \n", array[i].name);
}
}
int readFromFile()
{
int checkResult(char[]);
FILE *fp;
fp = fopen("names.txt", "r");
char names[arrayCount];
if (fp == NULL)
{
printf("Cannot access file \n");
}else{
while(!feof(fp))
{
fscanf(fp, "%s", names);
arrayCount++;
checkResult(names);
}
}
fclose(fp);
return 1;
}
int checkResult(char names[]){
NAME tempStruct;
int i;
if(array == NULL)
{
tempStruct.name = malloc((strlen(names) + 1) * sizeof(char));
strcpy(tempStruct.name, names);
tempStruct.count = 1;
}
else
{
for(i = 0; i < arrayCount; i++)
{
if(strncmp(array[i].name, names, arrayCount)==0)
{
printf("MATCH %s", names);
break;
}
}
if(i == arrayCount)
{
tempStruct.name = malloc((strlen(names) + 1) * sizeof(char));
strcpy(tempStruct.name, names);
}
if (Add(tempStruct) == -1)
{
return 1;
}
}
}
In the main i am freeing the memory and calling the other functions
int main(){
void printStruct();
int readFromFile();
readFromFile();
printStruct();
int i;
for (i = 0; i < arrayCount; i++)
{
free(array[i].name);
}
free(array);
return 0;
}
What we're doing here is looping through looking for the first match and breaking the loop when we find it. If we search without finding it anywhere in the array, then we add it...
NAME** array = calloc( MAX_NAMES, sizeof( NAME* ) );
int count = 0;
int checkName(char names[])
{
if(!count)
{
array[0] = calloc( 1, sizeof( NAME ) );
array[0]->name = malloc((strlen(names) + 1) * sizeof(char));
strcpy(array[0]->name, names);
count = 1;
}
else
{
int i;
for(i = 0; i < count; i++)
{
if(strcmp(array[i]->name, names)==0)
{
printf("MATCH %s", names);
break;
}
}
if( i == count && count < MAX_NAMES )
{
array[count] = calloc( 1, sizeof( NAME ) );
array[count]->name = malloc((strlen(names) + 1) * sizeof(char));
strcpy(array[count]->name, names);
count++;
}
}
}
The above code first tests to see that the array is not empty... if it is, then the first element is created for the array and the name is assigned.
Otherwise, it parses the array to see if any entry in the array already matches the name... if it does, it will break the loop and the i == count test will fail, so the name is not added.
If the loop finishes without matching the name, then the i == count test will return true and we add the new name to the end of the array, if there is room in the array.

Memory leak in C hash table implementation

I have implemented a hash table structure as follows (reads all words from a text files, and contructs a hash table and then prints all the values of the table on a single line):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
unsigned int hashf(const char *buf, size_t len) {
unsigned int h = 0;
size_t i;
for (i = 0; i < len; i++) {
h += buf[i];
h += h << 10;
h ^= h >> 7;
}
h += h << 3;
h ^= h >> 11;
h += h << 15;
return h;
}
void destroy_hash(char *hashtable[], int table_size) {
int i;
for (i=0; i<table_size; i++) {
if (hashtable[i]) {
free(hashtable[i]);
}
}
}
int main(int argc, char *argv[])
{
if (argc != 3) {
printf("Invalid parameters!\n");
return EXIT_FAILURE;
}
const char *filename = argv[1];
int table_size = atoi(argv[2]);
char *hashtable[table_size];
int i;
for (i = 0; i < table_size; i++) {
hashtable[i] = NULL;
}
unsigned int h, h_k;
FILE *fileread = fopen(filename, "r");
char *key;
char buf[100];
int probe_nro, word_nro = 0;
if (fileread) {
fscanf(fileread, "%99s", buf);
key = malloc((strlen(buf)+1)*sizeof(char));
memcpy(key, buf, strlen(buf) + 1);
while(!feof(fileread)) {
// Increase word_nro by 1
word_nro += 1;
if (word_nro <= table_size) {
h = hashf(key, strlen(buf)) % table_size;
if (!hashtable[h]) {
hashtable[h] = key;
}
else {
// Begin probing
probe_nro = 1;
// Save original hash to h_k:
h_k = h;
h = (h_k+(probe_nro*probe_nro)) % table_size;
while (hashtable[h] && (probe_nro <= 10000)) {
probe_nro += 1;
h = (h_k+(probe_nro*probe_nro)) % table_size;
}
// If no vacancy found after 10000 probes, return error
if (probe_nro == 10000) {
printf("Error: table full\n");
free(key);
destroy_hash(hashtable, table_size);
return(1);
}
hashtable[h] = key;
}
fscanf(fileread, "%99s", buf);
if (!feof(fileread)) {
key = malloc((strlen(buf)+1)*sizeof(char));
memcpy(key, buf, strlen(buf) + 1);
}
}
else {
free(key);
printf("Error: table full\n");
destroy_hash(hashtable, table_size);
return(1);
}
}
for (i=0; i < table_size; i++) {
if (hashtable[i]) {
printf("%s", hashtable[i]);
}
else {
printf(" ");
}
if (i < table_size - 1) {
printf(",");
}
}
printf("\n");
destroy_hash(hashtable, table_size);
}
else {
printf("Can't open file!\n");
return(1);
}
return(0);
}
I can't find the memory leak, which is indicated in valgrind as:
total heap usage: 7 allocs, 6 frees, 604 bytes allocated
still reachable: 568 bytes in 1 blocks
Can you maybe spot, what I should still free, or what I'm doing wrong? Many thanks.
On this line
if (!feof(fileread)) {
key = malloc((strlen(buf)+1)*sizeof(char));
memcpy(key, buf, strlen(buf) + 1); // <--
}
You are making key point to a new location without freeing the old memory you allocated with malloc. It should be
if (!feof(fileread)) {
free(key); // <--
key = malloc((strlen(buf)+1)*sizeof(char));
memcpy(key, buf, strlen(buf) + 1);
}
void destroy_hash(char *hashtable[], int table_size) {
int i;
for (i=0; i<table_size; i++) {
if (hashtable[i]) {
free(hashtable[i]);
hashtable[i] = NULL; /* this one ? */
}
}
}

Resources