How to malloc an array of structures [duplicate] - c

This question already has answers here:
How to find the size of an array (from a pointer pointing to the first element array)?
(17 answers)
Closed 6 years ago.
I would like to know how to malloc (and hen realloc) an array of a structure.
Here is my structure :
typedef struct tag {
char *key;
char *val;
} tag;
I use this structure in another structure :
typedef struct node {
int id;
double lat;
double lon;
int visible;
tag *tab;
} node;
I define a node *n, then:
n->tab = (tag*)malloc(sizeof(tag) * 5);
but I have an error of malloc corruption.
void remplisTag(xmlNodePtr cur, node *n) {
xmlNodePtr fils;
n->tab = malloc(sizeof(*n->tab) * 5);
if (n->tab == NULL) {
error(E_ERROR_MALLOC);
}
printf("apres malloc\n");
int taille = 5;
int ind = 0;
xmlAttrPtr attr1, attr2;
xmlChar *key;
xmlChar *value;
fils = cur->xmlChildrenNode;
fils = fils->next;
while (xmlStrcmp(fils->name, (const xmlChar*)"text") != 0) {
if (xmlStrcmp(fils->name, (const xmlChar*)"tag") == 0) {
if (ind == taille - 1) {
n->tab = realloc(n->tab, sizeof(tag) * (taille + 5));
taille = taille + 5;
} else {
taille = taille;
}
/* searching for key */
attr1 = xmlHasProp(fils, (const xmlChar*)"k");
if (attr1 == NULL) {
error(E_KEY);
} else {
key = xmlGetProp(fils, (const xmlChar*)"k");
if (key == NULL) {
error(E_KEY_V);
}
/* searching for value */
attr2 = xmlHasProp(fils, (const xmlChar*)"v");
if (attr2 == NULL) {
error(E_VALUE);
}
value = xmlGetProp(fils, (const xmlChar*)"v");
if (value == NULL) {
error(E_VALUE_V);
}
tag t;
t.key = malloc(sizeof((char*)key));
strcpy(t.key, (char*)key);
strcpy(t.val, (char*)value);
t.val = malloc(sizeof((char*)value));
n->tab[ind++] = t;
}
}
fils = fils->next;
}
free(n->tab);
}
In main:
node *n = malloc(sizeof(node));
xmlNodePtr cur;
in a while loop:
remplisTag(cur, n);

There is a memory allocation issue in the following lines
tag t;
t.key = malloc(sizeof((char*)key));
strcpy(t.key, (char*)key);
strcpy(t.val, (char*)value);
t.val = malloc(sizeof((char*)value));
The memory in C is very fiddly - when you allocate memory, you need to hold enough to store the data.
tag t;
t.key = malloc(sizeof((char*)key));
strcpy(t.key, (char*)key);
Creates enough for a pointer -which is probably not enough.
The fix is something like.
tag t;
t.key = strdup( key );
t.val = strdup( value );
The strdup function combines the malloc (of the correct size) and the strcpy.

There is no visible problem in your allocation statement, some people prefer that malloc() return value not be cast to the destination type, and it is slightly more reliable to use the type of the destination pointer to avoid type mismatches that would be hard to detect:
n->tab = malloc(sizeof(*n->tab) * 5);
What is the precise error message you get?
Is it a runtime error?
How did you allocate the node structure that n points to?
Can you post the full code to the function that produces this failure?
A runtime message from malloc() is an indication that the memory allocation structures used internally by malloc have been corrupted. It would indicate that the problem is elsewhere, probably a buffer overrun in another object allocated by malloc(). Check the code that was executed since the previous call to malloc().
EDIT:
In the code posted, there are some allocation errors:
t.key = malloc(sizeof((char*)key));
strcpy(t.key, (char*)key);
strcpy(t.val, (char*)value);
t.val = malloc(sizeof((char*)value));
The space you allocate is just the size of a pointer char*, not the length of the string plus 1 for the final null terminator. If key is longer than 3 or 7 bytes, depending on the architecture, you have a buffer overrun.
t.val is allocated after you copy contents to it. Undefined behavior!
You should simplify this with strdup():
t.key = strdup((char*)key);
t.val = strdup((char*)value);
Your test for reallocation is too conservative: the array should be reallocated when ind == taille:
if (ind == taille) {
n->tab = realloc(n->tab, sizeof(*n->tab) * (taille + 5));
taille += 5;
}
taille and ind should be stored into the node to keep track of how much space has been allocated and how many tags are present. The current code does not provide this information to the caller, the rest of the tag array is uninitialized, there is no way to tell, undefined behavior is lurking.
Note that there are too many casts in your code. Casts prevent some type mismatch detection by the compiler, it is wise to change the argument types for your functions to avoid unnecessary casts.
For example: libxml2 defines xmlChar as a typedef for unsigned char. This is a very bad design decision. They should use char and handle the strings correctly regardless of whether char happens to be signed or unsigned on the current environment. This choice forces programmers to cast most arguments to the xmlXXX APIs, making the code ugly and error prone. You cannot change that, but you could use inline functions to convert between char* and xmlChar* to keep casts to a minimum.

