accessing variable length array after its memory should have been deallocated - c

I'm currently studying variable length array and automatic storage.
I have the following code that allocate memory for an variable length array myArray inside function vla, and return a pointer to the variable length array from the function.
#include <stdio.h>
int * vla(int n){
int myArray[n];
myArray[0] = 10;
myArray[1] = 11;
int * pointerToInt = myArray;
return pointerToInt;
}
int main(void){
int * pointerToInt = vla(10);
printf("%d, %d", pointerToInt[0], pointerToInt[1]); // prints 10, 11
return 0;
}
I thought that variable length array belong to the automatic storage class (i.e. the memory for the variable length array will be allocated when we enter the function containing the variable length array, and the memory is automatically deallocated after the function exit)
So according to this logic, the memory allocated to myArray variable length array is deallocated after we return from vla method, but how come I can still correctly access the first and second element of the variable length array?
Is this behavior defined? or it is undefined behaviour that just happen to work?

myArray is a stack/auto variable created on the stack memory. Remember memory always exists. It is just owned by different pointers based on allocation and deallocation. The reason why you can still access same values is that the same piece of memory has not been assigned to another pointer and not been overwritten.
To evaluate it. Create another function that allocates same amount from stack but puts different values. Or add arguments in the same function and call it twice with different values. You will then see the difference.
#include <stdio.h>
int * vla(int n, int a, int b){
int myArray[n];
myArray[0] = a;
myArray[1] = b;
int * pointerToInt = myArray;
return pointerToInt;
}
int main(void){
int * pointerToInt = vla(10, 10, 11);
vla(10, 20, 21); // over write stack
printf("%d, %d", pointerToInt[0], pointerToInt[1]); // prints 20, 21
return 0;
}
By the way returning stack memory from vla is not a good idea. Dynamic memory is allocated from heap using malloc family of functions.

You can still correctly access the first and second element of the variable length array because you are assigning base address of the myArray to pointerToInt. Auto variables have a life inside the block only, but in this program we are using pointer to access the data in the memory, as long as that part of stack is not allocated to any other program, we can access that part of stack. If that part of stack is allocated to some other process we will get segmentation fault as we are trying to access unauthorized memory

Related

Memory allocation using for loop

