Dynamic allocation and procedures - c

I don't understand why this first version of my code is working and the second isn't.
First version :
#include <stdio.h>
#include <stdlib.h>
void procedure(int *t){
t = (int*)realloc(t, 4*sizeof(int));
t[3] = 4;
}
int main()
{
int *var;
var = (int*)malloc(sizeof(int));
procedure(var);
printf("%d\n\n", var[3]);
}
Second version:
#include <stdio.h>
#include <stdlib.h>
void procedure(int *t){
t = (int*)malloc(4*sizeof(int));
t[3] = 4;
}
int main()
{
int *var = NULL;
procedure(var);
printf("%d\n\n", var[3]);
}
In the second version, var is still a NULL pointer after the procedure execution. Why?

In the second version of your code, you are simply passing the address var points to. In procedure(...), you have, in essence, declared an int-pointer and on the first line (the malloc line), you are assigning that pointer a value. var is not updated with this value, because var is a separate entity entirely.
Essentially, you might as well be doing the following:
int *var = NULL;
int *t = malloc(4*sizeof(int));
t[3]=4;
printf("%d\n\n", var[3]);
var is never reassigned to anything, so var will always be null.
This can be corrected, though, like so:
#include <stdio.h>
#include <stdlib.h>
void procedure(int **t){
*t = malloc(4*sizeof(int));
(*t)[3] = 4;
}
int main()
{
int *var = NULL;
procedure(&var);
printf("%d\n\n", var[3]);
}
You can view this working at: https://ideone.com/aTY9Ok
EDIT: Also, it is worth noting that you should be doing the same thing in your first version because realloc(...) might return a different address than var which could lead to a memory leak.

You should remember that everything in C is passed by value, even pointers. So let's start with the second example.
You set var in main to NULL. Then you copy the address in it (NULL) to the varaible t in procedure. You proceed to malloc memory and assign that address to t. But t is just a copy of var, and any change to t is not reflected in var. Outside of procedure, the pointer retains the NULL address and the call to printf with var[3] is undefined behavior.
The second case features the same symptoms, but with a twist. realloc doesn't have to return a different address. It's memory allocator aware, so if it can just "extend" the block of memory being pointed to, it will. That's what you see happening. The call to realloc extends the memory and returns the same address it was given. So by sheer coincidence, t and var end up pointing to the same location, still.
That's why the modification to t[3] is visible using var[3]. This is not a behavior you can rely on.

Let's take it step by step here.
int *t means the "address of t", meaning that it is simply a number
Passing any number into a function means you are COPYING that data into that function (NOT LINKING IT)
Which means that number can change inside the function, but not outside (because it is a copy)
Even though t is a pointer, that pointer is still a number... setting equal to something else (ie. t = (int*)malloc(4*sizeof(int));) does not mean the value of var changed. (Because again, t is a copy of var)

If to read the description of the function realloc in the C Standard then you will know that
Returns 4
The realloc function returns a pointer to the new object
(which may have the same value as a pointer to the old object), or
a null pointer if the new object could not be allocated.
So in the first case it occured such a way that the value of the pointer was not changed. Though to rely on this results in undefined behavior.
In the second case when the standard function malloc was used the new extent with a different address was allocated. So the original pointer does not points to the new extent of memory because it was passed to the function by value.
Thus in the both cases the original pointer was not changed. The difference is that in the first case the system can just enlarge the memory extent keeping its original address unchanged while in the second case the system allocates a new extent with a different address.

Related

Returning an array from function in C

