Passing an array to a function in c - c

I have a doubt regarding passing of arrays to a function.
consider the following code snippet.
void main()
{
int a[4]={10,20,30,40};
fun1(a);
}
void fun1(int a1[])
{
for(int i=0;i<4;i++)
{
printf("%d\n",a1[i]);
}
}
Passing an array is nothing but passing the address of the first location.
And I should pass the above array with its name(starting address of the array).
My doubt is since a[4] is an auto variable, it should die when it comes out of the main function and it should give the unexpected results(the pointer should be dangled).
But it is working fine.
I am very confused with this, can you please clear it off.
Even if we pass a single element int a as f(&a), it should not exist in the function f, if it is declared as automatic(local variable in main function).
Please clear this as well.

Yes, variable a will be out of scope when main() terminates.
But when fun1 is executing, main() has not reached termination yet, so the content of a is still perfectly valid.

What you are doing is fine. The array a does indeed go out of scope but by that point your function has finished so you don't have to worry about accessing data that is no longer around. If you have concerns about passing the variable as the array name (which is fine) you can always step through your code to ensure you are accessing the data you think that you are.
You could also make your function safer by passing an additional integer argument that specifies the size of your array rather than having it hard coded as 4. If you used the function you have and passed an integer array of length less than 4, it will be accessing out of bounds memory.

void fun1 ( int a1[]) is creating a copy of whatever array is coming into the function. So it will exist.
You can also vision it as a stack. A stack will be created for main() method. And since the fun1() is called from the main method, the stack of main method will destroy only when the stack for fun1() is destroyed.

int a[] in function declaration/definition is equal to const int *a so nothing bad will happen and no memory will be freed implicitly.

Related

Programming language C

Can a function be used to copy elements from one array and save it into another array without returning the array to main.Because once we come out of a function all the variables local to it are lost.e.g
void copy(char to[],char from[])
{
int i;
while((to[i]=from[i])!='\0')
++i;
}
How does this code work?Because after copying elements from to array to from array.After the function is executed all the variables must be lost and nothing
must be saved in from array after function is executed.Please clarify my doubt.
The arrays are passed by pointers (the way references are used in C). So when the data is modified in the body of the function, the calling function can access the modified data.
After the function is executed all the variables must be lost and
nothing must be saved in from array after function is executed.
True, objects that have liftetimes within the lifetime of the function will be lost when the function exists. However the function's lifetime has no effect on objects that have existed before it or after it.
This line
void copy(char to[],char from[])
doesn't actually take two arrays by value. Instead, the [] decays to a pointer, what you've actually written is:
void copy(char* to, char* from)
This is because of array-pointer-equivalence. The language couldn't tell how big the arrays its going to need to copy would be when it compiled the function, since it could be different each time.
Thus only the pointers, to and from, are local, the data they point to is the same data that was pointed to in main.
After the function is executed all the variables must be lost and nothing must be saved in from array after function is executed.
Not exactly.
Generally C uses call-by-value, which means the function deals with copies of the parameters and so cannot modify them.
In order to modify the variable directly, you need to pass the address of the variable (ie the pointer to it), the function then access the variable via the pointer and can modify it directly.
That's also the case when you pass an array to a function, the value passed the the function is the location/address of the first element of the array. The function itself can then access and alter any element of the array.
In short, it's totally OK for your function copy to modify array to. And usually you should make from as const because you are not changing it inside the function. So the prototype should look like this:
void copy(char to[], const char from[]);
While local variables are lost at function end (scope-close), this only applies to to and from themselves -- NOT what they might point to.
BTW, your code is broken, try this instead:
void copy ( char * to, char * from ) {
while ((*to = *from) != '\0') {to++; from++;}
}
Both this version and yours blindly assumes that to is long enough to hold the result. This is potentially dangerous code.

What happens to an array during recursion in C?