Related

How to solve an Invalid write/read of size 8 involving a void pointer in C

I am currently working on a hash table for a project and I am having some trouble with the memory cleanup. I am using Valgrind and I am getting this error response.
==1409499== Invalid write of size 8
==1409499== at 0x4014F9: symtabInstall (symtab.c:106)
==1409499== by 0x4011D0: main (test1.c:17)
==1409499== Address 0x4a47128 is 0 bytes after a block of size 8 alloc'd
==1409499== at 0x484086F: malloc (vg_replace_malloc.c:381)
==1409499== by 0x4014B0: symtabInstall (symtab.c:102)
==1409499== by 0x4011D0: main (test1.c:17)
int symtabInstall(void *symtabHandle, const char *symbol, void *data){
// Install a (symbol, data) pair in the table.
// If the symbol is already installed in the table, then the data is
// overwritten.
// If the symbol is not already installed, then space is allocated and
// a copy is made of the symbol, and the (symbol, data) pair is then
// installed in the table.
// If successful, returns 1.
// If memory cannot be allocated for a new symbol, then returns 0.
// Note that no validation is made of the symbol table handle passed
// in. If not a valid handle, then the behavior is undefined (but
// probably bad).
sym_t *symtable = symtabHandle;
signed int location = search(symbol, symtable);
if (location != -1)
symtable->entries[location]->data = data;
///Create the input pair
values *input = malloc(sizeof(input) * 1);
if (input == NULL)
return 0;
input->symbol = malloc(strlen(symbol) + 1);
input->data = data; /// This is the Line -------------------
strcpy(input->symbol, symbol);
///Find spot to put in
int symh = hash(symbol, symtable);
///Input check
if (symtable->entries[symh] == NULL){
symtable->entries[symh] = input;
} else {
int i = symh + 1;
int c = 0;
while(i < symtable->size){
if (i == symtable->size && c == 0){
c = 1;
} else if (c == 1){
return 0;
}
i %= symtable->size;
if (symtable->entries[i] != NULL){
symtable->entries[symh] = input;
symtable->entries[symh]->data = data;
}
i++;
}
}
return 1;
}
For context, input is one of the buckets for the hash table and has two pointers symbol and data. Data is the one giving me the issue as I need to allocate memory for it.
Here are the structs for both.
typedef struct values {
char *symbol;
void *data;
struct values *next;
} values;
typedef struct{
values **entries;
int size;
} sym_t;
I am also given no knowledge of the data type for data.
It seems the problem is this memory allocation
values *input = malloc(sizeof(input) * 1);
I think you mean
values *input = malloc(sizeof( *input) * 1);
or
values *input = malloc(sizeof(values) * 1);
Pay attention to that using the multi[plier 1 does not make a great sense.:)
Also you forgot to initialize the data member next of the allocated object of the type values.
And the body of this while loop
while(i < symtable->size){
if (i == symtable->size && c == 0){
// ...
also does not make a great sense because the condition in the following if statement
i == symtable->size
never can evaluate to true.

Passing pointer to pointer for reallocation in function

I'm a beginner C programmer and have issues implementing an (ordered) dynamic array of structs.
Before adding an element to the array, I want to check if it is full and double it's size in that case:
void insert_translation(dict_entry **dict, char *word, char *translation){
if( dictionary_entries == dictionary_size ){
dict_entry *temp_dict;
temp_dict = realloc(&dict, (dictionary_size *= 2) * sizeof(dict_entry) );
// printf("Increased dict size to %d\n", dictionary_size);
// if(temp_dict == NULL){
// fprintf(stderr, "Out of memory during realloc()!\n");
// /*free(dict);
// exit(EXIT_OUT_OF_MEMORY);*/
// }
//free(dict);
//*dict = temp_dict;
}
dictionary_entries++;
printf("Inserted %s into dict - %d of %d filled.\n", word, dictionary_entries, dictionary_size);
}
I call the function from the main function like this:
dictionary_size = 2; //number of initial key-value pairs (translations)
dictionary_entries = 0;
dict_entry *dictionary = malloc(dictionary_size * sizeof(dict_entry));
[...]
insert_translation(&dictionary, "bla", "blub");
In my understanding, dictionary is a pointer to a space in memory. &dictionary is a pointer to the pointer, which I pass to the function. In the function, dict is said pointer to pointer, so &dict should be the pointer to the area in memory? However, when I try to compile, I get the following error message:
pointer being realloc'd was not allocated
Edit
I expanded the code sample to show more of the code in the main function.
The problem is in this statement
temp_dict = realloc(&dict, (dictionary_size *= 2) * sizeof(dict_entry) );
The parameter dict has the type
dict_entry **dict
in the statement that reallocs the memory you have to use the value of the pointer *dic but you are uisng an expression &dict that has the type dict_entry ***.
Compare the type of the left side of the assignment
ict_entry *temp_dict
with the type of the reallocated pointer. They should be the same (except in C one of them can have the type void *)
So you need to write
temp_dict = realloc(*dict, (dictionary_size *= 2) * sizeof(dict_entry) );
^^^^^
In C arguments are passed by value. If you want to change the original value of an argument you should to pass it by reference through a pointer to the argument. In the function you need to dereference the pointer that to change the object pointed to by the pointer.
&dict -> *dict. You can simplify the code by using a return type, to avoid such bugs:
dict_entry* insert_translation(dict_entry* dict, char *word, char *translation)
{
...
if( dictionary_entries == dictionary_size )
{
dictionary_size *= 2;
dict_entry *tmp = realloc(dict, sizeof(dict_entry[dictionary_size]));
if(tmp == NULL)
{
// error handling, free(dict) etc
}
else
{
dict = tmp;
}
}
...
return dict;
}

Abort trap 6 malloc

I am trying to make an implementation of an n-ary tree in C. When running it I get the following error:
sibling(1143,0x7fff7e925000) malloc: *** error for object 0x7f946b4032c8: incorrect checksum for freed object - object was probably modified after being freed.
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6
I am unsure what is causing the error. As it says it seems that I am writing to an object that was freed. But in my code I do not free any of the memory allocated. I am new to c to this confused me very much. I tried debugging with gdb and it says the error is caused by the printTree(); call in main where I am recursively trying to print the tree. Hope you can help me understand the issue :-).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *name;
unsigned int utility;
unsigned int probability;
} Child;
typedef struct {
unsigned int level;
unsigned int player;
unsigned int nChildren;
Child *children;
} Data;
typedef struct sNaryNode{
Data *data;
struct sNaryNode *kid;
struct sNaryNode *sibling;
} NaryNode;
NaryNode* createNode(Data data){
NaryNode *newNaryNode = malloc(sizeof (NaryNode*));
newNaryNode->sibling = NULL;
newNaryNode->kid = NULL;
newNaryNode->data = &data;
return newNaryNode;
}
NaryNode* addSibling(NaryNode* n, Data data){
if(n == NULL) return NULL;
while(n->sibling)
n = n->sibling;
return (n->sibling = createNode(data));
}
NaryNode* addChild(NaryNode* n, Data data){
if(n == NULL) return NULL;
else if(n->kid)
return addSibling(n->kid, data);
else
return (n->kid = createNode(data));
}
void printTree(NaryNode* n) {
if(n == NULL) return;
if(n->sibling) {
printf("%u %u %u %u %u %s", n->data->level, n->data->player, n->data->nChildren, n->data->children[0].probability, n->data->children[0].utility, n->data->children[0].name);
printTree(n->sibling);
}
else if(n->kid) {
printf("%u %u %u %u %u %s", n->data->level, n->data->player, n->data->nChildren, n->data->children[0].probability, n->data->children[0].utility, n->data->children[0].name);
printTree(n->kid);
}
else {
printf("The tree was printed\n");
}
}
int main(void) {
NaryNode *root = calloc(1, sizeof(NaryNode));
Data data;
data.level = 1;
data.player = 1;
data.nChildren = 2;
data.children = calloc(data.nChildren, sizeof data.nChildren);
data.children[0].probability = 50;
data.children[0].utility = 1;
data.children[0].name = "Kom med det første tilbud (anchor)";
data.children[1].probability = 50;
data.children[1].utility = 1;
data.children[1].name = "Afvent modspilleren kommer med første tilbud";
*root = *createNode(data);
int i = 0;
for(i=0; i<root->data->nChildren; i++) {
addChild(root, data);
}
printTree(root);
}
There are various errors in your code.
Allocating an incorrectly sized memory block :
data.children = calloc(data.nChildren, sizeof data.nChildren);
data.children is an array of Child structures, yet you're allocating structures whose size is equal to sizeof(unsigned int), due to data.nChildren being an unsigned int.
Taking the address of a temporary variable and storing it for later usage :
NaryNode* createNode(Data data){
newNaryNode->data = &data;
}
data in createNode only exists for as long as the function is running : in this case, you're taking the address of the local variable data and storing it in the structure that you're returning for later usage. This is a very bad idea, since this pointer will refer to an object that doesn't exist anymore after the function returns.
Keep in mind that you don't need to pass a copy of the Data object into createNode in your current code, since there is really only one Data object in the whole program. Thus, you can change the prototype of createNode to createNode(Data* data), and pass the address of the Data structure that you create in main. Doing anything more involved than that, though, would require deep-copying the structure, I think.
Incorrectly managing the objects' lifetime.
NaryNode *root = calloc(1, sizeof(NaryNode));
*root = *createNode(data);
createNode returns an NaryNode*. However, you never actually assign it to an NaryNode* so that you can free it later. Instead, the pointer to the object that the function returns is known only during the *root = *createNode(data) invocation, and irrevocably lost later on. You do, however, retain the contents of the object due to dereferencing it and copying it into root : the object itself, however, as returned from createNode, is lost and not recoverable, unless pointers to it still exist in the tree.
Here is another problem. This line does not allocate space for a NaryNode, but only for a pointer to a NaryNode:
NaryNode *newNaryNode = malloc(sizeof (NaryNode*));