I've written a function that returns an array whilst I know that I should return a dynamically allocated pointer instead, but still I wanted to know what happens when I am returning an array declared locally inside a function (without declaring it as static), and I got surprised when I noticed that the memory of the internal array in my function wasn't deallocated, and I got my array back to main.
The main:
int main()
{
int* arr_p;
arr_p = demo(10);
return 0;
}
And the function:
int* demo(int i)
{
int arr[10] = { 0 };
for (int i = 0; i < 10; i++)
{
arr[i] = i;
}
return arr;
}
When I dereference arr_p I can see the 0-9 integers set in the demo function.
Two questions:
How come when I examined arr_p I saw that its address is the same as arr which is in the demo function?
How come demo_p is pointing to data which is not deallocated (the 0-9 numbers) already in demo? I expected that arr inside demo will be deallocated as we got out of demo scope.
One of the things you have to be careful of when programming is to pay good attention to what the rules say, and not just to what seems to work. The rules say you're not supposed to return a pointer to a locally-allocated array, and that's a real, true rule.
If you don't get an error when you write a program that returns a pointer to a locally-allocated array, that doesn't mean it was okay. (Although, it means you really ought to get a newer compiler, because any decent, modern compiler will warn about this.)
If you write a program that returns a pointer to a locally-allocated array and it seems to work, that doesn't mean it was okay, either. Be really careful about this: In general, in programming, but especially in C, seeming to work is not proof that your program is okay. What you really want is for your program to work for the right reasons.
Suppose you rent an apartment. Suppose, when your lease is up, and you move out, your landlord does not collect your key from you, but does not change the lock, either. Suppose, a few days later, you realize you forgot something in the back of one closet. Suppose, without asking, you sneak back to try to collect it. What happens next?
As it happens, your key still works in the lock. Is this a total surprise, or mildly unexpected, or guaranteed to work?
As it happens, your forgotten item still is in the closet. It has not yet been cleared out. Is this a total surprise, or mildly unexpected, or guaranteed to happen?
In the end, neither your old landlord, nor the police, accost you for this act of trespass. Once more, is this a total surprise, or mildly unexpected, or just about completely expected?
What you need to know is that, in C, reusing memory you're no longer allowed to use is just about exactly analogous to sneaking back in to an apartment you're no longer renting. It might work, or it might not. Your stuff might still be there, or it might not. You might get in trouble, or you might not. There's no way to predict what will happen, and there's no (valid) conclusion you can draw from whatever does or doesn't happen.
Returning to your program: local variables like arr are usually stored on the call stack, meaning they're still there even after the function returns, and probably won't be overwritten until the next function gets called and uses that zone on the stack for its own purposes (and maybe not even then). So if you return a pointer to locally-allocated memory, and dereference that pointer right away (before calling any other function), it's at least somewhat likely to "work". This is, again, analogous to the apartment situation: if no one else has moved in yet, it's likely that your forgotten item will still be there. But it's obviously not something you can ever depend on.
arr is a local variable in demo that will get destroyed when you return from the function. Since you return a pointer to that variable, the pointer is said to be dangling. Dereferencing the pointer makes your program have undefined behavior.
One way to fix it is to malloc (memory allocate) the memory you need.
Example:
#include <stdio.h>
#include <stdlib.h>
int* demo(int n) {
int* arr = malloc(sizeof(*arr) * n); // allocate
for (int i = 0; i < n; i++) {
arr[i] = i;
}
return arr;
}
int main() {
int* arr_p;
arr_p = demo(10);
printf("%d\n", arr_p[9]);
free(arr_p) // free the allocated memory
}
Output:
9
How come demo_p is pointing to data which is not deallocated (the 0-9 numbers) already in demo? I expected that arr inside demo will be deallocated as we got out of demo scope.
The life of the arr object has ended and reading the memory addresses previously occupied by arr makes your program have undefined behavior. You may be able to see the old data or the program may crash - or do something completely different. Anything can happen.
… I noticed that the memory of the internal array in my function wasn't deallocated…
Deallocation of memory is not something you can notice or observe, except by looking at the data that records memory reservations (in this case, the stack pointer). When memory is reserved or released, that is just a bookkeeping process about what memory is available or not available. Releasing memory does not necessarily erase memory or immediately reuse it for another purpose. Looking at the memory does not necessarily tell you whether it is in use or not.
When int arr[10] = { 0 }; appears inside a function, it defines an array that is allocated automatically when the function starts executing (or at certain times within the function execution if the definition is in some nested scope). This is commonly done by adjusting the stack pointer. In common systems, programs have a region of memory called the stack, and a stack pointer contains an address that marks the end of the portion of the stack that is currently reserved for use. When a function starts executing, the stack pointer is changed to reserve more memory for that function’s data. When execution of the function ends, the stack pointer is changed to release that memory.
If you keep a pointer to that memory (how you can do that is another matter, discussed below), you will not “notice” or “observe” any change to that memory immediately after the function returns. That is why you see the value of arr_p is the address that arr had, and it is why you see the old data in that memory.
If you call some other function, the stack pointer will be adjusted for the new function, that function will generally use the memory for its own purposes, and then the contents of that memory will have changed. The data you had in arr will be gone. A common example of this that beginners happen across is:
int main(void)
{
int *p = demo(10);
// p points to where arr started, and arr’s data is still there.
printf("arr[3] = %d.\n", p[3]);
// To execute this call, the program loads data from p[3]. Since it has
// not changed, 3 is loaded. This is passed to printf.
// Then printf prints “arr[3] = 3.\n”. In doing this, it uses memory
// on the stack. This changes the data in the memory that p points to.
printf("arr[3] = %d.\n", p[3]);
// When we try the same call again, the program loads data from p[3],
// but it has been changed, so something different is printed. Two
// different things are printed by the same printf statement even
// though there is no visible code changing p[3].
}
Going back to how you can have a copy of a pointer to memory, compilers follow rules that are specified abstractly in the C standard. The C standard defines an abstract lifetime of the array arr in demo and says that lifetime ends when the function returns. It further says the value of a pointer becomes indeterminate when the lifetime of the object it points to ends.
If your compiler is simplistically generating code, as it does when you compile using GCC with -O0 to turn off optimization, it typically keeps the address in p and you will see the behaviors described above. But, if you turn optimization on and compile more complicated programs, the compiler seeks to optimize the code it generates. Instead of mechanically generating assembly code, it tries to find the “best” code that performs the defined behavior of your program. If you use a pointer with indeterminate value or try to access an object whose lifetime has ended, there is no defined behavior of your program, so optimization by the compiler can produce results that are unexpected by new programmers.
As you know dear, the existence of a variable declared in the local function is within that local scope only. Once the required task is done the function terminates and the local variable is destroyed afterwards. As you are trying to return a pointer from demo() function ,but the thing is the array to which the pointer points to will get destroyed once we come out of demo(). So indeed you are trying to return a dangling pointer which is pointing to de-allocated memory. But our rule suggests us to avoid dangling pointer at any cost.
So you can avoid it by re-initializing it after freeing memory using free(). Either you can also allocate some contiguous block of memory using malloc() or you can declare your array in demo() as static array. This will store the allocated memory constant also when the local function exits successfully.
Thank You Dear..
#include<stdio.h>
#define N 10
int demo();
int main()
{
int* arr_p;
arr_p = demo();
printf("%d\n", *(arr_p+3));
}
int* demo()
{
static int arr[N];
for(i=0;i<N;i++)
{
arr[i] = i;
}
return arr;
}
OUTPUT : 3
Or you can also write as......
#include <stdio.h>
#include <stdlib.h>
#define N 10
int* demo() {
int* arr = (int*)malloc(sizeof(arr) * N);
for(int i = 0; i < N; i++)
{
arr[i]=i;
}
return arr;
}
int main()
{
int* arr_p;
arr_p = demo();
printf("%d\n", *(arr_p+3));
free(arr_p);
return 0;
}
OUTPUT : 3
Had the similar situation when i have been trying to return char array from the function. But i always needed an array of a fixed size.
Solved this by declaring a struct with a fixed size char array in it and returning that struct from the function:
#include <time.h>
typedef struct TimeStamp
{
char Char[9];
} TimeStamp;
TimeStamp GetTimeStamp()
{
time_t CurrentCalendarTime;
time(&CurrentCalendarTime);
struct tm* LocalTime = localtime(&CurrentCalendarTime);
TimeStamp Time = { 0 };
strftime(Time.Char, 9, "%H:%M:%S", LocalTime);
return Time;
}

