I'm writing a simple utility in C and I'm writing codes to print error messages in STDERR.
I have a struct, defined as:
struct arguments
{
FILE *source;
int modifier_value;
int filesize;
};
I have declared a pointer to the above struct, and allocated memory to it:
struct arguments *arg = NULL;
arg = malloc(sizeof(struct arguments));
if(arg == NULL)
{
fprintf(stderr, "error: malloc - %s\n", strerror(errno)); //I know i could use perror as well, but I like the convention of using fprintf() for both stdout, stderr, and other file streams, just for symmetry
return EXIT_FAILURE;
}
As you can see, I have only allocated memory sufficient to store one object of type struct arguments and I still error checking for it.
The problem is I have many pointers like that which points to space of one object, and error checking all of them just increases number of codes and affects readability of code.
Is it a "good practice" / "is it ok" if I ignore error checking just for the reason that I'm not allocating memory too much memory (I heard something about paging and I think system combines many pages if I request for too much memory and chances of error in that case would be high, but not for memory request of something like 64 bytes).
Is it a "good practice" / "is it ok" if I ignore error checking just for the reason that I'm not allocating memory too much memory
It is poor practice to fail to error-check function calls that report on errors, except where you don't care whether the call succeeded. And you always care whether malloc() succeeds, or else you shouldn't be calling it in the first place. You don't know whether you are allocating too much memory unless you check whether your malloc() calls succeed.
The problem is I have many pointers like that which points to space of one object, and error checking all of them just increases number of codes and affects readability of code.
In the first place, use dynamic allocation only where you actually need it. Some people seem to have the idea that they need dynamic allocation wherever they want a pointer to an object. This absolutely is not the case. You need pointers if you are performing dynamic allocation, but you don't necessarily need dynamic allocation where you use pointers. Very often, static or automatic allocation can be combined with the address-of operator (unary &) instead. For example:
{
struct arguments arg = {0};
init_arguments(&arg);
do_something(&arg);
// all done with arg
}
You need dynamic allocation only when (i) you do not know at compile time how much memory you will need, or (ii) you need an object whose lifetime extends past the termination of the innermost block enclosing its creation.
When you really do need dynamic allocation, you can reduce the amount of boilerplate code by using a macro or a wrapper function. Similar applies to performing other success checks. For example, use a function such as this instead of using malloc() directly:
void *checked_malloc(size_t size) {
void *result = malloc(size);
if (result == NULL && size != 0) {
fputs("error: malloc failed -- aborting...\n", stderr);
abort();
}
return result;
}
Create allocation wrapper functions to make always checking allocation success easy.
To expand on #Weather Vane idea of passing an argument to identify the caller, yet do it in a macro wrapper.
my_malloc.h
#ifndef MY_MALLOC
#define MY_MALLOC(size) my_malloc((size), __FUNC__, __LINE__)
#include <stdlib.h>
// Return a valid allocation or don't return.
void *my_malloc(size_t size, const char *func, unsigned line);
#endif
my_malloc.c
#include "my_maloc.h"
#include <stdio.h>
#include <stdlib.h>
void *my_malloc(size_t size, const char *func, unsigned line) {
if (size == 0) {
return NULL;
}
void *ptr = malloc(size);
if (ptr == NULL) {
fprintf(stderr, "Failed to allocate %zu bytes at \"%s()\", line %u\n",
size, func, line);
exit(EXIT_FAILURE);
}
return ptr;
}
user_code.c
#include "my_malloc.h"
...
// No need to explicitly pass the function name, line number
arg = MY_MALLOC(sizeof *arg * n);
// Error checking not needed.
...
free(arg);
I'd even consider a matching MY_FREE where freeing passes in the pointer and the expected size. Then those 2 routines could keep allocation statistics, free size validation, ...
If you have many objects, you cam allocate memory for all immediately:
void *pvc;
pvc = malloc(how_many_for_all);
and then consecutively declare pointers to objects like this:
Obj1 *p1;
Obj2 *p2;
Obj3 *p3;
p1 = (Obj1)pvc;
p2 = (Obj2)(pvc + sizeof(Obj1));
p3 = (Obj3)(pvc + sizeof(Obj1) + sizeof(Obj2));
This is pseudocode sooner. Compiler will be make warnings, but this works.
Related
Edit: solved by kaylums little comment. Thank you!
good morning,
I am relatively new to C still and I'm trying to make a doubly linked list.
I got my program to run properly with all the functions with this kind of element:
the program crashes after either 2 or 3 inserted elements in the list in the calloc() call of my insertElement() function. I don't get any SIGSEGV or anything, the program just stops with a random negative return.
I'll try to give a minimum code example of the function and the function call:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct Element {
char name[30];
}Element;
typedef struct List {
int size;
Element* first;
Element* last;
}List;
Element* insertElement(List* List, char name[30]) {
Element* element;
element = (Element*)calloc(0, sizeof(Element));
strncpy_s(element->name, name, 30);
return element;
}
List globalList;
char name[30];
int main() {
while (true) {
printf("insert the name >>");
if (fgets(name, 30, stdin) != NULL)
name[strcspn(name, "\n")] = 0;
insertElement(&globalList, name);
}
}
is there already something obvious wrong with that basic stuff?
Thank you very much in advance! Any advice would be very much appreciated, have a good day!
element = (Element*)calloc(0, sizeof(Element));
what is 0 in first argument?
actually you ask for 0 number of your type from memory!
here is some explanation about dynamic memory allocation:
Dynamic memory allocation is a process of allocating memory at run time. There are four library routines, calloc(), free(), realloc(), and malloc() which can be used to allocate memory and free it up during the program execution. These routines are defined in the header file called stdlib.h.
What is malloc() ?
It is a function which is used to allocate a block of memory dynamically. It reserves memory space of specified size and returns the null pointer pointing to the memory location.
The pointer returned is usually of type void. It means that we can assign malloc function to any pointer. The full form of malloc is memory allocation.
What is calloc() ?
Calloc() function is used to allocate multiple blocks of memory. It is a dynamic memory allocation function which is used to allocate the memory to complex data structures such as arrays and structures. If this function fails to allocate enough space as specified, it returns will null pointer. The full form of calloc function is contiguous allocation.
Why use malloc() ?
Here are the reasons of using malloc()
You should use malloc() when you have to allocate memory at runtime.
You should use malloc when you have to allocate objects which must exist beyond the execution of the current memory block.
Go for malloc() if you need to allocate memory greater than the size of that stack.
It returns the pointer to the first byte of allocated space.
It enables developers to allocate memory as it is needed in the exact amount.
This function allocates a memory block size of bytes from the heap.
Why use calloc() ?
Here are the reasons of using calloc()
When you have to set allocated memory to zero.
You can use calloc that returns a pointer to get access to memory heap.
Used when you need to initialize the elements to zero to returns a pointer to the memory.
To prevent overflow that is possible with malloc()
Use calloc() to request a page that is known to already be zeroed.
Syntax of malloc()
Here is a Syntax of malloc()
ptr = (cast_type *) malloc (byte_size);
n above syntax, ptr is a pointer of cast_type. The malloc function returns a pointer to the allocated memory of byte_size.
Example of malloc() in C
In the bellow code, sizeof(*ptr) is used to allocate a memory block of 15 integers. In the printf statement, we are finding the value of the 6th integer.
#include<stdlib.h>
#include<stdio.h>
int main(){
int *ptr;
ptr = malloc(15 * sizeof(*ptr));
if (ptr != NULL) {
*(ptr + 5) = 480;
printf("Value of the 6th integer is %d",*(ptr + 5));
}
}
Output:
Value of the 6th integer is 480
Syntax of calloc()
Here is a Syntax of malloc()
ptr = (cast_type *) calloc (n, size);
The above syntax is used to allocate n memory blocks of the same size. After the memory space is allocated, all the bytes are initialized to zero. The pointer, which is currently at the first byte of the allocated memory space, is returned.
Example of calloc() in C
The C language program below calculates the sum of the first ten terms. If the pointer value if null, then the memory space will not be allocated.
For loop is used to iterate the value of a variable "i" and print the sum. Lastly, function free is used to free-up the pointer.
#include <stdio.h>
#include <stdlib.h>
int main() {
int i, * ptr, sum = 0;
ptr = calloc(10, sizeof(int));
if (ptr == NULL) {
printf("Error! memory not allocated.");
exit(0);
}
printf("Building and calculating the sequence sum of the first 10 terms \n");
for (i = 0; i < 10; ++i) { * (ptr + i) = i;
sum += * (ptr + i);
}
printf("Sum = %d", sum);
free(ptr);
return 0;
}
Output:
Building and calculating the sequence sum of the first 10 terms n Sum = 45
I will not extend on the actual problem (specifying 0 as the number of elements requested to calloc()). I will point you to several other things found in your code.
The first problem in reading your code is that you lack to include the file <stdbool.h>, necessary to use the constants true and false and the type bool. I have added it in the first line.
#include <stdbool.h>
Next, you use at several places the value 30 as the size of several objects that are all related. If you decide in the future to change that value, it will be difficult to find all the ocurrences of the constan 30 and change all of them (and the risk you have used also 30 for anything else and it gets changed in the middle)
I have included a constan with the following lines:
#define NAME_LENGTH (30)
and all the definitions:
...
char name[NAME_LENGTH];
in the structure...
Element* insertElement(List* List, char name[NAME_LENGTH]) {
in the prototype of insertElement (you don't need as name is actually defined as char *, not as an array of NAME_LENGTH elements...
On other side, you need to include a pointer on each Element to link each to the next element of the list. This is done right after name:
struct Element *next; /* we need to include struct as the type Element is not yet defined */
Next, include sizeof *element as the second parameter to calloc() and 1 to the first. Better, if you are going to initialize all fields in the Element structure, then it is better to call malloc() (see the final code , posted at the end)
NEVER, NEVER, NEVER cast the value returned by malloc()
(and friends) This is a legacy that causes a lot of
errors, that get undetected (and very difficult to find),
due to the cast. When you cast you tell the compiler:
leave it in my hands, as I know what I'm doing. And this
makes the compiler silent, when it should be complaining.
The problem mainly has to do with forgetting to include
the header file where malloc (and friends) are declared
(<stdlib.h>) and you will take long time to detect and
see why your program has crashed.
For the same reason, don't use the size of the type, when
you can use the pointed to expression as template of the
type. This is because if you change the type of the
pointed to object, you need to remember that here you have
put the type of the object (and you need to change it too)
This way, this expression
will only be bad if you change the object into a non
pointer object. Also, you have requested for 0 elements
of the specified type, which has already been noticed in other answers. This will make calloc() to return NULL, value you don't check in your code, and you try to use it later on. This will crash your program, but in the best case, it is Undefined Behaviour (and a very difficult error to find, so be careful and always check the value returned by malloc()).
Next, don't use strncpy_s() as it is Microsoft specific routine, and isn't included in any standard. A proper substitute has been provided by strncpy():
strncpy(element->name, name, sizeof element->name);
also use the sizeof operator, as it protects you if you decide in the future to change the type of the pointer.
Finally, it is better to use fgets() as the test expression for the while statement in main(). The reason is that you can end the loop when the end of file is detected.
Finally, you code ends as (including the linking of Elements in the linked list):
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define NAME_LENGTH (30)
typedef struct Element {
char name[NAME_LENGTH];
struct Element *next;
} Element;
typedef struct List {
int size;
Element* first;
Element* last;
} List;
Element* insertElement(List* List, char name[NAME_LENGTH]) {
Element* element;
/* NEVER, NEVER, NEVER cast the value returned by malloc
* (and friends) This is a legacy that causes a lot of
* errors, that get undetected (and very difficult to find),
* due to the cast. When you cast you tell the compiler:
* leave it in my hands, as I know what I'm doing. And this
* makes the compiler silent, when it should be complaining.
* The problem mainly has to do with forgetting to include
* the header file where malloc (and friends) are declared
* (<stdlib.h>) and you will take long time to detect and
* see why your program has crashed. */
/* for the same reason, don't use the size of the type, when
* you can use the pointed to expression as template of the
* type. This is because if you change the type of the
* pointed to object, you need to remember that here you have
* put the type of the object. This way, this expression
* will only be bad if you change the object into a non
* pointer object. Also, you have requested for 0 elements
* of the specified type. */
element = malloc(sizeof *element);
/* don't use strncpy_s as it is not standard. Use the sizeof
* operator again, to protect the expression if you change
* the type of element->name */
strncpy(element->name, name, sizeof element->name);
element->next = NULL;
if (List->last) {
List->last->next = element;
List->last = element;
} else {
List->first = List->last = element;
}
return element;
}
List globalList;
char name[NAME_LENGTH];
int main() {
/* if you put the fgets() call as the test of the while
* statement below, you will process each line until you get
* an end of file condition. Then you can do both things: to
* null the occurence of the \n char, and the call to
* insertElement() I have not corrected because it's a
* question of taste. */
printf("insert the name >> ");
while (fgets(name, sizeof name, stdin) != NULL) {
/* sizeof name is better than the constant, as if you
* change the type definition of object name, you have to
* remember that you are using here its size. sizeof
* does the job for you. */
name[strcspn(name, "\n")] = 0;
insertElement(&globalList, name);
printf("insert the name >> ");
}
Element *p;
char *sep = "\n\n{ ";
for (p = globalList.first; p; p = p->next) {
printf("%s\"%s\"", sep, p->name);
sep = ", ";
}
printf(" };\n");
}
How do I free dynamically allocated memory?
Suppose input (assume it is given by user) is 1000 and now if I allocate memory of 1000 and after this(second time) if user gives input as 500 can I reuse already allocated memory ?
If user now inputs value as say 3000 , how do I go with it ? can I reuse already allocated 1000 blocks of memory and then create another 2000 blocks of memory ? or should I create all 3000 blocks of memory ?
which of these is advisable?
#include <stdio.h>
#include <stdlib.h>
typedef struct a
{
int a;
int b;
}aa;
aa* ptr=NULL;
int main() {
//code
int input=2;
ptr=malloc(sizeof(aa)*input);
for(int i=0;i<input;i++)
{
ptr[i].a=10;
ptr[i].b=20;
}
for(int i=0;i<input;i++)
{
printf("%d %d\n",ptr[i].a,ptr[i].b);
}
return 0;
}
I believe, you need to read about the "lifetime" of allocated memory.
For allocator functions, like malloc() and family, (quoting from C11, chapter §7.22.3, for "Memory management functions")
[...] The lifetime of an allocated object extends from the allocation
until the deallocation. [....]
So, once allocated, the returned pointer to the memory remains valid until it is deallocated. There are two ways it can be deallocated
Using a call to free() inside the program
Once the program terminates.
So, the allocated memory is available, from the point of allocation, to the termination of the program, or the free() call, whichever is earlier.
As it stands, there can be two aspects, let me clarify.
Scenario 1:
You allocate memory (size M)
You use the memory
You want the allocated memory to be re-sized (expanded/ shrinked)
You use some more
You're done using
is this is the flow you expect, you can use realloc() to resize the allocated memory size. Once you're done, use free().
Scenario 2:
You allocate memory (size M)
You use the memory
You're done using
If this is the case, once you're done, use free().
Note: In both the cases, if the program is run multiple times, there is no connection between or among the allocation happening in each individual invocation. They are independent.
When you use dynamically allocated memory, and adjust its size, it is important to keep track of exactly how many elements you have allocated memory for.
I personally like to keep the number of elements in use in variable named used, and the number of elements I have allocated memory for in size. For example, I might create a structure for describing one-dimensional arrays of doubles:
typedef struct {
size_t size; /* Number of doubles allocated for */
size_t used; /* Number of doubles in use */
double *data; /* Dynamically allocated array */
} double_array;
#define DOUBLE_ARRAY_INIT { 0, 0, NULL }
I like to explicitly initialize my dynamically allocated memory pointers to NULL, and their respective sizes to zero, so that I only need to use realloc(). This works, because realloc(NULL, size) is exactly equivalent to malloc(NULL). I also often utilize the fact that free(NULL) is safe, and does nothing.
I would probably write a couple of helper functions. Perhaps a function that ensures there is room for at_least entries in the array:
void double_array_resize(double_array *ref, size_t at_least)
{
if (ref->size < at_least) {
void *temp;
temp = realloc(ref->data, at_least * sizeof ref->data[0]);
if (!temp) {
fprintf(stderr, "double_array_resize(): Out of memory (%zu doubles).\n", at_least);
exit(EXIT_FAILURE);
}
ref->data = temp;
ref->size = at_least;
}
/* We could also shrink the array if
at_least < ref->size, but usually
this is not needed/useful/desirable. */
}
I would definitely write a helper function that not only frees the memory used, but also updates the fields to reflect that, so that it is completely safe to call double_array_resize() after freeing:
void double_array_free(double_array *ref)
{
if (ref) {
free(ref->data);
ref->size = 0;
ref->used = 0;
ref->data = NULL;
}
}
Here is how a program might use the above.
int main(void)
{
double_array stuff = DOUBLE_ARRAY_INIT;
/* ... Code and variables omitted ... */
if (some_condition) {
double_array_resize(&stuff, 321);
/* stuff.data[0] through stuff.data[320]
are now accessible (dynamically allocated) */
}
/* ... Code and variables omitted ... */
if (weird_condition) {
/* For some reason, we want to discard the
possibly dynamically allocated buffer */
double_array_free(&stuff);
}
/* ... Code and variables omitted ... */
if (other_condition) {
double_array_resize(&stuff, 48361242);
/* stuff.data[0] through stuff.data[48361241]
are now accessible. */
}
double_array_free(&stuff);
return EXIT_SUCCESS;
}
If I wanted to use the double_array as a stack, I might do
void double_array_clear(double_array *ref)
{
if (ref)
ref->used = 0;
}
void double_array_push(double_array *ref, const double val)
{
if (ref->used >= ref->size) {
/* Allocate, say, room for 100 more! */
double_array_resize(ref, ref->used + 100);
}
ref->data[ref->used++] = val;
}
double double_array_pop(double_array *ref, const double errorval)
{
if (ref->used > 0)
return ref->data[--ref->used];
else
return errorval; /* Stack was empty! */
}
The above double_array_push() reallocates for 100 more doubles, whenever the array runs out of room. However, if you pushed millions of doubles, this would mean tens of thousands of realloc() calls, which is usually considered wasteful. Instead, we usually apply a reallocation policy, that grows the size proportionally to the existing size.
My preferred policy is something like (pseudocode)
If (elements in use) < LIMIT_1 Then
Resize to LIMIT_1
Else If (elements in use) < LIMIT_2 Then
Resize to (elements in use) * FACTOR
Else
Resize to (elements in use) + LIMIT_2
End If
The LIMIT_1 is typically a small number, the minimum size ever allocated. LIMIT_2 is typically a large number, something like 220 (two million plus change), so that at most LIMIT_2 unused elements are ever allocated. FACTOR is between 1 and 2; many suggest 2, but I prefer 3/2.
The goal of the policy is to keep the number of realloc() calls at an acceptable (unnoticeable) level, while keeping the amount of allocated but unused memory low.
The final note is that you should only try to keep around a dynamically allocated buffer, if you reuse it for the same (or very similar) purpose. If you need an array of a different type, and don't need the earlier one, just free() the earlier one, and malloc() a new one (or let realloc() in the helpers do it). The C library will try to reuse the same memory anyway.
On current desktop machines, something like a hundred or a thousand malloc() or realloc() calls is probably unnoticeable compared to the start-up time of the program. So, it is not that important to minimize the number of those calls. What you want to do, is keep your code easily maintained and adapted, so logical reuse and variable and type names are important.
The most typical case where I reuse a buffer, is when I read text input line by line. I use the POSIX.1 getline() function to do so:
char *line = NULL;
size_t size = 0;
ssize_t len; /* Not 'used' in this particular case! :) */
while (1) {
len = getline(&line, &size, stdin);
if (len < 1)
break;
/* Have 'len' chars in 'line'; may contain '\0'! */
}
if (ferror(stdin)) {
fprintf(stderr, "Error reading standard input!\n");
exit(EXIT_FAILURE);
}
/* Since the line buffer is no longer needed, free it. */
free(line);
line = NULL;
size = 0;
Recently, I'm learning C. I found a question on the internet. The question is:
What is the problem with this function in terms of memory allocation?
What is a good solution? You may assume that a struct item type has
been declared. The purpose of this function is to allocate an array of
struct item, which you may assume has been declared prior to this
function.
BOOLEAN allocate_items(struct item * items, size_t howmany)
{
size_t count;
items = malloc(sizeof(struct item) * howmany);
if(!items) {
perror("failed to allocate memory");
return FALSE;
}
return TRUE;
}
So, I think that the 4th line is wrong. It should be like:
items = malloc(sizeof(struct item));
And also the 6th line is wrong. It should be like:
if(items == NULL){
Is it correct?
First of all, both line 4 and 6, as you mentioned seems to be OK.
That said, the basic problem with this function is, you're allocating memory to a local scope of variable. This way
as you don't return the pointer to allocated memory, after the function returns, there would be no way to access the allocated memory.
by not freeing up the allocated memory, you will face memory leak.
If you have to allocate memory to a pointer, you need to pass the address of that pointer to the function and allocate memory. You can also return the pointer but then you need to change the function signature.
Finally, arrays are not pointers and vice-versa. They may appear or beahave similar sometimes, but they are not the same.
The 4th line is not wrong as they are trying to declare an array of the structs.
You should add a line inside the function that declares a new pointer, temp, to hold the current value of items, then after allocating the memory,
the 6th line should be
if(items == temp)
to check whether the value has changed(because that is the closest we can get to checking whether malloc worked)
this is because the ! operator is used to check if a condition is true or not(at least at a basic level in most languages) and as a pointer isn't a condition or an int that can be used as true or false, the operator won't work.
Here a fixed version, as it would probably be written in the "industry".
bool allocate_items(struct item ** pitems, size_t howmany)
{
// argument validation
assert(NULL != pitems); // some also add release version checks...
if(NULL == pitems ) return false;
// We can also spot memory leak sources here.
// If *pItems != NULL - does that mean we have to free first to prevent
// a leak? What if it is just some random value and not something we can
// free? So contract usually is: *pitems has to be NULL...
assert(NULL == *pitems);
if(NULL != *pitems) return false;
// implementation
*pitems = malloc(sizeof(struct item) * howmany);
if(NULL == *pitems) {
perror("failed to allocate memory");
}
return NULL != *pitems;
}
While the bool defined in stdbool.h sometimes causes trouble with C++ interop (same symbols on both sides, but sometimes sizeof(bool) differs), it is still the better option compared to inventing yet another bool type.
The pitems is a pointer to the location where the pointer to the new chunk of memory shall be written to. A caller of this function might have written:
int main(int argc, const char*[] argv) {
struct item *myBunchOfStuff = NULL;
if(false != allocate_items( &myBunchOfStuff, 20) ) {
// ...
free(myBunchOfStuff);
myBunchOfStuff = NULL;
}
return 0;
}
Defensive programming states: Your function cannot claim "Heh - my function only crashed because I was given a bad value!". Instead, it has to verify itself. It is responsible not to crash. The pointer could still be != NULL but otherwise bad. That is impossible for the function to catch, usually.
In C, everyone is proud of not requiring the cast of malloc()'s return value. You can be proud of that until you compile your code with a C++ compiler. Then you have to change your code and fix that. Well, I guess it is a matter of preference...
While parameter checking is often seen as a separate part of the functions implementation, after that, you should try to stick to "single point of exit". Main reason for that is maintainability. With multiple exit points, if the function gets bigger later on, it gets harder to spot if some early exit forgets to free some memory or cleanup other forms of state.
I'm creating a source files containing buffer functionality that I want to use for my other library that I'm creating.
It is working correctly but I'm having trouble getting rid of the buffer structure that I'm creating in one of the functions. The following snippets should help illustrate my problem:
C header:
//dbuffer.h
...
typedef struct{
char *pStorage;
int *pPosition;
int next_position;
int number_of_strings;
int total_size;
}DBUFF;
...
C source:
//dbuffer.c
...
DBUFF* dbuffer_init(char *init_pArray)
{
//Find out how many elements the array contains
int size = sizeof_pArray(init_pArray);
//Initialize buffer structure
DBUFF *buffer = malloc(sizeof(DBUFF));
//Initialize the storage
buffer->pStorage = malloc( (sizeof(char)) * (size) );
strncpy( &(buffer->pStorage)[0] , &init_pArray[0] , size);
buffer->number_of_strings = 1;
buffer->total_size = size;
buffer->next_position = size; //size is the next position because array allocates elements from 0 to (size-1)
//Initialize the position tracker which keeps record of starting position for each string
buffer->pPosition = malloc(sizeof(int) * buffer->number_of_strings );
*(buffer->pPosition + (buffer->number_of_strings -1) ) = 0;
return buffer;
}
void dbuffer_destroy(DBUFF *buffer)
{
free(buffer->pStorage);
free(buffer);
}
...
Main:
#include <stdio.h>
#include <stdlib.h>
#include "dbuffer.h"
int main(int argc, char** argv)
{
DBUFF *buff;
buff = dbuffer_init("Bring the action");
dbuffer_add(buff, "Bring the apostles");
printf("BUFFER CONTENTS: ");
dbuffer_print(buff);
dbuffer_destroy(buff);
// Looks like it has been succesfully freed because output is garbage
printf("%s\n", buff->pStorage);
//Why am I still able to access struct contents after the pointer has been freed ?
printf("buff total size: %d\n", buff->total_size);
return (EXIT_SUCCESS);
}
Output:
BUFFER CONTENTS: Bring the action/0Bring the apostles/0
��/�
buff total size: 36
RUN SUCCESSFUL (total time: 94ms)
Question:
Why am I still able to access struct contents using the line below after the pointer to the struct has been freed ?
printf("buff total size: %d\n", buff->total_size);
Once you've called free() on the allocated pointer, attempt to make use of the pointer invokes undefined behavior. You should not be doing that.
To quote C11 standard, chapter §7.22.3.4, free() function
The free() function causes the space pointed to by ptr to be deallocated, that is, made
available for further allocation. [..]
It never say's anything about a cleanup, which you might be (wrongly) expecting.
Just to add clarity, calling free() does not always actually free up the allocated physical memory. It just enables that pointer (memory space) to be allocated again (returning the same pointer, for example) for successive calls to malloc() and family. After calling free(), that pointer is not supposed to be used from your program anymore but C standard does not guarantee of a cleanup of the allocated memory.
If any attempt is made to read memory that has been freed can crash your program. Or they might not. As far as the language is concerned, its undefined behaviour.
Your compiler won't warn you about it(or stop you from accessing it). But clearly don't do this after calling free -
printf("buff total size: %d\n", buff->total_size);
As a good practice you can set the freed pointer to NULL .
free() call will just mark the memory in heap as available for use. So you still have the pointer pointing to this memory location but it's not available anymore for you. Thus, the next call to malloc() is likely to assign this memory to the new reservation.
To void this situations normally once you free() the memory allocated to a pointer you should set it to NULL. De-referencing NULL is UB also but at least when debugging you can see tha pointer should not be used because it's not pointing to a valid memory address.
[too long for a comment]
To allow your "destructor" to set the pointer passed to NULL modify your code like this:
void dbuffer_destroy(DBUFF ** buffer)
{
if ((NULL == buffer) || (NULL == *buffer))
{
return;
}
free((*buffer)->pPosition);
free((*buffer)->pStorage);
free(*buffer);
*buffer = NULL;
}
and call it like this:
...
dbuffer_destroy(&buff);
...
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void getinfo(unsigned int a, unsigned int b, char **pStr);
int main(){
unsigned int len_max = 8;
unsigned int current_size = 0;
current_size = len_max;
char *host, *user;
char *pStr = malloc(len_max);
if(pStr == NULL){
perror("\nMemory allocation\n");
return EXIT_FAILURE;
}
printf("Inserisci hostname: ");
getinfo(len_max, current_size, &pStr);
if((host=malloc(strlen(pStr)+1 * sizeof(char))) == NULL) abort();
strncpy(host, pStr, strlen(pStr)+1);
printf("Inserisci username: ");
getinfo(len_max, current_size, &pStr);
if((user=malloc(strlen(pStr)+1 * sizeof(char))) == NULL) abort();
strncpy(user, pStr, strlen(pStr)+1);
printf("\nHostname: %s\nUsername: %s\n", host, user);
free(pStr);
free(host);
free(user);
return EXIT_SUCCESS;
}
void getinfo(unsigned int a, unsigned int b, char **pStr){
unsigned int i = 0;
int c = EOF;
while((c = getchar()) != '\n'){
(*pStr)[i++] = (char)c;
if(i == b){
b = i+a;
if((*pStr = realloc(*pStr, b)) == NULL){
perror("\nMemory allocation error\n");
exit(EXIT_FAILURE);
}
}
}
(*pStr)[i]='\0';
}
The problem is that if realloc fails i have to exit (because i cannot allocate memory). But before exit there's to free all the used pointers.The problem is that if the function fails the first time there's only 1 pointer that have to be freed (pStr). But if it fails the second time there's 2 pointers that have to be freed (pstr & user).
How can i fix it?
As already noted, if you are going to exit, then all practical modern O/S will release the allocated memory before exit. It was not always thus; early versions of AmigaDOS, IIRC, did not reclaim allocated memory automatically until reboot.
This is a simple case. There are more complex cases, such as you are parsing a file into memory and the 579th memory allocation fails, and you'd like to release the previous 578 memory allocations so that the user can try again.
In such cases, you have to keep a record of each memory allocation that is relevant (which may itself require some memory allocation — though if you're parsing a file, you probably have a master structure which contains the complete description) and then release all the allocated data.
In your example, if this was not a main() function and if you did not abort on memory allocation error, then you would need to ensure that the three allocated pointers are released on exit from the function. The standard tricks for that include:
Initialize the pointers to 0 so they can be freed reliably:
char *host = 0;
char *user = 0;
When using realloc(), do not assign the result to the expression passed as the first parameter:
Do NOT do:
ptr = realloc(ptr, newsize);
If (when) ptr is the only reference to the allocated memory and the reallocation fails, you've just leaked memory; there is no way to release the memory that is still allocated to you.
Use:
void *newptr = realloc(oldptr, newsize);
if (newptr == 0)
...recover from memory allocation failure
oldptr = newptr;
The trouble with the simpler version is that you've just thrown away the only reference to the allocated memory. (Note that your code falls into the dangerous/leaking pattern).
Note that pretty much every function that acquires resources must either release the acquired resource before returning, or make the resource available to some other part of the program so that the other part can release the resource when it is done with it.
The 'make available' operation might be returning the acquired resource (think of it as memory, but it could be a file descriptor, directory stream, or any of a large number of other allocated resources) to the calling function, or storing it in a structure that was passed to the current function, or copying it to a global or (file) static variable, or even stashing it in a (function) static variable so if the function is called again, it has some resource available on entry.
As a few people have pointed out, modern OS's reclaim memory on exit. However, it is considered a best practice to free your resources anyway, as this makes debugging easier. For example, if you are trying to find a leak and you use a tool like valgrind, all the memory you don't properly free (even if by the program logic, this doesn't matter) will appear as leaks. There are some large API's around that notoriously don't do this, and they make tracking leaks in applications which use them a nightmare.
Also, in some specialized environments it might be important to clean up after yourself. Therefore, it's a good habit to get into now.
A clean-up technique you'll see occasionally (eg, in the linux kernel) is something I think of as the "bail and release" pattern. It's one of the few (perhaps: only) contexts where goto is still considered acceptable. It depends upon you being able to free your resources in the opposite order you allocated them. Usually this is in the context of a single function, in this case main():
#include <stdlib.h>
int main(void) {
int exit_status = EXIT_FAILURE;
char *s1, *s2, *s3;
s1 = malloc(100);
if (!s1) return EXIT_FAILURE;
s2 = malloc(100);
if (!s2) goto endB;
s3 = malloc(100);
if (!s3) goto endA;
exit_status = EXIT_SUCCESS;
/* do whatever */
free(s3);
endA:
free(s2);
endB:
free(s1);
return exit_status;
}
To explain: if allocating s1 fails, we just return -- there is nothing to clean-up. But if allocating s2 fails, we goto endB, freeing s1. If allocating s3 fails, we goto endA, which will free s2 and s1. Finally, if everything succeeded, we do whatever, and afterward, all three pointers will be freed. If this were a normal function, we might be returning a pointer, so there would be a separate return for that before the "end" bits, which would complete with "return null" instead.
Nb: please don't take this as a licence to make free-wheeling use of goto!
Yeah, you don't have to free anything if this is the whole program.
The whole reason to free memory is so it can be reused somewhere later in the program. Even if your program went on from this point, you've only allocated a small number of bytes. It's OK to allocate them and keep them forever.
In fact, you don't even have to do the arithmetic you're doing there to carve out exact-sized mallocs, you could say Oh, usernames and hostnames are never more than like 30 chars, just to be sure I'll allocate 256 char blocks. Oh wait your max is 8 chars, whatever. Or even just make a global buffer 256 chars or 8 chars long. Then make sure your strncpy()s never go past len_max or else you're risking a buffer overflow hack.
meanwhile that getinfo() looks painful. Try something like fgets(mybuffer, len_max, stdin).
Last I checked, the executable doesn't even bother to 'free' all unfreed blocks at the end, it just walks away. The VM system returns all the used memory (including the stack and program code) to the OS, and the process vaporizes and it's over. The malloc()ed blocks are just a pattern of bytes on that memory, and it's all forgotten.
This is more of a general C language advice than a specific answer, but it's too long to go in comment.
The usual way to write C in the presence of dynamic resource management is to goto suitable labels which are followed by the relevant deallocation calls:
int f(int n)
{
void * p1, * p2, * p3;
int result = -1;
p1 = malloc(n);
if (!p1) goto END0;
if (n % 2) goto END1;
p2 = malloc(3 * n);
if (!p2) goto END1;
if (n % 7 == 0) goto END2;
p3 = malloc(7 * n + 8);
if (!p3) goto END2;
if (do_useful_stuff(p1, p2, p3) == -1) goto END3;
result = compute_more_stuff(p1, p2, p3);
END3:
free(p3);
END2:
free(p2);
END1:
free(p1);
END0:
return result;
}
The alternative is to split up your code into very small functions that do only one thing at a time and handle resource allocation in an ad-hoc fashion:
int small_function(void ** p)
{
void * q = malloc(13);
if (some_init(&q) == -1)
{
free(q); // ad-hoc exit management
return -1;
}
int n = complex_computation(q);
free(q);
return n;
}
You don't have to free dynamically allocated memory before exiting. The OS will make all that memory available to the next process.