Shouldn't free() accept a (void *const) as input arg - c

I was trying to understand the working of free.
Is it defined in the standards that free() will not change the pointer which it was passed?

In standard C argument passing is by value. So a function cannot change the value of its argument (and this is not specific to free). Every call is a call by value. If inside a function you change some argument only a local copy (e.g. in some machine register) of that argument is changed and the caller does not see any change.
If you want to change something, you'll pass the address of that something as a value and you'll dereference that pointer.
Hence free won't change the pointer you pass to it, but you need to be sure to never use that pointer again. Otherwise, that is undefined behavior. A common style is to code free(ptr), ptr=NULL; (so that any further access thru ptr would crash with a segmentation fault).
In practice, most implementations of the C standard library are marking a free-d zone to be reusable by future malloc. But sometimes (notably when freeing a large memory zone) the memory is released to the kernel (e.g. by munmap(2) on Linux). What really happens to the memory zone is implementation specific.
Read wikipages of C dynamic memory allocation & virtual address space.
Look also inside the source code of some free software C standard library implementation (e.g. most libc on Linux, such as musl-libc or GNU libc...). Compile your code with all warnings & debug info (e.g. gcc -Wall -Wextra -g if using GCC...) then use valgrind to hunt memory leak bugs.

The const storage type tells the compiler that you do not intend to modify a block of memory once allocated (dynamically, or statically). Freeing memory is modifying it.