how to use a static struc into a static function ? ( like a global )

for the need of my project i need to handle a global (representing the heap ). It's a C project, i don't have any errors at the compilation.
but when i try to use a member of struct -> segfault.
if someone could tell me where is the point ?
thanks
static t_meta *init_get_meta()
{
static t_meta *allineed = NULL;
int i;
i = 0;
if (allineed == NULL)
{
//allineed->pagesize = getpagesize();
//allineed->pagesize = 4096;
allineed->pagesize = 0; --> segfault right here
printf("LOVE\n");
while (i < 8)
{
allineed->listfree[i++] = NULL;
}
allineed->last = extend_heap(allineed);
}
return (allineed);
}
You are de-referencing a NULL pointer.
Here in this line of code you check for NULL and go ahead and access that memory which is illegal.
if (allineed == NULL)
allineed->pagesize = 0; // incorrect at this time allineed is pointing to 0x0
What you need to do is malloc the structure and than check if malloc returned with not a NULL value. something on the lines of
static t_meta *allineed = malloc(sizeof(t_meta));
if (allineed)
{
//do something
}
else
//return error
You might want to look at these questions if you are trying to implement a basic malloc yourself
How do malloc() and free() work?
How is malloc() implemented internally?
A very basic malloc would do these basic steps
void * my_malloc(size_t size)
{
size_t headersize = 1; // 1 byte header
uint8_t alignment = 8; // 8 byte alignment
// the block should be 8 bytes align
size_t alloc_size = ((size+1)+(alignment-1))&~(alignment-1);
//use system call
void *head = sbrk(alloc_size );
if(head == (void *)(-1))
return NULL;
//update the header here to mark the size and other bits depending upon req
char *header_val = (char *)head;
*header_val = (alloc_size/2) | ( 1 << 7);//only support power 2 sizes
//return updated pointer location to point to ahead of header
// after changing the pointer to char type as pointer arithmetic is not allowed on void pointers
//printf("allocated size is %d with first byte %p\n",alloc_size,header_val);
//printf(" %02x\n",(unsigned char)*(char *)header_val);
return (char *)head + headersize;
}

