Clarification on freeing memory in C - c

I'm trying to free all my memory, and I'm not sure if I'm doing it properly for a struct*. A snippet of my code:
struct words { char word[40]; };
int main() {
struct words* aList = malloc(2*sizeof(struct words));
// A text file is opened and each word is stored in a struct. I use an int variable to count how many times I've stored a word.//
if(n >= 2*sizeof(struct words) {
n = n*2;
aList = realloc(n*sizeof(struct words));
//Once my program is done, at the end of my main.//
free(aList);
From my understanding of C (I've only been using it for about 2 months), I've created an array of struct pointers at the start. Then I'm dynamically increasing the size of the array with realloc. When I free aList from memory, does it only free the addresses stored in aList?

void* ptr = malloc(512);
This provides you with a block of memory which contains 512 bytes of data. That doesn't mean the block is 512 bytes big, it means that it contains 512 bytes or more.
Typically, each block has a small prefix which is used by the allocator.
struct MemoryBlock {
size_t howBigWasIt;
char data[0]; // no actual size, just gives us a way to find the position after the size.
};
void* alloc(size_t size) {
MemoryPool* pool = getMemoryPool(size);
MemoryBlock* block = getFirstPoolEntry(pool);
block->howBigWasIt = size;
return &block->data[0];
}
static MemoryBlock blockForMeasuringOffset;
void free(void* allocation) {
MemoryBlock* block = (MemoryBlock*)((char*)allocation) - sizeof(MemoryBlock));
MemoryPool* pool = getMemoryPool(block->howBigWasIt);
pushBlockOntoPool(pool, block);
}
Then understand that realloc is implemented by allocating a new block for the new size, copying the data over and releasing the old allocation.
So you can't release sub-allocations of an allocation:
int* mem = malloc(4 * sizeof(int));
free(int + 3); // invalid
HOWEVER.
int i = 0;
int** mem = malloc(4 * sizeof(int*));
mem[0] = malloc(64);
mem[1] = alloca(22); // NOTE: alloca - this is on the stack.
mem[2] = malloc(32);
mem[3] = &i; // NOTE: pointer to a non-allocated variable.
You are responsible for free()ing each of the allocations here.
// mem[3] was NOT an malloc
free(mem[2]);
// mem[1] was NOT an malloc
free(mem[0]);
free(mem);
but this is a matter of matching allocations to frees.

Related

memory allocation in structures

My code uses two structures, block and layout (which is a collection of an arbitrary number of blocks).
struct block{
char type;
unsigned short int loc;
unsigned short int size[2];
};
struct layout{
unsigned short int no;
struct block *blocks;
short int **moves;
};
I am using this function to quickly initialize (and partly fill) the structure layout, based a set of blocks:
struct layout init_layout(int block_no, struct block *blocks){
struct layout new_layout;
int i, j;
new_layout.no = (unsigned short int)block_no;
// the following two lines cause an memory corruption error
new_layout.blocks = (struct block *)malloc(block_no);
new_layout.moves = (short int **)malloc(block_no);
for(i = 0; i < block_no; i++){
new_layout.blocks[i] = blocks[i];
new_layout.moves[i] = (short int *)malloc(2);
for(j = 0; j < 2; j++)
new_layout.moves[i][j] = 0;
}
return new_layout;
}
So far, I do not see, that there is something wrong with it. However, when I call function like this
int main(int argc, char** argv){
// just some arbitrary values for 10 blocks
int size[2] = {2, 2};
struct block *blocks = (struct block *)malloc(10);
for(length = 0; length < 10; length++){
blocks[length] = init_block('R', 1, size);
}
struct layout puzzle;
puzzle = init_layout(10, blocks);
return 0;
}
I end up with an memory corruption error, as marked by the comment in init_layout().
What do I miss in my implementation?
When you are allocating memory for anything, you need to analyze, closely -- "What is it that I'm allocating memory for?"
Below, you incorrectly assume a cast of an arbitrary number block_no will adequately size the memory needed for both new_layout.blocks and new_layout.moves -- it won't:
new_layout.blocks = (struct block *)malloc(block_no);
new_layout.moves = (short int **)malloc(block_no);
What you are allocating for new_layout.blocks is actually space for struct block *blocks; (a pointer-to-struct-block), while you can malloc (block_no * sizeof (struct block)); to allocate space for block_no struct block, it is far better to allocate based upon what you are creating (i.e. space for an array new_layout.blocks (again a pointer-to-struct-block) which needs block_no * sizeof *new_layout.blocks bytes of memory to hold block_no of type struct block, e.g.:
new_layout.blocks = malloc(sizeof *new_layout.blocks * block_no);
new_layout.moves = malloc(sizeof *new_layout.moves * block_no);
(simply dereferencing the object you are allocating an array of, will accurate allow you to use sizeof to get the object (element) size for the array. (e.g. sizeof *new_layout.blocks) which you multiply by how many you need (e.g. sizeof *new_layout.blocks * block_no)
The same applies to:
new_layout.moves[i] = malloc(**new_layout.moves * 2);
(note: here you are allocating for 2 shorts, so you will need to dereference you pointer-to-pointer-to-short twice to be allocating for sizeof (short))
See Also: Do I cast the result of malloc? for thorough explanation.
For starters, this
new_layout.blocks = (struct block *)malloc(block_no);
should be
new_layout.blocks = malloc(block_no * sizeof *new_layout.blocks);
For the moves this is a bit more complicated.
Assuming short int **moves; should reference a certain number of int[2] the declaration is not optimal and better should be:
short int (*moves)[2]; /* Define a pointer to
an array with two elements of type short int. */
And allocation then should look like this:
new_layout.moves = malloc(block_no * sizeof *new_layout.moves);
Finally initialisation goes like this:
for(i = 0; i < block_no; i++){
new_layout.blocks[i] = blocks[i];
for(j = 0; j < sizeof new_layout.moves[0]/sizeof new_layout.moves[0][0]; j++)
new_layout.moves[i][j] = 0;
}
You might have noticed:
No memory allocation in the loop any more.
The magic number 2 only appears once.
:-)

how to correctly free a struct? ANSI C

How does one correctly free a structure? If I have is this right? Or just called free once is correct?
typedef struct AStruct{
char * buffer;
int size;
} AStruct;
typedef struct S_Session {
int Id;
AStruct* buff;
char * name;
} S_Session;
S_Session* S_Session_new() {
S_Session* s = (S_Session*)malloc(sizeof(S_Session));
s->Id = 1;
s->buff = (AStruct*)malloc(sizeof(AStruct));
s->buff->buffer = malloc(8196);
s->buff->size = 8196;
s->name = malloc(100);
return s;
}
int main(int argc, char *argv[])
{
S_Session* sess = S_Session_new();
free(sess->buff->buffer);
free(sess->buff);
free(sess->name);
free(sess);
}
The rule like others have already said is to free everything you allocate, so from your code, you have 4 malloc's and you call free for those mallocs when the programs ends, which is correct.
In C nothing is automatic, so if you decided to call free only over your allocated struct, the remaining memory that you allocated would not been freed.
But for just a simple program, after the program ends the process is killed and the memory is freed by the Operating System, so it would be the end of the world if your release just the struct.
As a good practice you should free all the allocate memory by your program before it's termination.
In C, you should not cast the return value of malloc(). It can mask an error in the case that the prototype is missing, and the worst case result of using that value may be a crash.
In general, you should check the validity of a function call result before acting upon it. In this case, checking to see if malloc() actually succeeds will avoid a likely unintended crash in the case the system ran out of memory.
Since you can calculate exactly how much memory you need, you can implement your S_Session_new() to perform a single allocation of all the memory you need, and set the pointers to the right places within that memory. Doing so allows you to release that memory with a single call to free().
S_Session* S_Session_new() {
char *mem;
S_Session* s = 0;
size_t sz = 0;
sz += sizeof(S_Session);
sz += sizeof(AStruct);
sz += 8196;
sz += 100;
mem = malloc(sz);
if (mem) {
s = (void *)mem;
s->Id = 1;
s->buff = (void *)(mem += sizeof(S_Session));
s->buff->buffer = (void *)(mem += sizeof(AStruct));
s->buff->size = 8196;
s->name = (void *)(mem += 8196);
}
return s;
}

Implementation of Realloc in C

int getmin(int a, int b)
{
return a<b?a:b;
}
void *reallocation(void *ptr, size_t size) //size_t in bytes
{
void *newptr;
int msize;
msize = getsize(ptr);
msize = getmin(msize, size);
printf("msize = %d", msize);
newptr = malloc(size);
newptr = memcpy(newptr, ptr, msize);
free(ptr);
return newptr;
}
I have implemented my own realloc, and in order to get the size of the allocated memory using malloc(however i know there isn't any method for this in c).
My reallocation function is working fine on my system
How do we get the size of the memory allocated by malloc().
Also can we do inplace reallocation if the size of the previously allocated memory is greater than the new required?
There is no portable way to get the size of memory allocated by malloc().
However, one can always do something like that to simulate what you want.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void myfree(void * p) {
size_t * in = p;
if (in) {
--in; free(in);
}
}
void * mymalloc(size_t n) {
size_t * result = malloc(n + sizeof(size_t));
if (result) { *result = n; ++result; memset(result,0,n); }
return result;
}
size_t getsize(void * p) {
size_t * in = p;
if (in) { --in; return *in; }
return -1;
}
#define malloc(_x) mymalloc((_x))
#define free(_x) myfree((_x))
void *reallocation(void *ptr,size_t size) {
void *newptr;
int msize;
msize = getsize(ptr);
printf("msize=%d\n", msize);
if (size <= msize)
return ptr;
newptr = malloc(size);
memcpy(newptr, ptr, msize);
free(ptr);
return newptr;
}
int main() {
char * aa = malloc(50);
char * bb ;
printf("aa size is %d\n",getsize(aa));
strcpy(aa,"my cookie");
bb = reallocation(aa,100);
printf("bb size is %d\n",getsize(bb));
printf("<%s>\n",bb);
free(bb);
}
malloc does not initialize memory to zero. (calloc is the equivalent that does.) If you are seeing things set to zero, it's accidental.
I believe the library version of realloc uses length information in the heap that is not directly available. (And it may overestimate the original allocation, which means it might copy a little extra memory when using realloc to expand the allocation. This generally has no effect.)
realloc likely doesn't do a copy when shrinking an allocation.
Also, I should note that in same cases, you don't have to do a copy even when realloc increases the size, for example, if the next block in the heap is free.
the memory allocated by malloc gets initialized to zero, so i am checking for that condition.
That's incorrect. From the draft:
Description
2 The malloc function allocates space for an object whose
size is specified by size and whose value is indeterminate.
Your getsize needs to be fixed.
My reallocation function is working fine.
You are not even fixing the alignment -- it may fail for certain types. Read this SO question.
Also can we do inplace reallocation if the size of the previously allocated memory is greater than the new required?
What would in-place reallocation mean? Shouldn't this be a simple no-op?

How to track malloc and free? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Simple C implementation to track memory malloc/free?
I need to know how much memory I have used till now in a C program and here is the pseudo code
#include <stdio.h>
int usedMemory =0;
void *MyMalloc(int size){
usedMemory = usedMemory +size ;
return malloc(size);
}
void MyFree(void *pointer){
/*****************what should i write here????*************/
}
int main(int argc, char *argv[])
{
char *temp1= (char *)MyMalloc(100);
char *temp2= (char *)MyMalloc(100);
/*......other operations.........*/
MyFree(temp1);
MyFree(temp2);
return 0;
}
Can anyone tell me what to write in the MyFree method(which decrements the amount of memory freed from usedMemory.
You could allocate few extra bytes more than asked, and store the size in the extra bytes, so that you could know the size later on, in MyFree function, with little calculation as:
unsigned long int usedMemory = 0;
void *MyMalloc(int size)
{
char *buffer = (char *) malloc(size + sizeof(int)); //allocate sizeof(int) extra bytes
if ( buffer == NULL)
return NULL; // no memory!
usedMemory += size ;
int *sizeBox = (int*)buffer;
*sizeBox = size; //store the size in first sizeof(int) bytes!
return buffer + sizeof(int); //return buffer after sizeof(int) bytes!
}
void MyFree(void *pointer)
{
if (pointer == NULL)
return; //no free
char *buffer = (char*)pointer - sizeof(int); //get the start of the buffer
int *sizeBox = (int*)buffer;
usedMemory -= *sizeBox;
free(buffer);
}
In C++, you could keep a global std::map<void*, std::size_t> around to track the size of each allocated block; your own allocator function would register the size when allocating, and the deallocation function would remove the entry. (Update: Or do as the linked question suggests and allocate a bit more memory and save the size there.)
The more fundamental problem is that this will probably only be of very limited use in a typical C++ program: Allocations there are done predominantly in two ways: 1) through explicit new expressions, which call ::operator new(), which in turn (usually) calls malloc(), and 2) through std::allocator<T>::allocate(), which on many platforms is implemented in terms of ::operator new().
The problem is that you don't have control over the specifics of your platform. You can replace the global operator-new to use your own MyMalloc(), but the default std::allocator might use malloc() directly and thus not be affected by that.
A cleaner approach for debugging purposes is to use an external tool like valgrind to track heap usage. For permanent internal use, tracking the allocation sizes is going to cause a significant performance hit, too.
You could allocate memory and store its size in the allocated block (error checking omitted for brevity):
unsigned int totalAlloc = 0;
void *MyAlloc(unsigned int size)
{
void *p;
totalAlloc += size;
p = malloc(size + sizeof(int));
*(int *) p = size;
return (void *)(((int *) p) + 1)
}
void MyFree(void *ptr)
{
ptr = (void *)(((int *) ptr) -1 );
totalAlloc -= * (int *) ptr;
free(ptr);
}
This code actually reserves more memory than requested in order to store the block's size in the (usually) first four bytes. This information can then be retrieved later on when you free the memory.
You need to manage a list of all malloc() you have done with pointer + size. Then you can search for the size in that list, and decrement it in free().
Check for example in that example how they are doing:
http://developers.sun.com/solaris/articles/lib_interposers_code.html#malloc_interposer.c
You might have other possibilities to track memory, like:
Valgrind with massif tool for tracking memory usage over time. You can even generate png output graphics
Interposed libraries. You can found some libraries that you can use by LD_PRELOAD=thelib.so ./yourprogram, and they will output some statistics like jemalloc
(A side note, please accept some answers to your question !)
you could try something like this... i'd strongly recommend to use this only for debugging purpose!
#define MAXMEMBLOCKS 10000
typedef struct {
int size;
void* ptr;
} memblock;
typedef struct {
int totalSize;
int current;
memblock memblocks[MAXMEMBLOCKS];
} currentMemory;
currentMemory mem;
void *MyMalloc(int size) {
if (mem.current < MAXMEMBLOCKS) {
mem.current += size;
mem.memblocks[mem.current].size = size;
mem.memblocks[mem.current].ptr = malloc(size);
return mem.memblocks[mem.current++].ptr;
} else {
// you needed more memblocks than estimated
return NULL;
}
};
int MyFree(void *pointer) {
int i;
for (i = 0; i < mem.current; i++) {
if (mem.memblocks[i].ptr == pointer) {
mem.totalSize -= mem.memblocks[i].size;
free(mem.memblocks[i].ptr);
mem.current--;
return 0;
}
}
// you tried to free a block wich hasn't been allocated through MyMalloc()
return -1;
}

how free() works?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main ()
{
int * ptr;
printf("before malloc pointer is :%p \n",ptr);
printf("before malloc valu is :%d \n",*ptr);
ptr = malloc(sizeof(int));
printf("after malloc pointer is %p \n",ptr);
printf("after malloc valu is :%d \n",*ptr);
int jig=32;
*ptr = jig;
printf("after assignment valu is : %d\n",*ptr);
free(ptr);
printf("after free %p \n",ptr); // after free pointer holds sane address then
printf("after fee is %d\n",*ptr); // why it coudnt print that???
return 0;
}
output is :
before malloc pointer is :0x6edff4
before malloc valu is :7265660
after malloc pointer is 0x9a52008
after malloc valu is :0
after assignment valu is : 32
after free 0x9a52008
after fee is 0
after free still pointer holds the address of that memory then why we can not print that memory's value.??
what does free() do.?
does it just make all memory as 0 ..??
after free still pointer holds the address of that memory then why we can not print that memory's value.??
Because the memory no longer belongs to you. You freed it, which means the OS is allowed to reuse it however it sees fit, wherever it needs to allocate more memory. You no longer own it, therefore you no longer have any business looking at the value of the data held by that memory.
Note also that:
int *ptr;
...
printf("Before malloc valu is :%d\n", *ptr);
is equally invalid. ptr holds a garbage value, and can point anywhere. Dereferencing it is not guaranteed to be a memory location you can access.
Both of these cases invoke undefined behavior, which means the standard says, "DON'T DO THIS," and if you ignore the standard your code will break in horrible ways whenever your boss is looking.
what does free() do.?
does it just make all memory as 0 ..??
No, not necessarily. The OS often zeroes out unused memory in the background to make calls to calloc faster, but free only tells the operating system "I'm done with this memory, do whatever you need to with it." The OS typically updates some housekeeping data to indicate that the block of memory is no longer owned by a process, so that a later call to malloc can use it if it's needed.
The interesting thing about malloc() and free() is that they don't actually change the memory they give you -- they just change how it's "thought of".
When you call malloc(), a segment of memory is chosen and dedicated to be yours. While it's yours you can use it how you like.
When you're done with it you free() it -- but it's still there. It's still the same memory[1], it's just not considered "yours" anymore. So someone else might be using it.
[1] I supposed with virtual addressing this might not be always true. But it's usually true.
free returns the memory to the system. It is the partner operation to malloc. Everything block of memory that you allocate with malloc should be returned to the system by calling free. After you call free you are no longer allowed to access that memory.
It's generally considered wise to set the pointer to NULL after you have called free, at least in debug builds, so that you can be sure that an error will be raised if you later attempt to dereference the pointer by mistake.
So, why can you still access memory that has been freed? Well, you can't reliably do so. It just so happens that the implementation of most memory management systems mean that you can sometimes get away with such abuses. Many memory managers allocate large blocks of memory from the operating systems and then, in turn, allocate small sub-blocks to the application. When you call free, the allocator returns that block back to its pool of readily available memory, but does not necessarily give the memory back to the OS, since OS memory allocation routines are typically expensive. Hence accessing it may still appear to work, because the memory is still allocated in your process. It's just that its now owned by the memory manager rather than by your app. Something like that is happening to you here.
Of course, sometimes you won't get away with abuses like this, most likely once you have deployed your software onto your most important client's machine!
Typically the memory manager will have something like a linked list of free blocks that are used to satisfy subsequent allocations.
Here's a minimal implementation I wrote several years ago. It's not really intended (or suitable) for serious use, but gives at least some general notion of one way to manage a heap:
#include <stddef.h>
typedef struct node {
size_t size;
struct node *next;
} node;
node *free_list;
static void *split_end(node *block, size_t new_size) {
size_t difference = block->size - new_size;
node *temp = (node *)((char *)block + difference);
temp->size = new_size;
block->size = difference;
return (void *)((size_t *)temp+1);
}
static void *split_begin(node *block, size_t new_size) {
size_t difference = block->size-new_size;
node *temp = (node *)((char *)block + new_size);
temp->size = difference;
temp->next = free_list;
free_list = temp;
return block;
}
void b_init(void *block, size_t block_size) {
((node *)block)->size = block_size - sizeof(node);
((node *)block)->next = NULL;
free_list = block;
}
void b_free(void *block) {
node *b = (node *)((size_t *)block -1);
b->next = free_list;
free_list = b;
}
void *b_malloc(size_t size) {
node *temp, **ptr;
size_t larger = size+sizeof(node);
size += sizeof(size_t);
for ( ptr = &free_list;
NULL != ptr;
ptr = &((*ptr)->next))
{
if ((*ptr)->size >= size) {
if ( (*ptr)->size <= larger) {
temp = (*ptr);
(*ptr) = (*ptr)->next;
return (void *)((size_t *)temp + 1);
}
else
return split_end(*ptr, size);
}
}
return NULL;
}
void *b_realloc(void *block, size_t new_size) {
node *b = (node *)((char *)block - sizeof(size_t));
char *temp;
size_t i, size;
if ( new_size == 0) {
b_free(block);
return NULL;
}
new_size += sizeof(size_t);
size = b->size;
if ( new_size <size)
size = new_size;
size -= sizeof(size_t);
if ( b->size >= new_size+sizeof(node *) )
return split_begin(b, new_size);
if ( b->size >= new_size)
return b;
temp = b_malloc(new_size);
if ( NULL == temp)
return NULL;
for ( i=0; i<size;i++)
temp[i] = ((char *)block)[i];
b_free(block);
return temp;
}
#ifdef TEST
#define num 10
int main(void) {
int i;
char block[4096];
char *temp[num];
char *big;
b_init(block, sizeof(block));
big = b_malloc(100);
for (i=0; i<num; i++)
temp[i] = b_malloc(10);
for (i=0; i<num; i++)
b_free(temp[i]);
b_realloc(big, 200);
b_realloc(big, 10);
b_realloc(big, 0);
return 0;
}
#endif

Resources