Realloc failing after second call - c

I'm attempting to read in a list of words to be sorted and I start out with a fairly small array (10 elements) and then would like to increase the size of the array by 10 if the current capacity isn't enough. This seems to work with the first realloc, but I get a SIGABRT when trying to call realloc again. I'm sure it is a simple thing I'm not seeing, but I can't seem to figure it out. Here is my program:
int main(int argc, char *argv[]){
char *string = malloc(100);
// Array of pointers starting with 100 elements
char **toSort = malloc(100*sizeof(char *));
if(toSort == NULL) {
exit(1);
}
for(int i = 0; i < 100; i++) {
// Each string can be up to 100 characters long
toSort[i] = malloc(101);
if(toSort[i] == NULL) {
exit(1);
}
}
// Get all lines in the file
int counter = 0;
int max = 10;
char *toAdd;
FILE *txt = fopen("wlist0.txt", "r");
while(fgets ( string, 100, txt ) && counter < max) {;
toAdd = malloc(100);
if(toAdd == NULL) {
exit(1);
}
strcpy(toAdd, string);
toSort[counter] = string;
counter++;
//if the array needs to be enlarged
if(counter == max) {
char **new = realloc(toSort, (max+10) * sizeof(char));
if(new == NULL) {
exit(1);
}
for(int i = max; i < max + 10; i++) {
toSort[i] = malloc(101);
if(toSort[i] == NULL) {
exit(1);
}
}
toSort = new;
max += 10;
}
};
for(int i = 0; i < max; i++) {
char *word = toSort[i];
printf("%s", word);
}
for(int i = 0; i < max; i++) {
free(toSort[i]);
}
free(toSort);
return 0;
};
Like my comments say, my strings have a maximum length of 100 characters. I suppose I could dynamically allocate memory for the strings as well, but I'll worry about that when I have the other realloc working. Any help would be greatly appreciated.

This code assigns values to toSort after it the memory it points to is freed/modified by realloc():
//if the array needs to be enlarged
if(counter == max) {
char **new = realloc(toSort, (max+10) * sizeof(char));
if(new == NULL) {
exit(1);
}
for(int i = max; i < max + 10; i++) {
toSort[i] = malloc(101); <--- toSort is invalid here
if(toSort[i] == NULL) {
exit(1);
}
}
toSort = new;
max += 10;
}
This will work better:
//if the array needs to be enlarged
if(counter == max) {
char **new = realloc(toSort, (max+10) * sizeof( *new )); <-- fixed here, too
if(new == NULL) {
exit(1);
}
toSort = new;
for(int i = max; i < max + 10; i++) {
toSort[i] = malloc(101);
if(toSort[i] == NULL) {
exit(1);
}
}
max += 10;
}
There may be other errors in your code. I haven't fully examined it.

Related

Heap has been corrupted after a certain size malloc In C

Im trying to write a very simple compressor in C and I ran into the error "Heap has been corrupted" in my code. I looked into it, and the error seems to come because of this line:
ptr = (char*)malloc(count * sizeof(char));
when i change the size from count to 1000 it works, and i tried debugging and seeing if there is a difference somewhere but i couldnt find it, i understand there might be somekind of an overflow but i dont understand why and whats the solution instead of just writing a big number to fix it
this is my code for now:
#include <stdio.h>
#include <stdlib.h>
errno_t err;
int count =0;
struct node {
int data;
struct node* left;
struct node* right;
};
struct node* newNode(int data) {
struct node* node = (struct node*)malloc(sizeof(struct node));
node->data = data;
node->left = NULL;
node->right = NULL;
return (node);
};
int* frequency(char* str) {
FILE* fptr;
err = fopen_s(&fptr, str, "r");
if (err != 0)
{
printf("The file wasn't opened\n");
exit(0);
}
int* ptr;
ptr = (int*)malloc(95 * sizeof(int));
if (ptr == NULL) {
printf("Error! memory not allocated.");
exit(0);
}
for (int i = 0; i < 95; i++) {
*(ptr + i) = 0;
}
char ch;
int index;
while ((ch = fgetc(fptr)) != EOF) {
index = (int)ch - 32;
(*(ptr+index))++;
}
err = fclose(fptr);
if (err != 0)
{
printf("The file wasn't closed\n");
exit(0);
}
for (int i = 0; i < 95; i++) {
printf("%d ", *(ptr+i));
}
return ptr;
}
void* letFrequency(int* occLet) {
for (int i = 0; i < 95; i++) // counts how many actually occur
{
if (*(occLet+i) > 0)
{
count++;
}
}
int* ptr;
ptr = (char*)malloc(count * sizeof(char));
if (ptr == NULL) {
printf("Error! memory not allocated.");
exit(0);
}
int max = 0;
int placement = 0;
for (int j = 0; j < count; j++) {
for (int i = 0; i < 95; i++) {
if (*(occLet+i) >= max)
{
max = *(occLet+i);
placement = i;
}
}
*(ptr+j) = (char)(placement + 32);
printf("%c", *(ptr +j));
*(occLet+placement) = 0;
max = 1;
}
return ptr;
}
void binaryMap(char* letFrq) {
struct node* rootzero = newNode(1);
struct node* rootone = newNode(0);
int leaveszero = 0;
int leavesone = 0;
if (count % 2 == 0) {
leavesone = count / 2;
leaveszero = count / 2;
}
else
{
leavesone = count / 2;
leaveszero = count / 2 + 1;
printf("%d", leaveszero);
}
}
int main() {
char str[70];
printf("Enter the name of the text file you want to compress: ");
scanf_s("%s", str, sizeof(str));
int* ptrFr;
char* ptrLetFr;
ptrFr = frequency(str);
ptrLetFr = letFrequency(ptrFr);
free(ptrFr);
binaryMap(ptrLetFr);
}
The lines;
int* ptr;
ptr = (char*)malloc( count * sizeof(char));
are clearly erroneous. If you intended count integers, then sizeof(char) will allocate too small a block. I suggest as a habit:
Do not cast void* - just assign it.
Use sizeof the object pointed to, not an explicit type.
Do not leave dangling pointers unnecessary.
To that end:
int* ptr = malloc(count * sizeof(*ptr) ) ;
Or if it were _intended to be char* then:
char* ptr = malloc(count * sizeof(*ptr) ) ;
Note how minimal the change is - you don't have to correct it three different places.

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.