Strange behaviour on Realloc: invalid next size [duplicate]

This question already has an answer here:
free char*: invalid next size (fast) [duplicate]
(1 answer)
Closed 8 years ago.
I know there are tons of other realloc questions and answers and I have read almost all of them, but I still couldn't manage to fix my problem.
I decided to stop trying when I accidentaly discovered a very strange behaviour of my code.
I introduced a line to try something, but although I don't use the value of newElems in main, the line changes the behaviour.
When the line is commented, the code fails at first realloc. Including the line, the first realloc works. (it still crashes on the second one).
Any ideas on what might be happening?
int main(int argc, char** argv) {
Pqueue q = pqueue_new(3);
Node a = {.name = "a"}, b = {.name = "b"},
c = {.name = "c"}, d = {.name = "d"};
push(& q, & a, 3);
// the next one is the strange line: as you can see, it doesn't modify q
// but commenting it out produces different behaviour
Pqueue_elem* newElems = realloc(q.elems, 4 * q.capacity * sizeof *newElems);
push(& q, & b, 5);
push(& q, & c, 4);
char s[5];
Node* n;
for (int i = 1; i <= 65; ++i) {
sprintf(s, "%d", i);
n = malloc(sizeof *n);
n->name = strdup(s);
push(& q, n, i);
}
Node* current = NULL;
while ((current = pop(& q))) {
printf("%s ", current->name);
}
return 0;
}
and the push function:
void push(Pqueue* q, Node* item, int priority) {
if (q->size >= q->capacity) {
if (DEBUG)
fprintf(stderr, "Reallocating bigger queue from capacity %d\n",
q->capacity);
q->capacity *= 2;
Pqueue_elem* newElems = realloc(q->elems,
q->capacity * sizeof *newElems);
check(newElems, "a bigger elems array");
q->elems = newElems;
}
// append at the end, then find its correct place and move it there
int idx = ++q->size, p;
while ((p = PARENT(idx)) && priority > q->elems[p].priority) {
q->elems[idx] = q->elems[p];
idx = p;
}
// after exiting the while, idx is at the right place for the element
q->elems[idx].data = item;
q->elems[idx].priority = priority;
}
The pqueue_new function:
Pqueue pqueue_new(unsigned int size) {
if (size < 4)
size = 4;
Pqueue* q = malloc(sizeof *q);
check(q, "a new queue.");
q->capacity = size;
q->elems = malloc(q->capacity * sizeof *(q->elems));
check(q->elems, "queue's elements");
return *q;
}
realloc will change the amount of memory that is allocated, if needed. It is also free to move the data to another place in memory if that's more efficient (avoiding memory fragmentation).
The function, then, returns a new pointer to the new location in memory where your data is hiding. You're calling realloc, and allocating (probably) four times as much memory as before, so it's very likely that that allocated memory is situated elsewhere in memory.
In your comment, you said realloc works like free + malloc. Well, in some cases it can behave similarly, however: realloc and free are different functions, that do different tasks. Both are functions that manage the dynamic memory, so yes, obviously there are similarities, and in the case of realloc, sometimes they can seem to be doing the same thing, however: As I explained here, realloc and free are fundamentally different functions
However, by not assigning the return value of realloc to q.elems, you're left with a pointer to a memory address that is no longer valid. The rest of your program can, and probably does, exhibit signs of undefined behaviour, then.
Unless you show some more code, I suspect this will take care of the problem:
//change:
Pqueue_elem* newElems = realloc(q.elems, 4 * q.capacity * sizeof *newElems);
//to
q.elems = realloc(q.elems, 4 * q.capacity * sizeof *newElems);
Or better yet, check for NULL pointers:
Pqueue_elem* newElems = realloc(q.elems, 4 * q.capacity * sizeof *newElems);
if (newElems == NULL)
exit( EXIT_FAILURE );// + fprintf(stderr, "Fatal error...");
q.elems = newElems;//<-- assign new pointer!
Looking at your pqueue_new function, I would suggest a different approach. Have it return the pointer to Pqueue. You're working with a piece of dynamic memory, treat it accordingly, and have your code reflect that all the way through:
Pqueue * pqueue_new(size_t size)
{//size_t makes more sense
if (size < 4)
size = 4;
Pqueue* q = malloc(sizeof *q);
check(q, "a new queue.");
q->capacity = size;
q->elems = malloc(q->capacity * sizeof *(q->elems));
check(q->elems, "queue's elements");
return q;
}
Alternatively, pass the function a pointer to a stack variable:
void pqueue_new(Pqueue *q, size_t size)
{
if (q == NULL)
{
fprintf(stderr, "pqueue_new does not do NULL pointers, I'm not Chuck Norris");
return;//or exit
}
if (size < 4)
size = 4;
check(q, "a new queue.");
q->capacity = size;
q->elems = malloc(q->capacity * sizeof *(q->elems));
check(q->elems, "queue's elements");
}
//call like so:
int main ( void )
{
Pqueue q;
pqueue_new(&q, 3);
}
Those would be the more common approaches.
Thank you all for the suggestions! I wouldn't have solved it without them,
The strange behaviour was caused by an off by one error. I was reallocating the queue only when q->size >= q->capacity, but since q was indexed from 0, it meant that before realloc I was writing in a forbidden location (q->elems[q->size]), which messed everything up.

Resources