Whether free changes the input argument or not relevant to the calling code. The calling code still has the pointer. It is similar to passing an int to a function. The called function may change the variable but it is change of the copy, not the original.
void foo(int i)
{
i += 2;
}
void bar()
{
int i = 10;
foo(i);
}
Here, the change made to i in foo does not change the value of i in `bar.
Similarly,
void free(void* ptr)
{
// Do the needful to deallocate
...
ptr = NULL;
}
void test()
{
char* p = malloc(10);
...
free(p);
}
Here, the change made to ptr in free does not change the value of the pointer in test. Hence, it does not make much sense to make the argument of free to be of type void* const.

Related

Is it okay to free multiple dynamically allocated memories at once?

During my school assignments, I just got curious if it really frees as I expect.
#include "stdio.h"
#include "stdlib.h"
void main(){
int* menu1 = (int*)malloc(sizeof(int));
int* menu2 = (int*)malloc(sizeof(int));
int* menu3 = (int*)malloc(sizeof(int));
int* menu4 = (int*)malloc(sizeof(int));
int* menu5 = (int*)malloc(sizeof(int));
free(menu1,menu2,menu3,menu4,menu5);
system("pause");
}
It still runs in VS2017, but I'm not sure that it's freed correctly.
for each pointer you have, you allocated memory separately. By memory allocation, the system allocates a bit more that requested in order to safe some control information which should be used for different internal purposes and also later for deallocation.
Since each allocated memory knows only about itself and not about other allocated pieces of memory, you cannot free all together.
The function free expects only one argument (one pointer). Please see 7.22.3.3 in C standard.
GCC doesn't compile this code.
No.
https://linux.die.net/man/3/free
void free(void *ptr);
I code does not compile:
error: too many arguments to function ‘free’
free(menu1,menu2,menu3,menu4,menu5);
The code as is, will not compile:
free(menu1,menu2,menu3,menu4,menu5); /* error: too many arguments to function 'free' */
The function free is defined in header <stdlib.h> and takes only one parameter:
void free( void* ptr );
Parameters:
`ptr` - pointer to the memory to deallocate
Return value:
(none)
Function deallocates the space previously allocated by malloc(), calloc(), aligned_alloc, (since C11) or realloc().
If ptr is a null pointer, the function does nothing.
References:
C11 standard (ISO/IEC 9899:2011):
7.22.3.3 The free function (p: 348)
C99 standard (ISO/IEC 9899:1999):
7.20.3.2 The free function (p: 313)
C89/C90 standard (ISO/IEC 9899:1990):
4.10.3.2 The free function
Your code does not compile, because the function free() expects one argument, but you passed more than that; 5 to be exact.
You could make it compile by enclosing the arguments in parentheses:
free((menu1, menu2, menu3, menu4, menu5));
This allows all the arguments to be evaluated by using the comma operator, but only the last one will be used by the function free(). That is, only menu5 will be freed, and the rest won't.
You must call free() on each argument separately to release memory appropriately:
free(menu1);
free(menu2);
...
free(menu5);
If this compiles you are using an olde compiler. What you are showing is a common error in C code.
What happens in this case the generated code looks something like this:
PUSH menu5 ; which probably looks more like "menu5(SP)"
PUSH menu4
PUSH menu3
PUSH menu2
PUSH menu1
CALL _free
free () only expects one argument and it finds an argument: menu1. The extra arguments simply get ignored.
What would cause even bigger problems is to not pass enough arguments to a function. In that case the function being called would use random garbage on the stack as the argument. Something like
fprintf (fp)
in rarely executed logging code could give you a crash.

How to call a void function with a pointer parameter?

I don't understant how I can call this function correctly in main.
I tried calling like this: X *p1=malloc(sizeof(X));read(&p1);
struct x
{ int c;
char n[250];
char u[150];
};
typedef struct x X;
void myread(X *p);
void myread(X *p)
{
scanf("%d",&p->c);
fgets(p->n,sizeof(p->n),stdin);
fgets(p->u,sizeof(p->u),stdin);
}
void main(){
X *p1;
p1=malloc(sizeof(X));
myread(p1);
}
The function as declared in your question (void read(X *p)) needs a pointer to X as parameter.
Your declaration of (X *p1) ensures that it is a pointer to X.
Your initialisation (p1=malloc(sizeof(X));) makes it a pointer to a suitably sized piece of useable memory.
That's it.
You then however use that appropriate pointer with the "take the address operator" &, which results in a pointer-to-pointer to X.
Calling the function with p1 as parameter would look like
read(p1);
I.e. just give the pointer to X as it is.
The function looks like it is supposed to fill the malloced space with values.
How that works and how it could be improved is not part of your question.
Don't use gets. It is dangerous and obsolete. Use fgets instead. Replace gets(p->n) with fgets(p->n, sizeof(p->n), stdin); and so on.
Don't name your function read (since that is the name of a POSIX standard function). Replace it by another name, e.g. myread.
You probably want to do:
X *p1=malloc(sizeof(X));
in your main. Then, you need to check that malloc succeeded:
if (!p1) { perror("malloc p1"); exit(EXIT_FAILURE); }
Beware that malloc gives (on success) some uninitialized memory zone. You may want to clear it using memset(p1, 0, sizeof(p1)), or you could use p1 = calloc(1, sizeof(X)) instead.
At last you can pass it to your myread:
myread(p1);
Don't forget to call free(p1) (e.g. near the end of your main) to avoid a memory leak.
Learn to use valgrind, it catches many memory related bugs.
Of course you need to carefully read the documentation of every standard function that you use. For example, fgets(3) documents that you need to #include <stdio.h>, and that call to fgets can fail (and your code needs to check that, see also errno(3) & perror(3)...). Likewise, malloc(3) wants #include <stdlib.h> and should be checked. And scanf(3) can fail too, and needs to be checked.
You should compile with all warnings and debug info (gcc -Wall -Wextra -g with GCC), improve your code to get no warnings, and you should use the gdb debugger; you may want to use GCC sanitizers (e.g. instrumentation options like -fsanitize=address, -fsanitize=undefined and others),
Beware of undefined behavior (UB). It is really scary.
PS. I hope that you are using Linux with gcc, since it is a very developer friendly system. If not, adapt my answer to your operating system and compiler and debugging tools.

Freeing dynamically allocated int that needs to be returned but cannot be freed in main in c

As my long title says: I am trying to return a pointer in c that has been dynamically allocated, I know, I have to free it, but I do not know how to myself, my search has showed that it can only be freed in main, but I cannot leave it up to the user to free the int.
My code looks like this right now,
int *toInt(BigInt *p)
{
int *integer = NULL;
integer = calloc(1, sizeof(int));
// do some stuff here to make integer become an int from a passed
// struct array of integers
return integer;
}
I've tried just making a temp variable and seeing the integer to that then freeing integer and returning the temp, but that hasn't worked. There must be a way to do this without freeing in main?
Program design-wise, you should always let the "module" (translation unit) that did the allocation be responsible for freeing the memory. Expecting some other module or the caller to free() memory is indeed bad design.
Unfortunately C does not have constructors/destructors (nor "RAII"), so this has to be handled with a separate function call. Conceptually you should design the program like this:
#include "my_type.h"
int main()
{
my_type* mt = my_type_alloc();
...
my_type_free(mt);
}
As for your specific case, there is no need for dynamic allocation. Simply leave allocation to the caller instead, and use a dedicated error type for reporting errors:
err_t toInt (const BigInt* p, int* integer)
{
if(bad_things())
return ERROR;
*integer = p->stuff();
return OK;
}
Where err_t is some custom error-handling type (likely enum).
Your particular code gains nothing useful from dynamic allocation, as #unwind already observed. You can save yourself considerable trouble by just avoiding it.
In a more general sense, you should imagine that with each block of allocated memory is associated an implicit obligation to free. There is no physical or electronic representation of that obligation, but you can imagine it as a virtual chit associated at any given time with at most one copy of the pointer to the space during the lifetime of the allocation. You can transfer the obligation between copies of the pointer value at will. If the pointer value with the obligation is ever lost through going out of scope or being modified then you have a leak, at least in principle; if you free the space via a copy of the pointer that does not at that time hold the obligation to free, then you have a (possibly virtual) double free.
I know I have to free it, but I do not know how to myself
A function that allocates memory and returns a copy of the pointer to it without making any other copies, such as your example, should be assumed to associate the obligation to free with the returned pointer value. It cannot free the allocated space itself, because that space must remain allocated after the function returns (else the returned pointer is worse than useless). If the obligation to free were not transferred to the returned pointer then a (virtual) memory leak would occur when the function's local variables go out of scope at its end, leaving no extant copy of the pointer having obligation to free.
I cannot leave it up to the user to free the int.
If you mean you cannot leave it up to the caller, then you are mistaken. Of course you can leave it up to the caller. If in fact the function allocates space and returns a pointer to it as you describe, then it must transfer the obligation to free to the caller along with the returned copy of the pointer to the allocated space. That's exactly what the calloc() function does in the first place. Other functions do similar, such as POSIX's strdup().
Because there is no physical or electronic representation of obligation to free, it is essential that your functions document any such obligations placed on the caller.
Just stop treating it as a pointer, there's no need for a single int.
Return it directly, and there will be no memory management issues since it's automatically allocated:
int toInt(const BigInt *p)
{
int x;
x = do some stuff;
return x;
}
The caller can just do
const int my_x = toInt(myBigInt);
and my_x will be automatically cleaned away when it does out of scope.

malloc preventing garbage from being printed?

Program was programmed in C and compiled with GCC.
I was trying to help a friend who was trying to use trying to (shallow) copy a value that was passed into a function. His the value was a struct that held primitives and pointers (no arrays or buffers). Unsure of how malloc works, he used it similar to how the following was done:
void some_function(int rand_params, SOME_STRUCT_TYPEDEF *ptr){
SOME_STRUCT_TYPEDEF *cpy;
cpy = malloc(sizeof(SOME_STRUCT_TYPEDEF));// this line makes a difference?!?!?
cpy = ptr;// overwrites cpy anyway, right?
//prints a value in the struct documented to be a char*,
//sorry couldn't find the documentation right now
}
I told him that the malloc shouldn't affect the program, so told him to comment it out. To my surprise, the malloc caused a different output (with some intended strings) from the implementation with the malloc commented out (prints our garbage values). The pointer that's passed into the this function is from some other library function which I don't have documentation for at the moment. The best I can assume it that the pointer was for a value that was actually a buffer (that was on the stack). But I still don't see how the malloc can cause such a difference. Could someone explain how that malloc may cause a difference?
I would say that the evident lack of understanding of pointers is responsible for ptr actually pointing to memory that has not been correctly allocated (if at all), and you are experiencing undefined behaviour. The issue is elsewhere in the program, prior to the call to some_function.
As an aside, the correct way to allocate and copy the data is this:
SOME_STRUCT_TYPEDEF *cpy = malloc(sizeof(SOME_STRUCT_TYPEDEF));
if (cpy) {
*cpy = *ptr;
// Don't forget to clean up later
free(cpy);
}
However, unless the structure is giant, it's a bit silly to do it on the heap when you can do it on the stack like this:
SOME_STRUCT_TYPEDEF cpy = *ptr;
I can't see why there difference in the print.
can you show the print code?
anyway the malloc causes memory leak. you're not supposed to allocate memory for 'cpy' because pointer assignment is not shallow-copy, you simply make 'cpy' point to same memory 'ptr' point by storing the address of the start of that memory in 'cpy' (cpy is mostly a 32/64 bit value that store address, in case of malloc, it will store the address of the memory section you allocated)

Freeing pointers from inside other functions in C

Consider the c code:
void mycode() {
MyType* p = malloc(sizeof(MyType));
/* set the values for p and do some stuff with it */
cleanup(p);
}
void cleanup(MyType* pointer) {
free(pointer);
pointer = NULL;
}
Am I wrong in thinking that after cleanup(p); is called, the contents of p should now be NULL? Will cleanup(MyType* pointer) properly free the memory allocation?
I am coding my college assignment and finding that the debugger is still showing the pointer to have a memory address instead of 0x0 (or NULL) as I expect.
I am finding the memory management in C to be very complicated (I hope that's not just me). can any shed some light onto what's happening?
Yes that will free the memory correctly.
pointer inside the cleanup function is a local variable; a copy of the value passed in stored locally for just that function.
This might add to your confusion, but you can adjust the value of the variable p (which is local to the mycode method) from inside the cleanup method like so:
void cleanup(MyType** pointer) {
free(*pointer);
*pointer = NULL;
}
In this case, pointer stores the address of the pointer. By dereferencing that, you can change the value stored at that address. And you would call the cleanup method like so:
cleanup(&p);
(That is, you want to pass the address of the pointer, not a copy of its value.)
I will note that it is usually good practice to deal with allocation and deallocation on the same logical 'level' of the software - i.e. don't make it the callers responsibility to allocate memory and then free it inside functions. Keep it consistent and on the same level.
cleanup will properly free p, but it won't change its value. C is a pass-by-value language, so you can't change the caller's variable from the called function. If you want to set p from cleanup, you'll need to do something like:
void cleanup(MyType **pointer) {
free(*pointer);
*pointer = NULL;
}
And call it like:
cleanup(&p);
Your code is a little bit un-idiomatic, can you explain a bit better why you want to write this cleanup function?
Yes
Yes
Yes: There is a block of memory magically produced by malloc(3). You have assigned the address of this memory, but not the memory itself in any meaningful way, to the pointer p which is an auto variable in mycode().
Then, you pass p to cleanup(), by value, which will copy the pointer and, using the copy local to cleanup(), free the block. cleanup() then sets it's own instance of the pointer to NULL, but this is useless. Once the function is complete the parameter pointer ceases to exist.
Back in mycode(), you still have pointer p holding an address, but the block is now on the free list and not terribly useful for storage until allocated again.
You may notice that you can even still store to and read back from *p, but various amounts of downstream lossage will occur, as this block of memory now belongs to the library and you may corrupt its data structures or the data of a future owner of a malloc() block.
Carefully reading about C can give you an abstract idea of variable lifetime, but it's far easier to visualize the near-universal (for compiled languages, anyway) implementation of parameter passing and local variable allocation as stack operations. It helps to take an assembly course before the C course.
This won't work as the pointer in cleanup() is local, and thus assigning it NULL is not seen by the calling function. There are two common ways of solving this.
Instead of sending cleanup the pointer, send it a pointer to the pointer. Thus change cleanup() as follows:
void cleanup(MyType** pointer)
{
free(*pointer);
*pointer = NULL;
}
and then just call cleanup(&p).
A second option which is quite common is to use a #define macro that frees the memory and cleans the pointer.
If you are using C++ then there is a third way by defining cleanup() as:
void cleanup(MyType& *pointer)
{
// your old code stays the same
}
There are two questions are here:
Am I wrong in thinking that after
cleanup(p); is called, the contents of
p should now be NULL?
Yes, this is wrong. After calling free the memory pointed by the pointer is deallocated. That doesn't mean that the content pointed by the pointer is set to NULL. Also, if you are expecting the pointer p to become NULL in mycode it doesn't happen because you are passing copy of p to cleanup. If you want p to be NULL in mycode, then you need a pointer to pointer in cleanup, i.e. the cleanup signature would be cleanup(MyType**).
Second question:
Will cleanup(MyType* pointer) properly
free the memory allocation?
Yes, since you are doing free on a pointer returned by malloc the memory will be freed.
It's not just you.
cleanup() will properly clean up your allocation, but will not set the pointer to NULL (which should IMHO be regarded as separate from cleanup.) The data the pointer points to is passed to cleanup() by pointer, and is free()ed properly, but the pointer itself is passed by value, so when you set it to NULL you're only affecting the cleanup() function's local copy of the pointer, not the original pointer.
There are three ways around this:
Use a pointer to a pointer.
void cleanup(struct MyType **p) { free(*p); *p = NULL; }
Use a macro.
#define cleanup(p) do { free(p); p = NULL; } while(0)
or (probably better):
void cleanup_func(struct MyType *p) { /* more complicated cleanup */ }
#define cleanup(p) do { cleanup_func(p); p = NULL; } while(0)
Leave the responsibility of setting pointers to NULL to the caller. This can avoid unnecessary assignments and code clutter or breakage.

Resources