Error freeing memory after sorting the array pointer

How will I be able to maintain the position of the allocated memory so that freeing memory of a sorted array will not be affected?
I am trying to sort the pointer array. I noticed that when I free the words double pointer variable it will give an error HEAP CORRUPTION DETECTED. The input I entered was "f ff 1".
Unsorted: f ff 1
Sorted: 1 f ff
I noticed that when I sort and free it will expect the same order which is "f ff 1". That is why I got some error.
Any suggestion on how will be able to free the sorted pointer array?
#include <stdio.h>
/*
A logical type
*/
typedef enum {
false,
true,
} bool;
/*
Bubble Sort
*/
void sort(char *myargv[], int n)
{
int i, j, cmp;
char tmp[256];
if (n <= 1)
return; // Already sorted
for (i = 0; i < n; i++)
{
for (j = 0; j < n-1; j++)
{
cmp = strcmp(myargv[j], myargv[j+1]);
if (cmp > 0)
{
strcpy(tmp, myargv[j+1]);
strcpy(myargv[j+1], myargv[j]);
strcpy(myargv[j], tmp);
}
}
}
}
void printArray(char *myargv[], int myargc)
{
int i = 0;
for (i = 0; i < myargc; ++i) {
printf("myargc[%d]: %s\n",i , myargv[i]);
}
}
int main (int argc, char *argv[])
{
char text[256];
char *myargv[256];
char *myargvTemp[256];
int myargc;
int i = 0;
int text_len;
bool new_word = false;
int index_start_word = 0;
char **words; //this will store the found word
int count = 0;
while(1){
printf( "Enter text:\n");
gets(text); //get the input
text_len = strlen(text); //get the length of the text
words = (char **) malloc(text_len * sizeof(char));
if (strlen(text) == 0 || text == '\0') exit(0); //exit if text is empty
for (i = 0; i < text_len ; ++i){
if(text[i] != ' '){ //if not space
if(new_word == false){
new_word = true;
index_start_word = i;
}
} else {
if (new_word == true) {
words[count] = (char *)malloc(i - index_start_word * sizeof(char)+1); //memory allocation
strncpy(words[count], text + index_start_word, i - index_start_word);
words[count][i - index_start_word] = '\0'; //place NULL after the word so no garbage
myargv[count] = words[count];
new_word = false;
count++;
}
}
if (new_word == true && i == text_len-1){
words[count] = (char *)malloc(i - index_start_word * sizeof(char)+2);
strncpy(words[count], text + index_start_word, (i+1) - index_start_word);
words[count][(i+1) - index_start_word] = '\0';
myargv[count] = words[count];
new_word = false;
count++;
}
}
myargc = count;
//not sorted
printf("myargc is: %d\n", myargc);
printArray(myargv, myargc);
//sorting happen
sort(&myargv, myargc);
printf("-----sorted-----\n");
printf("myargc is: %d\n", myargc);
printArray(myargv, myargc);
memset(myargv, 0, 255);
count = 0;
i = 0;
//free the memory of words
for (i=0; i<myargc; ++i) {
free(words[i]);
}
}
return 0;
}
There are at least 2 problems in your code:
you do not allocate enough space for the array of pointers: change the words = (char **) malloc(text_len * sizeof(char)); to this:
words = malloc(text_len * sizeof(char *));
This allocation is actually incorrect: you should compute the number of words and allocate the correct size for the pointer array, or use a fixed size array.
you swap the contents of the strings instead of swapping the pointers. This is incorrect as the various strings do not have the same lengths.
Here is a corrected version of the sorting function:
void sort(char *myargv[], int n) {
int i, j, cmp;
if (n <= 1)
return; // Already sorted
for (i = 0; i < n; i++) {
for (j = 0; j < n-1; j++) {
cmp = strcmp(myargv[j], myargv[j+1]);
if (cmp > 0) {
char *tmp = myargv[j+1];
myargv[j+1] = myargv[j];
myargv[j] = tmp;
}
}
}
}
You want words to hold pointers to char so you need to change
words = (char **) malloc(text_len * sizeof(char)); //will allocate array of single byte
to
words = (char **) malloc(text_len * sizeof(char *));// will allocate array of pointers

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