double free or corruption when using char** - c

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.

Related

How do I use free() properly to free memory when using malloc for char?

I attempt to malloc char** to store string, and free this, but I got this error. I can't understand why. The steps are as follows:
1:
char **pid_array = (char **)malloc(sizeof(char *) * MAX_LEN);
2:
pid_array[0] = (char *)malloc(sizeof(char) * SINGLE_LEN * MAX_LEN);
3:
free(pid_array); free(pid_array[0]);
The detailed code follows:
#include <assert.h>
#include <ctype.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MAX_LEN 1000
#define SINGLE_LEN 10
int isPid(char *str) {
int len = strlen(str);
for (int i = 0; i < len; i++) {
if (isdigit(str[i]) == 0) {
return 1;
}
}
return 0;
}
void getFileName(char *dir_path, char *pid_array[], int *len) {
DIR *dir = opendir(dir_path);
if (dir == NULL) {
fprintf(stderr, "path open failed!\n");
exit(EXIT_FAILURE);
}
chdir(dir_path);
struct dirent *ent;
int i = 0;
while ((ent = readdir(dir)) != NULL) {
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
continue;
}
int size = strlen(ent->d_name);
if (isPid(ent->d_name) == 0) {
pid_array[i++] = ent->d_name;
}
}
*len = i;
closedir(dir);
}
int main(int argc, char *argv[]) {
int pflag, nflag, vflag;
pflag = 0;
nflag = 0;
vflag = 0;
int opt;
while ((opt = getopt(argc, argv, "pvn")) != -1) {
switch (opt) {
case 'p':
pflag = 1;
break;
case 'v':
vflag = 1;
break;
case 'n':
nflag = 1;
break;
}
}
printf("pflag=%d; nflag=%d; vflag=%d; optind=%d\n", pflag, nflag, vflag, optind);
char **pid_array = (char **)malloc(sizeof(char *) * MAX_LEN);
pid_array[0] = (char *)malloc(sizeof(char) * SINGLE_LEN * MAX_LEN);
for(int i=0; i < MAX_LEN; i++){
pid_array[i]=pid_array[i-1]+SINGLE_LEN;
}
/*
for (int i = 0; i < MAX_LEN; i++) {
pid_array[i] = (char *)malloc(sizeof(char) * SINGLE_LEN);
assert(pid_array[i] != NULL);
}
*/
for (int i = 0; i < MAX_LEN; i++) {
free(pid_array[i]);
}
int *pid_array_len = (int *)malloc(sizeof(int));
getFileName("/proc", pid_array, pid_array_len);
for (int i = 0; i < *pid_array_len; i++) {
printf("%d\n", atoi(pid_array[i]));
}
free(pid_array);
free(pid_array[0]);
free(pid_array_len);
return 0;
}
The error is follow:
error
The steps as noted are not correct.
if pid_array is char** then
*pid_array is char*
**pid_array is char
And you need to construct them as such. And free them in the reverse order. If you intend to have a vector of pointers at pid_array then your case is very very common: every C program gets one for free. The main prototype can be declared as
int main(int argc, char**argv);
The system knows how many char* to pass to the program, but in your case maybe the simplest (safest) way is to use encapsulation and build a block like this
typedef struct
{
size_t argc;
char** argv;
} Block;
I will let an example below.
a way to free the block properly
If you insist in using just the pointer you can easily adapt this. Anyway a possible implementation is
Block* delete (Block* blk)
{
if (blk == NULL) return NULL;
fprintf(
stderr, "Deleting block of %llu strings\n",
blk->argc);
for (int i = 0; i < blk->argc; i += 1)
free(blk->argv[i]);
free(blk->argv);
free(blk);
fprintf(stderr, "Deleted...\n");
return NULL;
}
The reason to return a pointer is to create a simple way to assure the pointer is invalidated as in
my_block = delete (my_block);
In the example
A block is created
is filled with strings of random size
the strings are printed
the block is deleted
main for the example
int main(void)
{
srand(220630);
const int size = MAX_LEN;
Block* my_block = build(size);
fill(my_block);
show(my_block, "a vector of numbered strings");
my_block = delete (my_block);
return 0;
}
the output
a vector of numbered strings
25 strings:
1 "#000#k"
2 "#001#swfsxji"
3 "#002#cn"
4 "#003#akmxhksqgb"
5 "#004#dqnegzryobmhucldx"
6 "#005#iiuqddvuvukkrs"
7 "#006#jxvlsolocgnvgjcrwh"
8 "#007#zylbzumyhmeswxuno"
9 "#008#ex"
10 "#009#ixinxqyxqydnswb"
11 "#010#ylxelydzqgs"
12 "#011#absdfpdjvgwhxcmzekr"
13 "#012#sceqzvmjskkrmszpth"
14 "#013#n"
15 "#014#rsmkrqhssjniqgphjp"
16 "#015#dgojvpflydevwudvv"
17 "#016#qbmaolgrskkqghhkgb"
18 "#017#uzsunopqpdawg"
19 "#018#rvdeaiooylywf"
20 "#019#zfejmgqxu"
21 "#020#fjubcmllylxqahvbfh"
22 "#021#zwanyivra"
23 "#022#vooropiugmuya"
24 "#023#js"
25 "#024#qzecia"
Deleting block of 25 strings
Deleted...
The complete C code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LEN 25
typedef struct
{
size_t argc;
char** argv;
} Block;
Block* build(size_t ttl);
Block* delete (Block* blk);
int fill(Block* bl);
int show(Block* blk, const char* title);
int main(void)
{
srand(220630);
const int size = MAX_LEN;
Block* my_block = build(size);
fill(my_block);
show(my_block, "a vector of numbered strings");
my_block = delete (my_block);
return 0;
}
Block* build(size_t ttl)
{
if (ttl == 0) return NULL;
Block* blk = (Block*)malloc(sizeof(Block));
if (blk == NULL) return NULL;
blk->argc = (ttl > MAX_LEN) ? MAX_LEN : ttl;
blk->argv = (char**)malloc(ttl * sizeof(char*));
if (blk->argv == NULL) return NULL;
for (int i = 0; i < ttl; i += 1)
*(blk->argv + i) = NULL;
return blk;
}
int fill(Block* bl)
{
const char prefix[] = "#nnn#"; // common prefix
char buffer[30] = {0};
char data[20] = {0};
for (int i = 0; i < bl->argc; i += 1)
{
int rest = 1 + rand() % 19;
for (int j = 0; j < rest; j += 1)
data[j] = 'a' + rand() % 26; // a single letter
data[rest] = 0; // terminates string
int res = sprintf(buffer, "#%03d#%s", i, data);
bl->argv[i] = (char*)malloc(strlen(buffer) + 1);
strcpy(bl->argv[i], buffer);
}
return 0;
}
int show(Block* blk, const char* title)
{
if (title != NULL) printf("%s\n", title);
printf("%llu strings:\n", blk->argc);
for (int i = 0; i < MAX_LEN; i += 1)
printf("%d\t \"%s\"\n", 1 + i, *(blk->argv + i));
printf("\n");
return 0;
}
Block* delete (Block* blk)
{
if (blk == NULL) return NULL;
fprintf(
stderr, "Deleting block of %llu strings\n",
blk->argc);
for (int i = 0; i < blk->argc; i += 1)
free(blk->argv[i]);
free(blk->argv);
free(blk);
fprintf(stderr, "Deleted...\n");
return NULL;
}
// https://stackoverflow.com/questions/72809939/
// how-do-i-use-free-properly-to-free-memory-when
// -using-malloc-for-char