In the following code I try to print all paths from the root to leaves in a Binary Tree.
If I write a recursive function as follows :
void printPath(BinaryTreeNode * n, int path[],int pathlen)
{
//assume base case and initializations taken care of
path[pathlen++] = n->data;
printPath(root->left,path,pathlen);
printPath(root->right,path,pathlen);
}
(I have purposefully removed base cases and edge cases handling to improve readability)
What happens to the path array? Is it just one global copy that gets modified during each recursive call ?Does the pathlen variable overwrites some of the path values, giving the feeling that each stack frame has it's own local copy of path, since pathlen is local to each stack frame?
Passing around a int[] variable is really almost like passing a int* around. The first invocation of the recursive function passes the real int[] which is nothing more than an address in memory, that's the same address used in every recursive call.
Basically if you place a debug print, eg
printf("%p\n", path);
in your recursive function you will see that the address is always the same, it doesn't change nor it gets modified. The only thing that is pushed onto the stack frame during the invocation is the address of the array, which nonetheless remains is always the same.
Welcome to array-pointer-decay. When you pass around an array, two distinct things happen:
When you declare a function to take an array parameter, you are really defining the function to take a pointer parameter. I. e., the declaration
void foo(int bar[]);
is perfectly equivalent to
void foo(int* bar);
The declaration of the array has decayed into a declaration of a pointer to its first element.
Whenever you use an array, it also decays into a pointer to its first element, so the code
int baz[7];
foo(baz);
is again perfectly equivalent to
int baz[7];
foo(&baz[0]);
There are only two exceptions, where this array-pointer-decay does not happen: the statements sizeof(baz) and &baz.
Together, these two effects create the illusion that arrays are passed by reference, even though C only ever passes a pointer by value.
The array-pointer-decay was invented to allow the definition of the array subscript operator in terms of pointer arithmetic: the statement baz[3] is defined to be equivalent to *(baz + 3). An expression which tries to add 3 to an array. But due to array-pointer-decay, baz decays into an int*, on which pointer arithmetic is defined, and which yields a pointer to the fourth element in the array. The modified pointer can then be dereferenced to get the value at baz[3].
void printPath(BinaryTreeNode * n, int path[],int pathlen);
compiler really looks at that like this
void printPath(BinaryTreeNode * n, int *path, int pathlen);
what happens to the path array? Is it just one global copy that gets modified during each recursive call
Nothing. The same path gets passed around, since in C array passing is just a pointer copy operation; and no, it isn't a global copy, but a parameter passed to the first call of the function, and will almost always live on the stack.
and the pathlen variable overwrites some of the path values giving the feeling that each stack frame has it's own local copy of path since pathlen is local to each stack frame?
Since you modify the value of the array elements and not the pointer pointing to the beginning of the array, nothing changes what path itself is pointing to (which is the array all the time). Like like you said it may give a feeling (particularly if you're used to that construct in other languages), but in reality only the same path gets passed around.
Aside: You don't seem to handle the exit condition and as it stands it'll be an infinite loop and mostly probably undefined behaviour when you start modifying elements that are out of the array's bounds.

pointer function in C not working

I intend to make my pointer print the value, but it just stops working (no error report from the MinGW) . . .
#include<stdio.h>
void point_here(int *yolo) {
int you = 2014;
yolo = &you;
}
main () {
int *punk = NULL;
point_here(punk);
printf("Punk # %d is not dead\w/.\n", *punk);
}
How do I make this work? And why this does not work? Please explain. I'm new to pointers and C, and still confuse after reading stuff.
C is "call by value"; functions get copies of the caller's values, not references to them. If you change an argument inside the function, nothing happens in the caller's context.
To work around this you need explicit pointers, but even you still can't have a pointer to a local variable inside a function persist beyond the running of that function.
You're passing NULL as an argument to a function which effectively doesn't nothing. Then you try to dereference that NULL pointer which is illegal.
This modified version of your code works well:
#include <stdio.h>
void point_here(int *yolo) {
*yolo = 2014;
}
int main () {
int value = 0;
int *punk = &value;
point_here(punk);
printf("Punk # %d is not dead\w/.\n", *punk);
return 0;
}
As others have said, you have the following issues:
Pointer to a function value doesn't work after the function finishes executing
You aren't passing the pointer to the pointer you are passing the pointer value. (In other words, you aren't editing what you think you are).
I fixed these two issues by passing in a pointer that has already been allocated, then you just modify it in the function. This is one standard way to use pointers. Best of luck!
There are 2 problems. First the pointer variable is pass by value, second the variable "you" is on stack which gets lost once the function returns.
Change the variable you to static like
static int you = 2014;
and change the argument to **yolo;

C problem: Passing var defined in function stack

int myfunc2(struct MyStruct st2[])
{
return 0;
}
int myfunc()
{
struct MyStruct st;
myfunc2(&st);
return 0;
}
Is this a pure bug? Or it is not a bug if it didn't call another function and st is not passed to another function in myfunc2. Can the st be the same one referenced by myfunc2 when myfunc2 get the pointer and pass it to another function?
This is perfectly valid code. You can pass it to any number of functions from myfunc2. The variable you allocated on stack will remain valid until it goes out of scope from myfunc
It depends on whether MyStruct is defined at a scope visible to myfunc2() or not, and what parameter myfunc2() is expecting.
Edit: with your edit to include a function prototype, it is certainly perfectly valid code.
There's nothing wrong with passing the address of a local variable to a function, but remember that the variable goes out of scope (and the pointer ceases to be valid) when the containing function returns. Be careful if myfunc2() might save the pointer for later use.
The code you showed is valid if you used myfunc2 in the correct way. You need to tell us the semantics (or show the implementation) of myfunc2 in order to let us say if anything is ok.
Passing the address of a local variable instead of an array is perfectly fine and equivalent to passing an array of size 1.
The problem with your code, however, is that myfunc2() has no way of knowing the size of the array passed to it. I guess it's okay if it uses only the first element of array, but then it should probably be declared to accept a pointer, not an array.