My Doubt is regarding only memory allocation so don't think about program output
#include<stdio.h>
int main(){
for(int i=0;i<20;i++){
char *str=malloc(sizeof(char)*6); //assuming length of each string is 6
scanf("%s",str);
insertinlinkedlist(str);
}
}
whenever i allocate memory here as shown above only the base address of char array will pass to linked list,and that is the memory block allocated for char array is inside main only and i am storing the base address of that array in str which is local to main and is passed to insetinlinkedlist
I want to ask whenever memory is allocated inside loop than why the number of
memory blocks(no of char arrays declared ) are created equal to n (number of time loop runs) since variable name is same we should be directed to same memory location
Note I have checked in compiler by running the loop all the times when loop runs memory the value of str is different
is The above method is correct of allocating memory through loop and through same variable "Is the method ensures that every time we allocate memory in above manner their will be no conflicts while memory allocation and every time we will get the address of unique memory block"
Now above doubt also creates a doubt in my mind
That if we do something like that
int main(){
for(int i=0;i<n;i++){
array[50];
}
}
then it will also create 50 array inside stack frame
malloc returns a pointer to the first allocated byte. Internally it keeps track of how much memory was allocated so it knows how much to free (you do need to insert calls to free() or you'll leak memory, by the way). Usually, it does this by allocating a little bit of memory before the pointer it gives you and storing the length there, however it isn't required to do it that way.
The memory allocated by malloc is not tied to main in any way. Currently main is the only function whose local variables have a pointer to that memory, but you could pass the pointer to another function, and that function would also be able to access the memory. Additionally, when the function that called malloc returns, that memory will remain allocated unless manually freed.
The variable name doesn't matter. A pointer is (to first approximation) just a number. Much like how running int a = 42; a = 20; is permitted and replaces the previous value of a with a new one, int *p = malloc(n); p = malloc(n); will first assign the pointer returned by the first malloc call to p, then will replace it with the return value of the second call. You can also have multiple pointers that point to the same address:
int *a = malloc(42);
int *b = malloc(42);
int *c = a;
a = malloc(42);
At the end of that code, c will be set to the value returned by the first malloc call, and a will have the value returned by the last malloc call. Just like if you'd done:
//assume here that f() returns a different value each time
//it's called, like malloc does
int a = f();
int b = f();
int c = a;
a = f();
As for the second part of your question:
for(int i=0;i<n;i++){
int array[50];
}
The above code will create an array with enough space for 50 ints inside the current stack frame. It will be local to the block within the for loop, and won't persist between iterations, so it won't create n separate copies of the array. Since arrays declared this way are part of the local stack frame, you don't need to manually free them; they will cease to exist when you exit that block. But you could pass a pointer to that array to another function, and it would be valid as long as you haven't exited the block. So the following code...
int sum(int *arr, size_t n) {
int count = 0;
for (size_t i = 0; i < n; i++) {
count += arr[i];
}
return count;
}
for(int i=0;i<n;i++){
int array[50];
printf("%d\n", sum(array, 50));
}
...would be legal (from a memory-management perspective, anyway; you never initialize the array, so the result of the sum call is not defined).
As a minor side note, sizeof(char) is defined to be 1. You can just say malloc(6) in this case. sizeof is necessary when allocating an array of a larger type.

The last value of an array of array of ints overrides all other values

I'm trying to store 4 arrays in an array, and for some reason, the last value keeps overriding the previous three values. For example, if 123; 456; 789; 987 were inputted into the code below, ipadr[0] - ipadr[4] would all only store 123. I've tested to make sure that numConvert() is working, and within numConvert, 4 different arrays of ints are returned, but only numConvert(d) is the ipadr array (stored 4 times).
Also, is my syntax / code correct in order for this function to return ipadr as an array of arrays (int**)? Why do you need to make it static int* when initializing the array?
I'm new to C and this has been really frustrating me. Any help would be incredibly appreciated. Thank you in advance!!
int** ipConvert(int a, int b, int c, int d){
static int* ipadr[4];
ipadr[0]=numConvert(a);
ipadr[1]=numConvert(b);
ipadr[2]=numConvert(c);
ipadr[3]=numConvert(d);
return ipadr;
}
numConvert code:
int* numConvert(int dec) {
static int hold[8];
...
return hold;
}
The hold array is indeed overwritten after each call to numConvert, because it is a static area of 8 int.
Better use dynamic allocation with malloc, and have that function allocate 8 ints.
int* numConvert(int dec) {
int *hold = (int *)malloc(sizeof(int) * 8); // C++ need cast!
int x = dec;
for(int y=7;y>=0;y--){
if(x%2==0 || x==0){
hold[y]=0;
}
else{
hold[y]=1;
}
x=x/2;
}
printf("\ntest loop: ");
for(int i=0;i<8;i++){
printf("%i", hold[i]);
}
printf("\n");
return hold;
}
then the returned values will have to be freed, after you don't need them anymore.
As for static, this answer explains it in details.
Every time you write something in hold then return it, you basically overwrite the previous value. There is single instance of hold not multiple as you may be thinking.
static keyword you have used without knowing the full functionality. It is not the same as automatic storage duration.
int* numConvert(int dec) {
int *hold = malloc(sizeof *hold *8);
if( hold == NULL){
fprintf(stderr,"Error in malloc");
exit(1);
}
int x = dec;
....
....
return hold;
}
Free the dynamically allocated memory when you are done working with it.
What have we done here?
Dynamically allocated memory has lifetime beyond the scope of the function. So just like the static one it stays alive. But with contrary to the static variable each time a new chunk of memory is allocated. And for that we are not overwriting anything, which was the primary problem in your case.
One thing more..
hold is of automatic storage duration meaning every time we exit the function the hold is deallocated and then again when we call it we get to have a local variable named hold. So in each we get different instance. And that's why we return the address contained in hold. This memory whose address hold contains has lifetime beyond the scope of the function. So it stays unlike the local variable hold and we store this address in other function.
Declare your hold variable as instance variable rather then static variable like
int* numConvert(int dec) {
int hold[8];

Returning an array from a function in C: Segmentation Fault [duplicate]

This question already has answers here:
How is the array stored in memory?
(4 answers)
How to access a local variable from a different function using pointers?
(10 answers)
Closed 6 years ago.
I am trying to implement a simple program using a header file where a function in the header file accepts an int array and returns an int array too.
In header.h:
int* point(int a[]);
In header.c:
#include<stdio.h>
#include "header.h"
int* point(int a[])
{
printf("In the point function\n");
int array[4],i;
for(int i=0;i<4;i++)
{
printf("%dth Iteration\n",i);
array[i]=a[i];
}
return array;
}
In test.c:
#include<stdio.h>
#include "header.h"
void main()
{
int *array,i;
int a[]={1,2,3,4};
printf("calling point function\n");
array=point(a);
printf("Back in the main function\n");
for(i=0;i<4;i++)
{
//SEGMENTATION FAULT HERE
printf("%d\n",array[i]);
}
}
I am getting a segmentation fault at the print loop in test.c.
You cannot return arrays from functions. When point() returns, the local array within this function goes out of scope. This array is created on the stack, and will get destroyed once the function finishes returning. All memory associated with it is discarded, and the returned pointer points to a position on the stack that doesn't exist anymore. You need to instead allocate a pointer on the heap, and return that instead. This allows array to be shared across your program.
Instead of:
int array[4];
you need to dynamically allocate a pointer using malloc():
int *array = malloc(4 * sizeof(*array)); /* or sizeof(int) */
if (array == NULL) {
/* handle exit */
}
malloc() allocates requested memory on the heap, and returns a void* pointer to it.
Note: malloc() can return NULL when unsuccessful, so it needs to be checked always. You also need to free() any memory previously allocated by malloc(). You also don't need to cast return of malloc().
Another thing to point out is using the magic number 4 all over your program. This should really be calculated using sizeof(a)/sizeof(a[0]).
You can declare this as a size_t variable in your main():
size_t n = sizeof(a)/sizeof(a[0]);
Or you can use a macro:
#define ARRAYSIZE(arr) (sizeof(arr) / sizeof(arr[0]))
And simply call ARRAYSIZE(a) everytime you want the size of the array.
The issue has to do with the scope of the array variable that you're returning in your method. Right now you're returning array, a local variable defined in the method, point. However, once point is finished executing, all local variables within the function frame, including array will be discarded from main memory. So even though you still get a memory address from point, there's no telling what could be at that memory address. Therefore, treating array as an int array when printing out its elements will lead to a segmentation fault.
My suggestion to fix this is to allocate memory from the heap using malloc so that array lasts outside the frame of point. The solution should look like this,
int* point(int a[])
{
printf("In the point function\n");
int *array = (int *) malloc(4 * sizeof(int)); //dynamically allocate memory for 4 integers
int i;
for(i=0;i<4;i++)
{
printf("%dth Iteration\n",i);
array[i]=a[i];
}
return array;
}
You could either define array[] as a global variable, or dynamically allocate memory for it as mentioned in the above comments using malloc().
Since array[] is allocated in the function point(), it gets deleted once the function exits. Hence, a reference to the returned pointer causes a segmentation fault.

pointer to array in separate function receiving unwanted garbage values

I have a function that I pass an array into and an int into from my main function. I am doing operations to the array inside this new function, let's call it foo. In foo, I initialize another array with 52 cells all with 0. I do operations on the array that I passed from main, and transfer that data to the newly initialized array. I want to return the new array back to the main function. But of course, I can't return data structures like arrays. So I instead return an int pointer that points to this array. Inside the int main, I pass the pointer to have it point to various cells in the array. When I print the results of what the pointer is pointing to, it should either be pointing to 0 or an integer greater than 0. But instead, I get inconsistent results. For some reason, some of the values that SHOULD be 0, prints out garbage data. I've been trying to spot the bug for some time, but I just wanted a second hand look at it. Here is just the GENERAL idea for the code for this portion anyways...
int main(){
int *retPtr;
char input[] = "abaecedg";
retPtr = foo(input, size);
for(i=0; i<52; i++){
// error displayed here
printf("%d\n", *(retPr + i));
}
}
int foo(char input[], int size)
{
int arr[52] = {0}; // should initialize all 52 cells with 0.
int i=0, value; // looking for non-zero results in the end.
int *ptr = &arr[0];
for(i=0; i<size; i++){
if(arr[i] > 64 && arr[i] < 91){
value = input[i] - 65;
arr[value]++;
}
}
return ptr;
}
Hopefully this makes sense of what I'm trying to do. In the foo function, I am trying to find the frequency of certain alphabets. I know this might be a bit cryptic, but the code is quite long with comments and everything so I wanted to make it as succinct as possible. Is there any possible reason why I'm getting correct values for some (numbers > 0, 0) and garbage values in the other?
The reason you get garbage back is that the array created in foo is allocated in foos stack frame, and you then return a pointer into that frame. That frame is discarded when foo returns.
You should allocate the array on the heap (using malloc and friends) if you want it to remain after foo returns. Don't forget to free() it when you're done with the array.
int main(){
char input[] = "abaecedg";
int retPtr[] = foo(input, size); //An array and a pointer is the same thing
...
free(retPtr);
}
int *foo(char input[], int size)
{
int arr[] = calloc(52*sizeof(int); // should initialize all 52 cells with 0.
...
arr[value]++;
...
return arr;
}
Another way is to let foo take an array as a parameter and work with that, in this way:
int main(){
int ret[52] = {0};
...
foo(input, size, ret);
...
}
void foo(char input[], int size, int *arr)
{
...
arr[value]++;
...
return; //Don't return anything, you have changed the array in-place
}
The reason this works is because an array is the exact same thing as a pointer, so you are really passing the array by reference into foo. arr will be pointing to the same place as ret, into the stack frame of main.
In function foo the array arr is a local array, that is, allocated on the stack. You must not return any pointer of data allocated on the stack, since the stack is rewinded after you return from the function, and its content is no more guaratneed.
If you want to return an array you should allocate it on the heap using malloc, for example, and return the pointer malloc returned. But you will then have to free that memory somewhere in your program. If you fail to free it you will have what's called a "memory leak", which may or may not crash/disturb this program from running again, depending on your environment. A not clean situation, that's for sure.
That's why I consider C not so good for functional programing idioms, such as returning things from function (unless they are primitive types). I would achieve what you tried to do by passing another array to foo - an output array, companioned by a size variable, and fill that array.
Alternately, you could wrap the array within a struct and return that struct. Structs can be returned by value, in which case they are copied via the stack to the caller function's returned value.

C - allocating values in an array of pointers in outside function

Lets say I have the following situation (some rough pseudocode):
struct {
int i;
} x
main(){
x** array = malloc(size of x pointer); // pointer to an array of pointers of type x
int* size = current size of x // (initally 0)
add(array, size);
}
add(x** array, int* size){ // adds one actual element to the array
x** temp = realloc(array, (*size)+1); // increase the array size by one
free(array);
array = temp;
// My question is targeted here
array[*size] = malloc(size of x); // makes a pointer to the value
array[*size]->i = size;
*size++;
}
My question is: Once add() is finished, do the values of the pointers stored in array disappear along with the function call stack, since I allocated them inside func()? I fear that they might, in which case would there be a better way for me to do things?
No, they don't. They persist until the pointer returned by malloc() is passed to the corresponding free() function. There would be no point in the existence of the malloc() function if it worked the same way as automatic arrays.
Edit: sidenote. As #Ancurio pointer it out, you're incorrectly freeing the memory behind the previous pointer returned by malloc() which is at that time invalid as realloc() has been used on it. Don't do that. realloc() does its job properly.)

Resources