When writing a function that returns pointer, why should I allocate memory to the pointer I'm going to return?

I'm a bit weak when it comes to memory allocation and pointers.
So, I want to understand why do I have to allocate memory to pointers in functions as follow:
char *cstring(char c, int n)
{
int i = 0;
char * res;
res = malloc ((n+1)*sizeof(char));
while (i<n)
{
res[i]=c;
i++;
}
res[i] ='\0';
return res;
}
and why is the following not valid?
char *cstring(char c, int n)
{
int i = 0;
char * res;
while (i<n)
{
res[i]=c;
i++;
}
res[i] ='\0';
return res;
}
I understand that I should allocate memory (generally) to pointers so that they have defined memory.
However, I want to mainly understand how is it related to the concept of stack and heap memories!
Thanks in advance!
Pointers need to point to a valid memory location before they can be dereferenced.
In your first example, res is made to point at a block of allocated memory which can subsequently be written to and read from.
In your second example, res remains uninitialized when you attempt to dereference it. This causes undefined behavior. The most likely outcome in this case is that whatever garbage value it happens to contain will not be a valid memory address, so when you attempt to dereference that invalid address your program will crash.
If you declare a variable like that,
int A = 5;
then that means the variable will be on the stack. When functions are called, their local variables are pushed to the stack. The main function is also an example of that. So you don't have to allocate memory manually, your compiler will do this for you in the background before it calls your main function. And that also means if you examine the stack during the execution of the function you can see the value 5.
With this,
int A = 5;
int *PtrToA = &A;
The pointer will be on the stack again. But this time, the value on the stack just shows the memory address of the actual integer value we want. It points to the address of the memory block that holds the value 5. Since A is held in the stack here, pointer will show a memory address on the stack.
Like the case in your question you can allocate memory dynamically. But you have to initialize it before you read it. Because when you request to allocate the memory, your operating system searches for a valid memory field in your programs heap and reserves that for you. Than it gives you back its adddress and gives you the read write permissions so you can use it. But the values in it won't contain what you want. When compiler allocates on stack, the initial values will be unset again. If you do this,
char *res;
res[1] = 3;
variable res will be on the stack and it will contain some random value. So accessing it is just like that,
(rand())[1] = 3;
You can get an access violation error because you may not have permission to write to that memory location.
An important note; after your function call returns, values of local variables on the stack are no more valid. So be careful with that. Do not dereference them after the function call ends.
In conclusion; if you want to use a pointer, be sure it points to a valid memory location. You can allocate it yourself or make it point another memory address.
The second version of your code declares a pointer, but does not initialize it to point to a valid memory address.
Then, the code dereferences that pointer -- during the loop. So, your code would access uninitialized memory in this case. Remember, array indexing is just syntactic sugar for dereferencing -- so your code accesses memory its not supposed to.
The first version of your code initializes the pointer to actually point to something, and hence when you dereference it during the loop, it works.
Of course, in either case, you return the pointer from the function -- its just that in the first version it points to something valid, whereas in the second version it points anywhere.
The moral here is to always initialize your variables. Not doing so could result in undefined behavior in your code (even if it appears to work sometimes). The general advice here is to always compile your code using at least some compilation flags. For example in gcc/clang, consider -Wall -Werror -Wextra. Such options often pick up on simple cases of not initializing variables.
Also, valgrind is a brilliant tool for memory profiling. It can easily detect uses of uninitialized memory at runtime, and also memory leaks.
Simple: because you do not have any allocated memory for the data you wite. In your example you define pointer, you do not initialize it so it will reference random (or rather not possible to predict) place in the memory, then you try to write to this random memory location.
You have 2 Undefined Behaviours here in 5 lines example. Your pointer is not initialized, and you did not allocate any valid memory this pointer to reference.
EDIT:
VALID
char *cstring(char c, int n)
{
char * res;
res = malloc ((n+1)*sizeof(char));
char *cstring(char c, int n)
{
char * res;
static char buff[somesize];
res = buff;
char buff[somesize];
char *cstring(char c, int n)
{
char * res;
res = buff;
INVALID
char *cstring(char c, int n)
{
char * res;
char buff[somesize];
res = buff;

How is it possible to access a functions variable outside the function?

I've been told at my university that everything is put on the top of the "stack" when working with a function. So, when returning from one, the top of the stack is removed, until we reach the bottom - main(). Suggesting that everything is lost we have made in the local scope of the previous functions.
Most books tell me the same thing.
However, i have come across a number of occurrences, where i used this exact feature.
For instance:
void address (bool** xpp)
{
bool* y = (bool*) malloc(10*sizeof(bool));
y[2] = false;
**xpp = &y;
}
int main(void)
{
bool* x;
bool** xp = &x;
address(&xp);
xp[0] = false;
xp[2] = false;
xp[7] = false;
printf("%d", xp[0]);
printf("%d", xp[2]);
printf("%d", xp[7]);
return 0;
}
In this case, to my understanding, i should not be able to refer to the xp[] array in the main() after address(), because, indeed i have set it's pointer to an arrays first elements pointer, but after returning to main() the array i had created in address() is supposed to be gone. So it should be pointing to nowhere and should pop up an exception.
However, all of the bool xp elements print '0', implying it's success in working.
Well, there are two different answers here. Your question boils down to, "I heard that local variables are lost when they're popped from the stack, but I tried it, and they were still there", but your actual code does not demonstrate the use of local variables on the stack that would be lost; it demonstrates the use of malloc, which is completely different.
And then the second answer is, any time you ask anything like "I heard that X doesn't work, but I tried it, and it worked", you're playing with fire: it might have seemed to have worked, but it wasn't guaranteed to.
Let's look at a slightly different version of your program. Instead of playing with pointers to pointers, I'm just going to have the address function return a pointer to the first element of an array. And instead of an array of bools, I'm going to use an array of int, so I can more easily show interesting numbers. Here's the first version of the code:
#include <stdio.h>
#include <stdlib.h>
int *address()
{
int *p = malloc(5 * sizeof(int));
if(p == NULL) abort();
p[0] = 1; p[1] = 2; p[2] = 3; p[3] = 4; p[4] = 5;
return p;
}
int main()
{
int *a = address();
int i, sum = 0;
for(i = 0; i < 5; i++) sum += a[i];
printf("sum = %d\n", sum);
for(i = 0; i < 5; i++) printf("a[%d] = %d\n", i, a[i]);
}
Function address returns a pointer, but it's a pointer to dynamically-allocated memory, which is guaranteed to stick around even after address returns. The program prints
sum = 15
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
a[4] = 5
which is just what you would expect.
But now let's change function address to not call malloc, but instead, use a local array:
int *address()
{
int la[5];
la[0] = 1; la[1] = 2; la[2] = 3; la[3] = 4; la[4] = 5;
return la;
}
This function is broken. It returns a pointer to the first element of a local array. By the time the function returns to its caller, that array will no longer exist. The pointer can never be useful to its caller; it is virtually guaranteed not to work. Indeed, when I compile this second version, my compiler warns me about it:
warning: address of stack memory associated with local variable 'a' returned
But if Ignore that warning and run the resulting program anyway, here's what I get:
sum = 15
a[0] = 507402241
a[1] = -16764064
a[2] = 0
a[3] = 0
a[4] = 0
This is a very interesting result. The second thing to notice is that the contents of the array are all wrong. We don't see 1, 2, 3, 4, 5; we see some numbers that are clearly garbage. But this was to be expected, because that array la in function address is gone.
But the first and perhaps more interesting thing to notice is that the sum is correct! How did that happen? And the sum doesn't match the contents of the array as printed! It's as if the "broken" pointer returned by the address function worked for a little while, just long enough to compute the "correct" sum, but got trashed later. And, in fact, that's exactly what happened.
After function address returns, the array la is "gone", but the memory on the stack that it was using hasn't been reused or erased yet, so the bit patterns are still there. So the calling function, main, can try to access those bits, and it even seems to get the right answer -- it computes the same sum, 15. It's important to note that this is absolutely not guaranteed to work; you would never want to depend on it in a real program -- it just happens to work.
But then, having computed the sum, main calls printf to print it out. And printf is a function that gets called -- a big, complicated function -- and it does all sorts of stuff, and allocates all sorts of its own variables on the stack. So that's when the stack memory that had been allocated to the la array actually gets overwritten. So that's why, when the last half of the main function tries to print out the array, it's garbage.
There's another point to make and that has to do with addresses. When we worry about the local array la getting lost or not, there are two questions to ask: do we lose the contents of the array, and, do we lose the pointer to the array? And in answering those questions, we encounter a significant fact: a function can still, perfectly well, return a value, even though the function's local (stack) storage has gone away.
To see this, consider the function
int five()
{
int r = 5;
return r;
}
When function five returns, its local variable r goes away. But the caller who says
int x = five();
has no problem, because as function five returns, and even as function fives local variable r is being allocated, the return value 5 is being copied into the caller's own variable x, so it's not lost.
But with all of that said -- and besides the question of whether the array is a local (stack) array or allocated with malloc -- there's also something wrong, sort of differently wrong, with he way you're taking y's address. y is a local variable, so after the function exits, &y is bogus, and not guaranteed to work, no matter where you've stashed it. (But, again, it might seem to work, for a little while, until something else overwrites the stack.)
How is it possible to access a functions variable outside the function?
Assuming it's not declared static you simply cannot, for the reason you mentioned: It's gone the moment the function had been left.
after returning to main() the array i had created in address() is supposed to be gone.
The call to malloc did not create a "variable", but it allocated memory from the heap. All that is stored locally inside the function's variable y is the address of this very block of memory. This address indeed is lost when y goes away by leaving the function.
To not lose the address of the memory allocated fix the code for example like this:
#include <stdlib.h> /* for malloc() */
#include <stdio.h> /* for printf() */
void address (bool** xpp)
{
bool* y = malloc(10*sizeof(bool));
y[2] = false;
*xpp = y;
}
int main(void)
{
bool* xp;
address(&xp);
xp[0] = false;
xp[2] = false;
xp[7] = false;
printf("%d", xp[0]);
printf("%d", xp[2]);
printf("%d", xp[7]);
return 0;
}
A major flaw still with this code is, that the caller (main) and the callee (address) do not "talk" about how much memory has to be/was allocate.
Almost everything about this code is misleading.
The question is, "How can the xp pointer be valid after function address returns? But it turns out that the call to address does not modify the xp pointer.
xp is set to point to x. The call to address doesn't change that. (The call to address does end up changing what xp points to, that is, it changes x.
Although xp is not a pointer to bool, it's used as if it were, in the three assignments
xp[0] = false;
xp[2] = false;
xp[7] = false;
Although xp doesn't actually point to memory that's been allocated to hold 10 bools, wherever it does point (that is, somewhere on the stack surrounding x), there's evidently enough memory to accidentally store 10 bools without causing too much damage.
And then, having stored a few bools at wherever-it-is, trying to print those three bools back out (from wherever-it-was) happens to work.
For answers to the question of how the local storage in a function can still be accessed (though incorrectly) after the function returns -- and although this code doesn't actually end up doing that -- see my other answer.
For the record, there are other problems. The call
address(&xp);
is a type mismatch (&xpp is a pointer-to-pointer-to-pointer-to-bool, but address() accepts a pointer-to-pointer-to-bool). The line
**xpp = &y;
is a type mismatch (&y is a pointer-to-pointer-to=-bool, but **xpp is a bool). Lines like
xp[0] = false;
are a type mismatch (false is a bool, but xp[0] is a pointer-to-bool). Finally, lines like
printf("%d", xp[0]);
are a type mismatch (xp[0] is a pointer-tobool, but %d expects an int, or maybe a bool).

Difference between passing argument like *mode1 or **mode2

I do not quite understand the difference between passing to a function *mode1 or **mode2.
I wrote some examples. (note: type can be any type)
[Code 1]
#include <stdio.h>
void function (type *vet)
{
/* other */
}
int main ()
{
type *vet;
function (vet)
/* other */
return 0;
}
[Code 2]
#include <stdio.h>
void function (type **vet)
{
/* other */
}
int main ()
{
type *vet;
function (&vet)
/* other */
return 0;
}
I know: in the first case is a pointer, in the second case is a pointer to a pointer. But why for example in the second case if I pass &vet can I allocate memory in function() and free it in main() and in the first one not?
I search someone who explain me the differences well. What can I do in the two cases? How and where to malloc or realloc? And free? And modify vet in the function?
Original questions
The main (most significant) difference is whether the value in the calling function can be changed.
In the first example, the called function gets a copy of the pointer in the calling code, and cannot modify the pointer in the calling code.
In the second example, the called function gets a pointer to the pointer, and by assigning to *vet in the called function, you can modify the value in the called function.
Why in the second case if I pass &vet can I allocate memory in function() and free it in main() and in the first one not?
In the second case, the code in function() can modify the actual pointer in main(), so the value of vet in main() ends up with the allocated pointer value, which can therefore be freed. In the first case, the value in main() is not modified by the called function, so the data can't be freed by main().
How and where to malloc or realloc? And free?
In the first case, you can use malloc() or realloc() in the function, but you should also free the allocated memory before return unless your code stores the value in a global variable (in which case you can delegate to some other code to handle the free(), but it had better be very clear which code has the responsibility, and in any case using global variables is probably not a good idea). Or unless you change the function signature and return a pointer to the allocated data which should be freed by the calling code.
In the second case, you can allocate or reallocate memory in the called function and leave it allocated to be used by other functions and to be freed by the calling function.
And modify vet in the function?
In both functions, you can modify the local vet variable as you see fit; this is true of any parameter to any function. What you can't necessarily do is modify values in the calling function; you have to have a pointer to value in the calling function to do that. In the first function, you can't change the value of vet in main(); in the second, you can. In both functions, you can change what vet points at. (One minor problem is the conflation of the name vet in the three contexts — the main() and the two different functions. The name vet in the two functions points at different types of things.)
Extension questions
But is it freed in function() like, for example, this?
#include <stdio.h>
#define NUM (10)
struct example
{
/* ... */
}
void dealloc (struct example *pointer)
{
free (pointer);
}
int main()
{
struct example *e;
e = malloc (NUM * sizeof(struct example));
if (e == NULL)
return -1;
struct example *e_copy = e;
dealloc (e_copy);
return 0;
}
This code is legitimate. You pass (a copy of) the value of the pointer to the dealloc() function; it passes that pointer to free() which releases the allocated memory. After dealloc() returns, the pointer values in e and e_copy are the same as before, but they no longer point to allocated memory and any use of the value leads to undefined behaviour. A new value could be assigned to them; the old value cannot be dereferenced reliably.
And what is the difference from this?
#include <stdio.h>
#define NUM (10)
struct example
{
/* ... */
}
int main()
{
struct example *e;
e = malloc (NUM * sizeof(struct example));
if (e == NULL)
return -1;
struct example *e_copy = e;
free (e_copy);
return 0;
}
The difference between this example and the last is that you call free() directly in main(), rather than from a function dealloc().
What would make a difference is:
void dealloc(struct example **eptr)
{
free(*eptr);
*eptr = 0;
}
int main()
{
...
dealloc(&e_copy);
return 0;
}
In this case, after dealloc() returns, e_copy is a null pointer. You could pass it to free() again because freeing the null pointer is a no-op. Freeing a non-null pointer twice is undefined behaviour — it generally leads to problems and should be avoided at all costs. Note that even now, e contains the pointer that was originally returned by malloc(); but any use of that pointer value leads to undefined behaviour again (but setting e = 0; or e = NULL; or e = e_copy; is fine, and using e = malloc(sizeof(struct example)); or such like also works.
As you said, the argument in the first case is a pointer, and a copy of the pointer vet is passed. We can modify the value that vet pointed to (e.g., *vet = new value). But we cannot modify the value of the pointer vet because it is just a copy of the original vet pointer. Therefore, after first function, value of *vet may be changed, but value of vet will not.
So how could we modify the value of the pointer vet? We use the pointer to pointer. In the second function, we can allocate memory for *vet, and this modified value will be kept after the second function. So we can free it in main.
We cannot do this in first case because if we try to allocate memory in function, we just allocate memory for the copy of the pointer vet, not the original vet.
You are correct in your understanding that type *var; is a pointer to data of type and type **var; is a pointer to a pointer to data of type.
The difference you asked about, allocating memory in the function and keeping track of it, is because of the ability to assign the value to the pointer.
In C, any time you want to modify a value in a function, you must provide it a pointer the data it is to modify.
If you want to allocate memory, you must know where it is in order to use it, and later free it. If you pass only a pointer to a function, and allocate memory to it, it cannot change the value of the pointer it is passed (rather, when your program returns to the function that called this allocation function, the stack will have unloaded the address you needed); it can only read from it (which in this use is rather pointless).
Consider this, the pointer variable
type *vet;
is created on the stack of function
main()
when "function_1()" is called from main, a stack for this new function is created. Any argument passed to this function is saved on the stack of this function. In this case, the argument is a pointer variable. Now function_1() can very well change the value of this pointer variable but as soon as the function returns the stack of this function is released and any changes are lost.
But when you are passing a pointer to pointer, what you pass is actually an address of a pointer variable and not a pointer variable. So when you work on this pointer variable inside the called function, you are actually working on the memory of the stack of the calling function. And since this memory is on the stack of the calling function, any changes made by the calling function will persist even after the stack of the called function is released.
First thing is, there is no garbage collector in C. So if you don't explicitely free an allocated memory block, it will eat up memory until the process exits. That is a mighty source of memory leaks.
So, once you've allocated a memory block using malloc or similar functions, you must keep a pointer to it in order to free it someday.
If you allocate a block within a function and you plan this block to remain useable after function termination, you must pass its value to some higher level piece of code that will eventually free it, long after the function that created it has exited.
To do so, you have three basic choices:
store the pointer in some global variable
return the pointer as the function's result
have one of the function arguments specify where the pointer is to be stored
case 1
void * global_address_of_buffer;
void alloc_a_buffer (int size)
{
global_address_of_buffer = malloc (size); // block reference in global var
}
alloc_a_buffer ();
// ...
free (global_address_of_buffer);
This is clearly impractical. If you call your function twice, you will lose the address of the first buffer.
One of the innumerable illustrations of why using globals will drag you screaming right into hell.
Nevertheless, it's a possibility.
case 2
void * alloc_a_buffer (int size)
{
return malloc (size); // block reference as return value
}
void * new_buffer;
new_buffer = alloc_a_buffer (10); // retrieve pointer through return value
// ...
free (new_buffer);
This is not always possible. For instance you might want all your functions to return a status indicating success or failure, in which case the return value will not be available for your pointer.
case 3
void alloc_a_buffer (int size, void ** buffer)
{
*buffer = malloc (size); // block reference set through 2nd parameter
}
void * new_buffer;
alloc_a_buffer (10, &new_buffer); // pass pointer address to the function
// ...
free (new_buffer);

Does local variable be deleted from memory when this function is called in main [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Can a local variable's memory be accessed outside its scope?
returning address of local variable
I have a question, first of all look at the code
#include <stdio.h>
int sum(); /* function declaration */
int main()
{
int *p2;
p2 = sum(); /* Calling function sum and coping its return type to pointer variable p2 */
printf("%d",*p2);
} /* END of main */ `
int sum()
{
int a = 10;
int *p = &a;
return p;
} /* END of sum */
I think the answer is 10 and address of variable a, but my tesacher says that a is local to the function come so a and its
value will be deleted from the memory location when the function returns or is finished executing. I tried this code and the answer is weel of course 10 and address of a, I use the GNU/GCC compiler. Can anyone say what is right and wrong.
Thanks in advance.
Your teacher is absolutely right: even if you fix your program to return int* in place of int, your program still contains undefined behavior. The issue is that the memory in which a used to be placed is ripe for reuse once sum returns. The memory may stay around untouched for you to access, so you might even print ten, but this behavior is still undefined: it may run on one platform and crash on ten others.
You may get the right result but that is just because you are lucky, by the time the sum() is returned, the memory of a is returned to the system, and it can be used by any other variables, so the value may be changed.
For example:
#include <stdio.h>
int* sum(); /* function declaration */
int* sum2(); /* function declaration */
int main()
{
int *p2;
p2 = sum(); /* Calling function sum and coping its return type to pointer variable p2 */
sum2();
printf("%d",*p2);
}
int* sum()
{
int a = 10;
int *p = &a;
return p;
} /* END of sum */
int* sum2()
{
int a = 100;
int *p = &a;
return p;
} /* END of sum */
With this code, the a will be reused by sum2() thus override the memory value with 100.
Here you just return a pointer to int, suppose you are returning an object:
TestClass* sum()
{
TestClass tc;
TestClass *p = &tc;
return p;
}
Then when you dereference tc, weird things would happen because the memory it points to might be totally screwed.
Your pointer still points to a place in memory where your 10 resides. However, from Cs point of view that memory is unallocated and could be reused. Placing more items on the stack, or allocating memory could cause that part of memory to be reused.
The object a in the function sum has automatic lifetime. It's lifetime will be ended as soon as the scope in which it has been declared in (the function body) is left by the program flow (the return statement at the end of the function).
After that, accessing the memory at which a lived will either do what you expect, summon dragons or set your computer on fire. This is called undefined behavior in C. The C standard itself, however, says nothing about deleting something from memory as it has no concept of memory.
Logically speaking, a no longer exists once sum exits; its lifetime is limited to the scope of the function. Physically speaking, the memory that a occupied is still there and still contains the bit pattern for the value 10, but that memory is now available for something else to use, and may be overwritten before you can use it in main. Your output may be 10, or it may be garbage.
Attempting to access the value of a variable outside that variable's lifetime leads to undefined behavior, meaning the compiler is free to handle the situation any way it wants to. It doesn't have to warn you that you're doing anything hinky, it doesn't have to work the way you expect it to, it doesn't have to work at all.

Resources