How does temporary storage work in C when a function returns?

I know C pretty well, however I'm confused of how temporary storage works.
Like when a function returns, all the allocation happened inside that function is freed (from the stack or however the implementation decides to do this).
For example:
void f() {
int a = 5;
} // a's value doesn't exist anymore
However we can use the return keyword to transfer some data to the outside world:
int f() {
int a = 5;
return a;
} // a's value exists because it's transfered to the outside world
Please stop me if any of this is wrong.
Now here's the weird thing, when you do this with arrays, it doesn't work.
int []f() {
int a[1] = {5};
return a;
} // a's value doesn't exist. WHY?
I know arrays are only accessible by pointers, and you can't pass arrays around like another data structure without using pointers. Is this the reason you can't return arrays and use them in the outside world? Because they're only accessible by pointers?
I know I could be using dynamic allocation to keep the data to the outside world, but my question is about temporary allocation.
Thanks!
When you return something, its value is copied. a does not exist outside the function in your second example; it's value does. (It exists as an rvalue.)
In your last example, you implicitly convert the array a to an int*, and that copy is returned. a's lifetime ends, and you're pointing at garbage.
No variable lives outside its scope, ever.
In the first example the data is copied and returned to the calling function, however the second returns a pointer so the pointer is copied and returned, however the data that is pointed to is cleaned up.
In implementations of C I use (primarily for embedded 8/16-bit microcontrollers), space is allocated for the return value in the stack when the function is called.
Before calling the function, assume the stack is this (the lines could represent various lengths, but are all fixed):
[whatever]
...
When the routine is called (e.g. sometype myFunc(arg1,arg2)), C throws the parameters for the function (arguments and space for the return value, which are all of fixed length) on to the stack, followed by the return address to continue code execution from, and possibly backs up some processor registers.
[myFunc local variables...]
[return address after myFunc is done]
[myFunc argument 1]
[myFunc argument 2]
[myFunc return value]
[whatever]
...
By the time the function fully completes and returns to the code it was called from, all of it's variables have been deallocated off the stack (they might still be there in theory, but there is no guarantee)
In any case, in order to return the array, you would need to allocate space for it somewhere else, then return the address to the 0th element.
Some compilers will store return values in temporary registers of the processor rather than using the stack, but it's rare (only seen it on some AVR compilers).
When you attempt to return a locally allocated array like that, the calling function gets a pointer to where the array used to live on the stack. This can make for some spectacularly gruesome crashes, when later on, something else writes to the array, and clobbers a stack frame .. which may not manifest itself until much later, if the corrupted frame is deep in the calling sequence. The maddening this with debugging this type of error is that real error (returning a local array) can make some other, absolutely perfect function blow up.
You still return a memory address, you can try to check its value, but the contents its pointing are not valid beyond the scope of function,so dont confuse value with reference.
int []f() {
int a[1] = {5};
return a;
} // a's value doesn't exist. WHY?
First, the compiler wouldn't know what size of array to return. I just got syntax errors when I used your code, but with a typedef I was able to get an error that said that functions can't return arrays, which I knew.
typedef int ia[1];
ia h(void) {
ia a = 5;
return a;
}
Secondly, you can't do that anyway. You also can't do
int a[1] = {4};
int b[1];
b = a; // Here both a and b are interpreted as pointer literals or pointer arithmatic
While you don't write it out like that, and the compiler really wouldn't even have to generate any code for it this operation would have to happen semantically for this to be possible so that a new variable name could be used to refer the value that was returned by the function. If you enclosed it in a struct then the compiler would be just fine with copying the data.
Also, outside of the declaration and sizeof statements (and possibly typeof operations if the compiler has that extension) whenever an array name appears in code it is thought of by the compiler as either a pointer literal or as a chunk of pointer arithmetic that results in a pointer. This means that the return statement would end looking like you were returning the wrong type -- a pointer rather than an array.
If you want to know why this can't be done -- it just can't. A compiler could implicitly think about the array as though it were in a struct and make it happen, but that's just not how the C standard says it is to be done.

Resources