get line in the text for each word

The following program prints the word frequency in a file. I am trying to save for each word in the text file, which line/lines appeared and how many times in total in the whole file. It counts how many times it appeared but I can't get which lines of the txt file.
There is a problem with int lines[]. The ouput of the program gives
segmentation fault
#define MAXWORDS 10000
#define MAXSTRING 100
/* structure holding word frequency information */
typedef struct _word {
char s[MAXSTRING]; /* the word */
int count; /* number of times word occurs */
int lines[1000];
} word;
void insert_word (word *words, int *n, char *s, int no) {
int i;
/* linear search for the word */
for (i=0; i<*n; i++) if (strcmp (s, words[i].s) == 0) {
/* found it? increment and return. */
words[i].count++;
words[i].lines[words[i].count]=no;
printf("%d", no);
return;
}
/* error conditions... */
if (strlen (s) >= MAXSTRING) {
fprintf (stderr, "word too long!\n");
exit (1);
}
if (*n >= MAXWORDS) {
fprintf (stderr, "too many words!\n");
exit (1);
}
/* copy the word into the structure at the first available slot,
* i.e., *n
*/
strcpy (words[*n].s, s);
/* this word has occured once up to now, so count = 1 */
words[*n].count = 1;
words[*n].lines[words[*n].count]=no;
/* one more word */
(*n)++;
}
...........
int main () {
word words[MAXWORDS];
char s[1000];
int i, n, m;
n = 0;
FILE* file = fopen("test.txt", "r");
/* read all the words in the file... */
int no=1;
while (fgets(s, sizeof(s), file)) {
scanf ("%s", s);
insert_word (words, &n, s,no);
no=no+1;
}
}
fclose(file);
qsort((void *) words, n, sizeof (word),
(int (*) (const void *, const void *)) wordcmp);
if (n < 20)
m = n;
else
m = 20;
for (i=0; i<m; i++)
printf ("%s\t[%d] {%d} \n", words[i].s, words[i].count, words[i].lines);
}
Here's a solution with dynamic memory allocation:
typedef struct _word {
char *s; /* the word */
int count; /* number of times word occurs */
int *line_numbers; // Array of line numbers
int num_line_numbers; // Size of the array of line numbers
} word;
// Creating a struct to hold the data. I find it's easier
typedef struct {
word *words; // The array of word structs
int num_words; // The size of the array
} word_list;
void insert_word (word_list *words, char *s, int line_number)
{
/* linear search for the word */
for (int i = 0; i < words->num_words; i++) {
if (strcmp (s, words->words[i].s) == 0) {
/* found it? increment and return. */
words->words[i].count++;
// See if it already appeared in this line
if (words->words[i].line_numbers[words->words[i].num_line_numbers - 1] == line_number) {
return;
}
// New line number. Increase the line number array by one
int *tmp = realloc(words->words[i].line_numbers, sizeof(int) * (words->words[i].num_line_numbers + 1));
if (NULL == tmp) exit(0);
words->words[i].line_numbers = tmp;
// Add the line number to the array
words->words[i].line_numbers[words->words[i].num_line_numbers] = line_number;
words->words[i].num_line_numbers += 1;
return;
}
}
/* error conditions... */
....
// Increase the size of the word array by one.
word *tmp = realloc(words->words, sizeof(word) * (words->num_words + 1));
if (tmp == NULL) exit(0);
words->words = tmp;
/* copy the word into the structure at the first available slot,
* i.e., *n
*/
words->words[words->num_words].s = malloc(strlen(s) + 1);
strcpy(words->words[words->num_words].s, s);
/* this word has occurred once up to now, so count = 1 */
words->words[words->num_words].count = 1;
words->words[words->num_words].line_numbers = malloc(sizeof(int));
words->words[words->num_words].line_numbers[0] = line_number;
words->words[words->num_words].num_line_numbers = 1;
words->num_words += 1;
}
bool remove_word(word_list *words, const char *word_to_delete)
{
for (int i = 0; i < words->num_words; i++) {
if (0 == strcmp(words->words[i].s, word_to_delete)) {
// TODO: handle special case where there is only 1 word in list
// Calc number of words after found word
int number_of_words_to_right = words->num_words - i - 1;
// Free mem
free(words->words[i].s);
free(words->words[i].line_numbers);
// Copy remaining words
memcpy(&words->words[i], &words->words[i + 1], sizeof(word) * number_of_words_to_right);
// Resize the array (technically not required)
word *tmp = realloc(words->words, sizeof(word) * --words->num_words);
if (NULL == tmp) exit(0);
words->words = tmp;
return true;
}
}
return false;
}
And in main()
word_list *words = malloc(sizeof(word_list));
if (NULL == words) exit(0);
memset(words, 0, sizeof(word_list));
....
/* read all the words in the file... */
char s[1000];
int line_number = 1;
while (fgets(s, sizeof(s), file)) {
char *word = strtok(s, " ");
while (word != NULL) {
size_t len = strlen(word);
if (len > 0 && word[len - 1] == '\n') word[--len] = 0;
insert_word(words, word, line_number);
word = strtok(NULL, " ");
}
line_number += 1;
}
fclose(file);
for (int i = 0; i < words->num_words; i++) {
printf("%s\t\t[%d] {", words->words[i].s, words->words[i].count);
for (int j = 0; j < words->words[i].num_line_numbers; j++) {
if (j != 0) printf(",");
printf("%d", words->words[i].line_numbers[j]);
}
printf("}\n");
}
// It's good practice to always free mem. It's super not important
// in this app since the OS will do it when you exit
for (int i = 0; i < words->num_words; i++) {
free(words->words[i].s);
free(words->words[i].line_numbers);
}
free(words->words);
free(words);

