I wrote a lightweight dictionary for a quick project with C, and I am getting the error: realloc(): invalid next size. I know this means my heap is corrupted somehow, but I'm not sure what I did wrong, it seems like my code is super simple.
The realloc always fails the fourth access, ie when dict->num_kvs = 4
Below is my code. It includes the dict library as well as the function that is using it. Any help would be much appreciated
Offending function:
int* get_letter_frequencies(char* stream) {
Dict* dict = Dict_initialize();
for(int i = 0; i < strlen(stream); i++) {
Dict_increment_or_add_key(dict, stream[i]);
}
int* to_return = Dict_get_values_array(dict);
Dict_free();
return to_return;
}
simple_dict.c (plus the struct definitions)
typedef struct kv_pair {
char key;
int value;
} KV_Pair;
typedef struct dict_ {
struct kv_pair* kv_pairs;
int num_kvs;
} Dict;
Dict* Dict_initialize() {
Dict* to_return = malloc(sizeof(Dict));
to_return->num_kvs = 0;
to_return->kv_pairs = NULL;
return to_return;
}
void Dict_free(Dict* dict) {
free(dict->kv_pairs);
free(dict);
}
int Dict_add_key(Dict* dict, char key) {
dict->num_kvs++;
printf("next size: %d\n", dict->num_kvs);
dict->kv_pairs = realloc(dict->kv_pairs, dict->num_kvs * sizeof(KV_Pair));
printf("realloc passed \n");
dict->kv_pairs[dict->num_kvs].value = 1;
return 0;
}
int Dict_find_key(Dict* dict, char key){
for(int i = 0; i < dict->num_kvs; i++) {
char cur_key = dict->kv_pairs[i].key;
if(cur_key == key) {
return i;
}
}
return -1;
}
int Dict_increment_or_add_key(Dict* dict, char key) {
int key_index = Dict_find_key(dict, key);
if(key_index == -1) {
Dict_add_key(dict, key);
} else {
dict->kv_pairs[key_index].value++;
}
}
int* Dict_get_values_array (Dict* dict) {
int* to_return = malloc(dict->num_kvs * sizeof(int));
for(int i = 0; i < dict->num_kvs; i++) {
to_return[i] = dict->kv_pairs[i].value;
}
if(dict->num_kvs > 26) {
printf("more than 26 kvs: %d", dict->num_kvs);
}
return to_return;
}
When you try to add the first element, you are incrementing dict->num_kvs to 1, then you allocate a single element. Then this line:
dict->kv_pairs[dict->num_kvs].value = 1;
It will try to write to the [1] element, instead of [0] element. This is out of bounds. You should use:
dict->kv_pairs[dict->num_kvs-1].value = 1;
PS: If you're using GCC or Clang, AddressSanitizer is a great tool to help you detect these type of bugs.
Related
I am trying to implement a generic hash structure that can support any type of data and any hash function.
A wrote the code and try to run it, it dosn't work, it breaks. I try to debug it and there it works well. I don't know where the problem is?
Here is the code that I used for implementing the structure:
The "hash.h" file:
typedef struct tip_hash_nod
{
void *info;
struct tip_hash_nod *urm;
}NOD_LISTA_HASH;
typedef struct
{
NOD_LISTA_HASH *Table;
int size;
int sizeMemory;
int (*hash)(const void *obiect,const int m);
void (*distruge)(void *obiect);
}*HASH;
void initializare_hash(HASH *h,int size,int (*hash_dat)(const void *obiect,const int m),void (*distruge)(void *obiect));
int hash_insert(HASH *h,void *obiect,int sizeOfObiect);
int hash_search(HASH h,void *obiect,int (*compara)(const void *a,const void *b));
void hash_delete(HASH *h);
And the "hash.c" file:
void initializare_hash(HASH *h,int size,int (*hash_dat)(const void *obiect,const int m),void (*distruge)(void *obiect))
{
int i;
(*h) = (HASH)malloc(sizeof(HASH));
(*h)->sizeMemory = size;
if(size != 0)
{
(*h)->Table = (NOD_LISTA_HASH *)malloc((*h)->sizeMemory * sizeof(NOD_LISTA_HASH));
for(i=0;i<(*h)->sizeMemory;i++)
{
(*h)->Table[i].info = NULL;
(*h)->Table[0].urm = NULL;
}
}
else
{
(*h)->Table = (NOD_LISTA_HASH *)malloc(sizeof(NOD_LISTA_HASH));
(*h)->Table[0].info = NULL;
(*h)->Table[0].urm = NULL;
(*h)->sizeMemory = 1;
}
(*h)->size = 0;
(*h)->hash = hash_dat;
(*h)->distruge = distruge;
}
int hash_insert(HASH *h,void *obiect,int sizeOfObiect)
{
int i,poz;
NOD_LISTA_HASH *p;
if((*h)->size == (*h)->sizeMemory)
{
HASH h1;
initializare_hash(&h1,2*(*h)->sizeMemory,(*h)->hash,(*h)->distruge);
for(i=0;i<(*h)->sizeMemory;i++)
{
if((*h)->Table[i].info != NULL)
hash_insert(&h1,(*h)->Table[i].info,sizeOfObiect);
p=(*h)->Table[i].urm;
while(p!=NULL)
{
hash_insert(&h1,p->info,sizeOfObiect);
p = p->urm;
}
}
hash_delete(h);
*h=h1;
return hash_insert(h,obiect,sizeOfObiect);
}
else
{
poz = (*h)->hash(obiect,(*h)->sizeMemory);
if((*h)->Table[poz].info == NULL)
{
(*h)->Table[poz].info = malloc(sizeOfObiect);
memcpy((*h)->Table[poz].info,obiect,sizeOfObiect);
(*h)->Table[poz].urm = NULL;
(*h)->size++;
}
else
{
p = &((*h)->Table[poz]);
while(p->urm!=NULL)
p = p->urm;
p->urm = (NOD_LISTA_HASH *)malloc(sizeof(NOD_LISTA_HASH));
p = p->urm;
p->info = malloc(sizeOfObiect);
memcpy(p->info,obiect,sizeOfObiect);
p->urm = NULL;
}
return poz;
}
}
int hash_search(HASH h,void *obiect,int (*compara)(const void *a,const void *b))
{
int poz;
NOD_LISTA_HASH *p;
poz = h->hash(obiect,h->sizeMemory);
if(h->Table[poz].info == NULL)
return -1;
else
if(compara(h->Table[poz].info,obiect)==0)
return poz;
else
{
p=h->Table[poz].urm;
while(p != NULL)
{
if(compara(p->info,obiect)==0)
return poz;
p = p->urm;
}
return -1;
}
}
static void distruge_lista(NOD_LISTA_HASH *p,void (*distruge_obiect)(void *obiect))
{
if(p->urm != NULL)
distruge_lista(p->urm,distruge_obiect);
else
{
if(p->info != NULL)
distruge_obiect(p->info);
free(p);
}
}
void hash_delete(HASH *h)
{
int i;
for(i=0;i<(*h)->sizeMemory;i++)
{
if((*h)->Table[i].info != NULL && (*h)->Table[i].urm != NULL)
{
distruge_lista((*h)->Table[i].urm,(*h)->distruge);
}
}
free((*h)->Table);
*h = NULL;
}
And this is my "main.c" file:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include "hash.h"
int comparare(const void *a,const void *b)
{
return (*(int *)a - *(int *)b);
}
int hash(const void *obiect,int m)
{
return (*(int *)obiect) % m;
}
void distruge_obiect(void *obiect)
{
free((int *)obiect);
}
int main()
{
HASH h;
int val,error;
initializare_hash(&h,0,hash,distruge_obiect);
val = 20;
hash_insert(&h,&val,sizeof(int));
val = 800;
hash_insert(&h,&val,sizeof(int));
val = 2000;
hash_insert(&h,&val,sizeof(int));
val = 765;
hash_insert(&h,&val,sizeof(int));
val = 800;
error = hash_search(h,&val,comparare);
if(error == -1)
printf("Elementul %d nu se afla in hash.\n",val);
else
printf("Elementul %d se afla pe pozitia: %d.\n",val,error);
hash_delete(&h);
getch();
return 0;
}
How I already sad if I try to debug it works with no problem, but when I run it, it crashes. I can onely make an assumption that it can not dealocate the memory or something. My call stack loocks like this:
You've dropped a pretty big pile of code on us, without much to go on. I had a quick look anyway, and noticed this incorrect allocation:
(*h) = (HASH)malloc(sizeof(HASH));
HASH is a pointer type, so you are allocating only enough memory for one pointer. You want to allocate memory for the thing to which it points:
*h = malloc(sizeof(**h));
(The cast is not required in C, and some folks around here will be strident about not using one.)
That error would be entirely enough to cause all manner of bad behavior. In particular, the erroneous code might seem to work until you dynamically allocate more memory and write to that, so perhaps that explains why your tests crash on the second insertion.
My goal is to copy strings_operand_table1[i] into label. I would then like to return label to my previous function that called it. How can I fix this and what better ways are there to do this?
char GetBaseDeclarationLabel(char *strings_label_table1[], char *strings_mneumonic_table1[],
char *strings_operand_table1[], int hex_address_table1[])
{
int i = 0;
int cmp_str2 = 0;
char label[20] = {0};
//int k = 0;
//printf(" i is %s \n", strings_label_table1[1]);
for(i = 0; i < 503; i++)
{
if(strings_mneumonic_table1[i] != NULL)`enter code here`
{
cmp_str2 = strcmp(strings_mneumonic_table1[i], "BASE");
if(cmp_str2 == 0)
{
//printf(" ??please?? \n");
//printf(" hex_address_table1[i] is %x \n", hex_address_table1[i]);
strcpy(label, strings_operand_table1[i]);
//label = strings_operand_table1[i];
break;
}
}
}
return label;
}
Edit:
Is this better? If I need to use pointers it seems easier to make the function void and return nothing.
void GetBaseDeclarationLabel(char *strings_label_table1[], char *strings_mneumonic_table1[],
char *strings_operand_table1[], int hex_address_table1[], char *label1)
{
int i = 0;
int cmp_str2 = 0;
//char label[20] = {0};
//int k = 0;
//printf(" i is %s \n", strings_label_table1[1]);
for(i = 0; i < 503; i++)
{
if(strings_mneumonic_table1[i] != NULL)
{
cmp_str2 = strcmp(strings_mneumonic_table1[i], "BASE");
if(cmp_str2 == 0)
{
//printf(" ??please?? \n");
//printf(" hex_address_table1[i] is %x \n", hex_address_table1[i]);
//strcpy(label, strings_operand_table1[i]);
label1 = strings_operand_table1[i];
break;
}
}
}
//return label;
}
Change the return type of the function to a char* AND do not return the address of a local.
Either:
malloc() the memory for label:
char* label = NULL;
/*... snip ... */
if(cmp_str2 == 0)
{
label = malloc(strlen(strings_operand_table1[i]) + 1);
if (label)
{
strcpy(label, strings_operand_table1[i]);
}
break;
}
or avoid memory allocation and simply point label to the matching entry in strings_operand_table1. This is ok as the entries in strings_operand_table1 will exist beyond the scope of the function (and it is simpler for the caller to differentiate between a failed search and failed memory allocation):
char* label = NULL;
/*... snip ... */
if(cmp_str2 == 0)
{
label = strings_operand_table1[i]);
break;
}
Update function return type from char to char*
char GetBaseDeclarationLabel(char *strings_label_table1[], char *strings_mneumonic_table1[],
char *strings_operand_table1[], int hex_address_table1[])
to
char* GetBaseDeclarationLabel(char *strings_label_table1[], char *strings_mneumonic_table1[],
char *strings_operand_table1[], int hex_address_table1[])
Note:
Here you are returning pointer of local array.
See when your function returns that local array's memory will be no longer so returning that pointer is useless.
Use heap memory. Malloc for that array and return pointer of that array and after use do not forget to free it.
Hello world (hi people),
First, I'd say this is my first post, so please be clement.
As the title says, I've a heap corruption when I wants to free my object(s). I passed a couple of hours trying to fix it but I just can't see what's wrong even though I'm sure it's obvious!
So that's why I come to you.
My goal is to create some functions to (poorly) mimic some std::vector function in C. All objects are dynamically created. The implementation may be tricky due to the massive use of pointers.
I got the heap corruption when I free the vector object but I don't know if it comes from the pushBack or the destroy function.
Feel free to ask more information. Constructive comments are welcome!
Here is some piece of code:
Header content:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct _array
{
unsigned int size;
int *pData;
} tArray, *ptArray;
typedef struct _vector
{
unsigned int size;
ptArray *pData;
} tVector, *ptVector;
ptArray createArray(unsigned int size);
void destroyArray(ptArray *pArray);
ptVector createVector();
int pushBackArray(ptVector pVector, ptArray pArrayToAppend);
int popBackArray(ptVector pVector);
void destroyVector(ptVector *pVector);
Main content:
int main(char argc, char *argv[])
{
unsigned int size = 5, i;
time_t seed = NULL;
ptArray pArr = createArray(size);
ptVector pVec = createVector();
srand(seed);
for(i = 0; i < pArr->size; i++)
{
pArr->pData[i] = rand() % 9 + 1;
}
//destroyVector(&pVec); // Works at this point
pushBackArray(pVec, pArr);
destroyArray(&pArr);
destroyVector(&pVec); // Heap corruption on free pVector->pData
getchar();
return 0;
}
Body content:
ptArray createArray(unsigned int size)
{
ptArray pArray = (ptArray)calloc(1, sizeof(tArray));
if(pArray)
{
pArray->pData = (int*)malloc(size * sizeof(int));
if(pArray->pData)
pArray->size = size;
}
return pArray;
}
void destroyArray(ptArray *pArray)
{
if(pArray)
{
free((*pArray)->pData);
free((*pArray));
(*pArray) = NULL;
}
}
ptVector createVector()
{
ptVector pVector = (ptVector)calloc(1, sizeof(*pVector));
return pVector;
}
int pushBackArray(ptVector pVector, ptArray pArrayToAppend)
{
int res = 0;
if(pVector && pArrayToAppend)
{
pVector->pData = (ptArray*) realloc(pVector->pData
, sizeof(ptArray) * pVector->size + 1);
if(pVector->pData)
{
pVector->pData[pVector->size] = createArray(pArrayToAppend->size);
if(pVector->pData[pVector->size])
{
memcpy(pVector->pData[pVector->size]->pData
, pArrayToAppend->pData
, pVector->pData[pVector->size]->size * sizeof(int));
pVector->size++;
}
else
{
pVector->pData = (ptArray*) realloc(pVector->pData
, sizeof(ptArray) * pVector->size);
res = 3;
}
}
else
res = 2;
}
else
res = 1;
return res;
}
void destroyVector(ptVector *pVector)
{
if(pVector)
{
unsigned int i;
for(i = 0; i < (*pVector)->size; i++)
destroyArray( &((*pVector)->pData[i]) );
free((*pVector)->pData); // Heap Corruption throw
free(*pVector);
(*pVector) = NULL;
}
}
specifying the size is incorrect at function pushBackArray
sizeof(ptArray) * pVector->size + 1
to
sizeof(ptArray) * (pVector->size + 1)
Im trying to copy substrings from one char* to another, when I printf(%c) it shows the chars printing, but at end of add method, i use printf(%s) to print entire string and nothing is printing out. Any help is appreciated - also perhaps a better method for substrings in C than char by char?
Code below:
int aliasCount;
typedef struct Alias {
char* alias;
char* actual;
struct Alias* next;
}Alias;
Alias* aliasHead;
void addAlias(char* new);
addAlias method
void addAlias(char* new)
{
strip(new);
Alias* newAlias = (Alias*)malloc(sizeof(Alias));
//Get start-end position for alias
int start=0; int end=0; int countSpace=0;
for(int i = 0; i < strlen(new); i++)
{
//Check for space
if(new[i]==' ')
{
printf("found space %d\n",i);
countSpace++;
if(countSpace==1)
{
start=i;
}
else if(countSpace==2)
{
end=i;
break;
}
}
}
//malloc memory
newAlias->next=NULL;
newAlias->alias=(char*)malloc(sizeof(char)*(end-start));
newAlias->actual=(char*)malloc(sizeof(char)*(strlen(new)-end+1));
//Get substring,
//Copy char by char from alias to node
for(int i = 0; i < strlen(new); i++)
{
if(i>start && i<end) //Alias
{
newAlias->alias[i] = new[i];printf("'%c'",newAlias->alias[i]);
}
else if(i>end) //Actual command
{
newAlias->actual[i] = new[i];printf("'%c'",new[i]);
}
}
printf("%s\n%s\n",newAlias->alias,newAlias->actual);
if(aliasCount==0)
{
aliasHead = newAlias;
}
else
{
Alias* curr = aliasHead;
for(int i = 0; i < aliasCount; i++)
{
curr=curr->next;
}
curr->next = newAlias;
}
aliasCount++;
printf("%s\n%s\n",aliasHead->alias,aliasHead->actual);
}
Your indices are wrong; you copy the range from new[start+1] to new[end-1] into the range from alias[start+1] to alias[end-1], when you actually need to copy it into the range from alias[0] to alias[end-start-2]:
newAlias->alias[i-start-1] = new[i];printf("'%c'",newAlias->alias[i]);
and similarly (mutatis mutandis) for actual.
Learning C and having many doubts.
I have a function (lets say function 1) that calls another function (lets say function 2).
Function 2 calculates an array of string.
How can I use this array in function 1?
Some code example:
int find_errors(char* word)
{
char error[100];
/*Given the word, It will find the duplicate chars and store it in the
error array. */
return 0;
}
int find_word(char* word)
{
find_errors (word);
printf("%s\n", error);
return 0;
}
There are at least three possible approaches:
Use a global variable
pass a parameter between them
return a pointer from the function
There are multiple ways to do this.
1) Create a dynamic array and return a pointer to the array. This will require you to manually free the memory for the array at a later time.
#define NUM_ELEMS 50
// In find_error():
char* error = malloc(NUM_ELEMS * sizeof(char));
return error;
// In find_word():
char *error = find_errors();
// do stuff
free(error);
2) Pass a pointer to find_errors that it can use as the error array. This will not require you to manually free the memory.
// In find_word():
char error[NUM_ELEMS];
find_error(error);
3) Use a global array. May make it more difficult for other people to understand your code. Has other potential problems as well.
// In global scope:
char error[NUM_ELEMS];
Your question relates to "call-by-reference" and "call-by-value".
char* getNewValsToSet(void)
{
char* new_vals = (char*) malloc(sizeof(char[5]));
new_vals[4] = '\0';
return new_vals;
}
void setValuesEven(char* vals_to_set)
{
vals_to_set[0] = 'A';
vals_to_set[2] = 'C';
}
void setValuesOdd(char* vals_to_set)
{
vals_to_set[1] = 'B';
vals_to_set[3] = 'D';
}
int main(void)
{
char* some_vals_to_set = getNewValsToSet();
setValsEven(some_vals_to_set);
setValsOdd(some_vals_to_set);
// ... now has vals "ABCD"
free(some_vals_to_set); //cleanup
return 0;
}
If you have "doubts" about learning C, IMHO it's one of the best things you can do (no matter the language in which you work) because it will explain exactly how things work "under-the-hood" (which all high-level languages try to hide to some degree).
You need to declare the error array globally and use it just like you did.
EDIT: using global variables isn't the best practice in most of the cases, like this one.
Here is an example of what you are looking for with an awesome console output. It dynamically allocates the array to hold any number errors (duplicate characters in your case) that may occur.
//Only free errors if result is > 0
int find_errors(char* word, char** errors)
{
int num_errors = 0;
int word_length = strlen(word);
int ARRAY_SIZE = MIN(8, word_length);
char existing[word_length];
int existing_index = 0;
*errors = NULL;
for(int i = 0; i < word_length; i++)
{
char character = word[i];
//Search array
for (int n = 0; n < word_length; ++n ) {
if(n >= existing_index)
{
existing[n] = character;
existing_index++;
break;
}
if (existing[n] == character) {
num_errors++;
if(!*errors)
*errors = (char*)malloc(ARRAY_SIZE * sizeof(char));
//Check if we need to resize array
if(num_errors >= ARRAY_SIZE)
{
ARRAY_SIZE *= 2;
ARRAY_SIZE = MIN(ARRAY_SIZE, word_length);
char *tmp = (char*)malloc(ARRAY_SIZE * sizeof(char));
memcpy(tmp, *errors, (unsigned long)ARRAY_SIZE);
free(*errors);
*errors = tmp;
}
//Set the error character
(*errors)[num_errors - 1] = character;
break;
}
}
}
return num_errors;
}
int find_word(char* word)
{
char* errors;
int errCount = find_errors (word, &errors);
if(errCount > 0)
{
printf("Invalid Characters: ");
for(int i =0; i < errCount; i++)
{
printf("%c ", errors[i]);
}
printf("\n");
free(errors);
}
return 0;
}
int main(int argc, char *argv[])
{
find_word("YWPEIT");
find_word("Hello World");
find_word("XxxxXXxXXoooooooOOOOOOOOOOOOOOOooooooooOOOOOOOOOOOOooooooOOO");
}