calloc, malloc and dynamic struct allocation - c

I am trying to dynamically allocate an array of structures in c so that I can refer to them the same as if I had done a static declaration. I understand that calloc() does the additional step of initializing all the allocated memory to 0. But, other than that, are the 2 completely interchangeable for the following code? If I am using fread() and fwrite() to get these data structures in and out of a file, does calloc() help or hinder this?
#define MAGIC 13
struct s_myStruct {
int a[6000][400];
int b[6000][400];
int c[6000][400];
};
struct s_myStruct stuff[MAGIC];
vs
struct s_myStruct *stuff = calloc(MAGIC, sizeof(s_myStruct);
Thank you.

They're not the same. Declaring the data like this:
struct s_myStruct stuff[MAGIC];
will leave the memory uninitialized if you're declaring it in function scope (which you must be, given the second choice). Adding = {0} before the semicolon rectifies this.
The second choice, of using calloc, allocates the memory on the heap.
There's always a difference though: sizeof(stuff) will be 13 * sizeof(struct s_myStruct) in the first case, and the size of a pointer in the second case.

You really don't want to do the first one, as you'd be putting 13 * 3 * 6000 * 400 * 4 = 370MB on the stack.
But this has nothing to do with using fread and fwrite.

Related

How to free() an array of structs allocated by malloc()?

I've been working on a project that uses structs as storage for strings. I declared a struct consists of char type members:
struct datastore1
{
char name[50];
char address[50];
char email[50];
char number[50];
char idnum[50];
};
I'm aware that I can just do char *name, char *address... but let's say we specified it with max length of 50. Then on my function which uses the struct, I malloc'ed it with index size of 30:
struct datastore1 *dsdata = malloc(30 * sizeof(struct datastore1));
Supposedly I finished copying all strings into the struct by accessing each index, How should i free the allocated memory that was used after calling malloc? I tried doing free(dsdata) on the end of the program but I am not sure if it's the right way. Should i free each indexes individually? Please enlighten me. Thank you in advance for the feedback!
How should i free the allocated memory that was used after calling malloc?
Consider below example,
struct datastore1 *obj1 = malloc(sizeof(struct datastore1));
free(obj1);
Here obj1 is pointing to the block of memory of size same as size of datastore1 in order to free you need to send the address which is allocated by malloc.
likewise,
struct datastore1 *obj2 = malloc(3 * sizeof(struct datastore1));
free(obj2);
obj2 is pointing to a block of contiguous memory of size 3 * sizeof(datastore1) you need to pass the base address to free
Should i free each indexes individually?
NO, Since block of memory is allocated only once and you need to free exactly one time.
Let me extend it further,
struct datastore1 *obj3[3];
for(int i=0;i<3;i++)
obj3[i] = malloc(sizeof(struct datastore1));
for(int i=0;i<3;i++)
free(obj3[i]);
Here obj3 is array of pointer and each index is pointing to different part of memory and hence need to be freed individually.
Note: For simplicity I haven't considered return value from malloc. Null check has to be done on malloc return value.
1.
How should I free the allocated memory that was used after calling malloc?
I tried doing free(dsdata) on the end of the program but I am not sure if it's the right way.
free(dsdata) is fine, since you allocated the whole space by just one call to malloc with:
struct datastore1 *dsdata = malloc(30 * sizeof(struct datastore1));
To cite the standard (C18), 7.22.3.4 - "The malloc function" (emphasize mine):
7.22.3.4 The malloc function
Synopsis
1
#include <stdlib.h>
void* malloc(size_t size);
Description
2 The malloc function allocates space for an object whose size is specified by size and whose value is indeterminate.
Returns
3 The malloc function returns either a null pointer or a pointer to the allocated space.
It is correct to use free(dsdata) because malloc allocated all of the required space at once and returned a pointer to the first structure variable of this array which is assigned to the pointer of dsdata.
The free() function "knows" that dsdata is a reference to the whole allocated space. You do not need to free each of the 30 structures of type struct datastore1 in memory individually.
2.
Should I free each indexes individually?
No, you do not need and even more important you should not do so; this would be Undefined Behavior:
Citation from the current standard (C18), 7.22.3.5/3 - "The free function" (emphasize mine):
Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined.
As far as I understand you only used malloc to allocate space for an array of datastore1 struct, so it is sufficient to just do free(dsdata).
If in the struct you would have pointers and you would use malloc to allocate each of them, only than you would need to free each of them first.
Both answers above are correct, but to fully understand how does it work I recommend you to learn how to use valgrind.
To check if program released memory correctly use
valgrind -v --leak-check=full --track-origins=yes ./your-program
This will execute your program on valgrind's virtual processor and give you full feedback about used resources.
Basically operator [] in C programming language in array definition context causes creation of (lets say to simplify) static array - this means that array is included in size of structure (if defined as part of structure) or is stored on the stack (if defined in function or globally).
The malloc function returns address of block of data you can use. Size of this block is at least as big as you requested. When you use free you release this block wich in this case means all data in block pointed by this address will be released.

Callocing memory

I'm trying to create a file system and I need to calloc the file descriptors.
Let's say I have two structures with the following definitions:
#define DESCRIPTOR_MAX (256)
#define TABLE_MAX (32)
typedef struct S16FS S16FS_t;
typedef struct {
bitmap_t *fd_status;
size_t fd_pos[DESCRIPTOR_MAX];
inode_ptr_t fd_inode[DESCRIPTOR_MAX];
} fd_table_t;
struct FS {
back_store_t *bs;
fd_table_t fd_table;
};
I'm callocing a new file system with no problem:
FS_t *fs = (FS_t *)calloc(8, sizeof(FS_t));
but my problem arrises when I want to calloc the fd_table within the FS struct. Here's what I'm trying.
This one produces no errors:
fs->fd_table = *(fd_table_t*)calloc(TABLE_MAX, sizeof(fd_table_t));
I'm getting an error with the following:
fs->fd_table.fd_pos = (size_t *)calloc(TABLE_MAX, sizeof(size_t));
error: array type 'size_t [256]' is not assignable
Can someone explain to me what i'm doing wrong or if I'm just completely wrong in my process? Do I even need to calloc the fd_pos?
It looks like fs->fd_table.fd_pos is an array, not a pointer. If you want a dynamic array, then change the type to size_t*.
Otherwise, it's perfectly fine to leave it as an array and not use dynamic allocation. In that case, if you want to zero the memory (as calloc does), you can just use memset:
memset( fs->fd_table.fd_pos, 0, sizeof(fs->fd_table.fd_pos) );
Oh yes, and also WhozCraig points out that your first example is a leak (allocating memory, then dereferencing and copying, followed by losing the pointer). In fact, you don't need to memset as I suggested above because the entire structure was zeroed with the first calloc.

Pointer to struct containing array

I have a simple struct containing an array of ints and an index to be used for that array.
#define BUFF_SIZE 100
typedef struct _buffer Buffer;
struct _buffer {
int buff[BUFF_SIZE];
int index;
};
I am trying to write a function to create a pointer to an instance of this struct, and initialise its values to zero. However when I try to initialise the array using the arrow operator I get an error that the expression is invalid.
...
Buffer* newBuff;
newBuff->buff = {0}; //Error occurs here
...
I know that in c an array is a pointer to the base of the memory block in which the array resides, but was under the impression that dereferencing the struct pointer would allow me to access the array. Am I wrong about this, or am I missing something here? I have a feeling that it is something very simple, but for the life of me I just can't spot it.
Thanks!
EDIT: Thanks for the quick answers guys, they've helped me understand some of what is occurring. I neglected to mention that this is intended to be run on an embedded system (sorry about that), so I would like to avoid using includes or malloc if at all possible.
There are several types of confusion here. A pointer points to memory (duh), but you need to get that memory from somewhere. How you initialize that memory is separate.
You can allocate your structure on the stack by declaring a local variable inside your function:
// Initialize all buff elements and index to 0
// Note: Buffer, not Buffer*
Buffer newBuf = { {0}, 0 };
Or you can allocate it on the heap:
Buffer *newBuf = malloc(sizeof(Buffer));
memset(newBuf, 0, sizeof(Buffer));
When allocating objects on the stack, they are only valid while the current function is executing. You can't return a pointer to an object on the stack. Further, stack space is typically limited, so you can't put megabyte-sized objects there. When allocating memory on the heap with malloc(), you need to take care to free() when it is not used any more, otherwise you leak memory.
You see that when allocating objects on the stack, you are able to use an initializer-list { {0}, 0 }. In the heap case, you can not do that and you have to zero the memory manually using memset.
The problem is not with the arrow -> operator, it's with the right side of the assignment: {0} is allowed in initializers, but you cannot assign an array like that. You need to use memset to zero out the elements of the array:
memset(newBuff->buff, 0, sizeof(newBuff->buff));
Note: your code does not set the newBuf to a valid location in memory. You need to allocate memory first, like this:
newBuff->buff = malloc(sizeof(*newBuff));
I have to disagree with #dasblinkenlight, but I think the problem is that newBuff is a pointer, but it hasn't been given a value. Hence, when you dereference it, you'll probably get a crash or unpredictable results.
You'd have to have a statement that's something like:
newBuff = malloc(sizeof (Buffer));
to allocate space of the appropriate size and assign it to newBuff.
Unless I'm missing something terribly obvious...
From your question I was able to understand- you want to initialize all array elements of structure variable buff[ ] to zero.
memset() function from <string.h> file will help you to solve this problem.
As you said you are writing code for embedded system so there is no need to include whole <string.h> file in your program
I tried to replicate your program and found the following solution-
void *memset(void * , int , size_t ) __attribute__((__nonnull__(1)));
#define BUFF_SIZE 100
typedef struct _buffer Buffer;
struct _buffer {
int buff[BUFF_SIZE];
int index;
};
int main (void)
{
Buffer* newBuff;
memset(newBuff->buff, 0, BUFF_SIZE);
}
Please let me know if it was helpful.

Memory is not reallocating

I'm in the middle of a project and I'm trying to use malloc() and realloc(). I know when I malloc, it works, but when I use realloc, it doesn't change the amount of alloced memory at all. I've always though that realloc will re-allocate your already malloced memory.
Here is what I have:
This include:
#include <stdlib.h>
I have a struct:
struct student {
int age;
int numOfClasses;
int gender; //0 male; 1 female
} student;
When I want to make 7 of those structs using malloc, I will use this line of code:
student stud* = (structure*) malloc(7*sizeof(student));
This line works. That line of code takes the size of the structure and multiples that by 7. In short, this will grab enough memory to make an array of 7 structures.
Now, if I want to change that to 8, I would do this where A is the previous malloced memory, and B is the new malloced (or realloced) memory:
Here is how I have it in code:
stud = (student*)realloc(stud, 8*sizeof(student));
From what I know, realloc takes the variable in the second parameter and mallocs that amount of memory. Then, it takes the pointer (or previous malloced), and fills in the just malloced memory with as much as it can from the given pointer. Of course, the second parameter must be bigger than the previous malloced size, or stud will lose some memory on the end. Now this is where my problem is. When I call the line above, it doesn't change anything. The malloced array is still length of 7. I'm pretty sure, also, that I have enough memory to realloc.
Am I doing this right? Where could my problem be?
Your understanding of realloc's behaviour is nearly correct. It doesn't have to return a different pointer; it may be that there was enough unused memory after the initial block, so the heap manager can just return the same pointer back to you (but adjust its own internal state such that it knows the block is now bigger).
You have made one small mistake, though.
stud = (student*)realloc(stud, 8*sizeof(student));
Here you are replacing your stud pointer with the return value from realloc. If it happens to return NULL due to memory starvation, then you have lost your original stud pointer and the memory is leaked. You should use a temporary pointer instead.
tmp = realloc(stud, 8*sizeof(student));
if (tmp)
stud = tmp;
Also note that you still have to actually put something in the eighth slot. After the realloc the eighth slot is valid allocated memory, but contains garbage until you store something meaningful in it.
This should work, although I'd have these recommendations:
Don't cast the return from malloc. It's useless in C and may hide that you have forgotten to include <stdlib.h>.
Do not use ptr = realloc (ptr, ...) as this creates a memory leak in the case realloc returns NULL. Instead, use
if ((new_ptr = realloc (stud, 8 * sizeof (*stud))) != NULL) {
stud = new_ptr;
} else {
scream_and_die("out of memory");
}
And use sizeof (*stud), i.e. reference an expression using the pointer, not the type being pointed to (to be independent of the particular type of pointer you allocate). This way, when you rename the typedef, the malloc/realloc line needs no modification. In other words, Best Practice for Dynamic Memory Allocation in C is
#include <stdlib.h>
sometype *ptr;
...
ptr = malloc (N * sizeof *ptr);
for an array of N sometypes.

Cygwin malloc overrides another memory in heap

I have a strange error when try to malloc some memory. I've a pointer to a struct which is "malloced" and I want another struct. So I call malloc again and the pointer what malloc give back is point an empty space - so far it's ok. Then I memset the allocated area and the memset overrides another variable which is still in use.
The first struct in the memory is in 0x1643c98 and the given pointer to the second is 0x1643bf8 but I want to malloc 200 byte. The code:
data_t *data = get_head_data();
int length = data->head.length;
data_t *new_data = malloc(length);
memset(new_data, 0x00, length); // this line override the perivously malloced data
//some other operation
I use window xp (32 bit) and cygwin, with gcc 3.4.4. processor is intel core 2 duo.
Any idea whats wrong or what should be the problem?
Thanks in advance.
EDIT: Sorry I was a totally wrong track. There is a buggy function which is call free unexpected. When I call malloc later the the previous address is in the memory and I think it's a valid, but it was free()-ed.
Thanks all the advice!
If you need to set the newly allocated memory to 0 - use calloc. You're probably confusing pointers, sizes, and variables - check your code again.
data_t *new_data = malloc(length);
Unless sizeof(data_t) is 1, that line is likely to be an error. You are allocating length bytes. If you want an array of length data_t's, then you need to allocate sizeof(data_t)*length bytes.
A better solution would be to use calloc, as #littleadv suggests. That function takes separate arguments for number_of_items, and sizeof_item, so it's harder to get wrong.

Resources