How to Assign Random String to 2D Array

The program reads a file which includes one word in every line.After reading random word put random word in a pointer and return the pointer .in main function
printf("%s",func("example.txt",str)) it prints different string when the program run.I want to do this in 2d array(20*20) like table,but i could not imagine how to do this.When i print the the function in internal loop,it give me the same word in every loop step.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
char *word(char *file, char *str);
int main() {
char *str ;
int i, j;
str = (char *)malloc(20);
srand(time(NULL));
char *puzzle[20][20];
for (i = 0; i < 20; i++) {
for (j = 0; j < 20; j++) {
puzzle[i][j] = word("words.txt", str);
}
}
for (i = 0; i < 20; i++) {
for (j = 0; j < 20; j++) {
printf("%s ", puzzle[i][j]);
}
printf("\n");
}
}
char *word(char *file, char *str) {
int end, loop, line;
FILE *fd = fopen(file, "r");
if (fd == NULL) {
printf("Failed to open file\n");
return (NULL);
}
srand(time(NULL));
line = rand() % 100 + 1;
for (end = loop = 0; loop < line; ++loop) {
if (0 == fgets(str, 20, fd)) {
end = 1;
break;
}
}
if (!end)
return (char *)str;
fclose(fd);
free(str);
}
I do not have your words.txt file, so I've created some random strings below.
And a note:
Because your nested loop is in the main, your code opens the file in the sub function and returns w/o closing it; then returns to the sub and reopens, and again, and again... It's always better to read at once and close the file before returning from the sub.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
char **word(int countString, int maxChars) {
int i;
int j;
int k;
// allocate memory for pointers that are pointing to each string
char **arrStr = malloc(countString * sizeof(char *));
// srand(time(NULL));
for (i = 0; i < countString; i++) {
// create a random string with a length of 'k'
// say, 5 <= k <= maxChars
// that (+ 1) is for the string terminating character '\0'
k = (rand() % (maxChars - 5)) + 5 + 1;
// allocate memory for string
arrStr[i] = malloc(k * sizeof(char));
for (j = 0; j < k - 1; j++) {
*(arrStr[i] + j) = rand() % 26 + 'A';
}
*(arrStr[i] + j) = '\0';
}
return arrStr;
}
int main() {
int countString = 10;
int maxChars = 20;
char **arrStr = NULL;
int i;
arrStr = word(countString, maxChars);
for (i = 0; i < 10; i++) {
printf("%s\n", *(arrStr + i));
}
// do not forget to free the strings
// and then the string pointers (array)
return 0;
}

Leaking memory in word frequency program

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.

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.

Resources