passing a pointer as argument to a function in C - c

Something I stumbled upon and made me wonder.
Why does this work?
void foo (int* a)
{
int x = 3;
*a = x;
}
int main()
{
int a;
foo(&a);
return 0;
}
But this causes a segmentation fault (both on Visual Studio 2008 and gcc)?
void foo (int* a)
{
int x = 3;
*a = x;
}
int main()
{
int* a;
foo(a);
return 0;
}
Is it something defined in the language or just an implementation issue?

When you declare
int* a;
You are declaring a pointer variable a but you are not making it point to anything. Then in the function, you do
*a = x;
Which dereferences the pointer and tries to assign what it points to the value of x. But since it doesn't point to anything, you get undefined behaviour, manifested in a segmentation fault.
You should do this:
int i; // the actual integer variable
int* a = &i; // a points to i
The difference between that and the first one is that int a; declares a real integer variable, then you take its address with &a and passes it to the function. The pointer a inside the function foo points to the variable a in main, and so dereferencing it and assigning to it is perfectly fine.

int a;
Assigns memory as soon as you declare it but this not the case with int *a;
int *a;
is pointer declaration (MEMORY not yet allocated for that).
int *a = (int*)malloc(sizeof(int)); // allocate memory

Related

function call using pointers

Can anyone explain me why am I getting the error
cannot convert int ** to int* of argument1
I have seen all the stack overflow answers but did not find the way to solve my problem. My code
#include<stdio.h>
int* sum(int,int*);
int main()
{
int a=5;
int *b;
*b=6;
int *res;
res=sum(a,&b);
printf("\n%d\n%d\n",a,*b);
printf("%d",*res);
}
int* sum(int x,int *y)
{
x=x+1;
*y=*y+3;
return (&y);
}
This is a basic problem but I am finding it hard to solve the error.
res=sum(a,&b);
Here b is already a pointer(an unallocated integer pointer which may lead to undefined behaviour).So &b is of type int **. So pass only b.
res(a,b);
After that you return &y which is also of int** type change it to y (of type int *)if you want to return the address.
return y;
In your case,
int* sum(int x,int *y)
function accepts an int, an int * and finally returns an int *. Now, inside the function definition, you're writing
return (&y);
here. y is int *, so &y produces int **, which is wrong, as per the defined return type[e of the function.
change
return (&y);
to
return y;
as you're returning an int *, and y is already one.
Next, the same kind of conceptual issue with the function call also. Instead of res=sum(a,&b);, you need to pass b only, as it's already a pointer.
Also, please notice,
the recommended signature of main() is int main(void).
return is not a function. You usually don't need a parenthesis around it's expression, specially, when using a variable name only as the expression.
Can anyone explain me why am I getting the error
Going over your code piece for piece:
int a=5; /* initializes a to value 5 */
int *b; /* declares pointer b */
*b=6; /* OPS, segfault here */
int *res; /* declares pointer res */
res=sum(a,&b); /* assigning to the address of res */
The statement *b = 6; is wrong, you should not do that. You are trying to assign the value 6 to a pointer that is not dynamically allocated, and you haven't set it to point to any address yet.
What you should do is, make the pointer point to the address of a variable first, for example:
int c = 3;
int *b = &c; /* create a pointer 'b' and make that
pointer point to the address of c */
*b = 6; /* OK */
Notice the difference in appearance between initializing int *b = &c;, and declaring and then assigning b = &c:
int *b; /* declaring a pointer 'b' */
b = &c; /* make that pointer point to address of c */
Next, you create a pointer variable 'res' and you try to assign the return value of sum to the address of res:
int *res; /* declaring pointer 'res' */
res = sum(a, &b); /* OPS, 'b' is a pointer */
Looking at the function 'sum', you are trying to make parameter int *y point to the address of b, but the way to do that with pointers is simply to omit the &, therefore passing only b: sum(a, b);
Now, the return value of sum is:
int* sum(int x,int *y) /*
^ sum returns a pointer to int */
And according to your code, you want to assign the result of function sum to the address of res, therefore you want to assign the address of y to the address of res:
res=sum(a,b); /* calling function sum */
int* sum(int x,int *y) /* 'y' points to address of b */
{
x=x+1;
*y=*y+3;
return y; /* returning the address */
}
When sum returns, res points to the same address as y and b.
With pointers assign the address to the address of another pointer, example:
/* a and c are int's */
int *x = &a;
int *y = &c;
x = &y; /* wrong */
While this is correct:
int *x = &a;
int *y = &c;
x = y; /* ok */
Because y is an int* y (pointer to int), then &y is an int** (pointer to int* or pointer to pointer to int), but your function (sum) must return int*, not int**. You just change return &y to return y to fix this.

Passing pointers into another function in C

Say I have a variable
int * foo;
I pass this variable into
func(int *x)
{
*x = bar;
}
However, this does not work. However, if I put a non-pointer (say change it to int foo;) and directly put the address in, this works.
Why doesn't my first case work?
Thanks!
Your code is doing exactly what you are telling it too. However, int *foo does not allocate any storage. The pointer is simply a handle to a memory address. In this case, it is arbitrary and results in undefined behavior. Try the following instead.
void func(int *x) {
*x = 42;
}
int main(int argc, char** argv) {
int *foo;
int storage;
foo = &storage;
func(foo);
printf("%d\n" storage);
return 0;
}
foo is simply a pointer to storage which is allocated on the stack by the runtime. You are just as well off using foo(&storage) in this case.
By declaring int * foo you've only created a pointer. foo is not actually pointing at anything yet - it's uninitialised. You might even get a segmentation fault from code like that, as the pointer could point outside of program memory. If you do:
int * foo = (int *)malloc(sizeof(int));
You will have initialised the pointer, malloc allocates some memory from the heap of the size passed to it. You can also do:
int bar = 0;
int * foo = &bar;
Which will make foo a pointer to bar (& returns the address of the variable).
You should do something like this
int bar = 235; // any value you want
void func(int *x)
{
*x = bar;
}
int main()
{
int *foo;
foo = (int*)malloc(sizeof(int));
func(foo);
printf("%d", *foo);
free(foo);
return 0;
}

usage of double pointers as arguments

Please find the code snippet as shown below:
#include <stdio.h>
int My_func(int **);
int main()
{
int a =5;
int *p = &a;
My_Func(&p);
printf("The val of *p is %d\n,*p);
}
void My_Func(int **p)
{
int val = 100;
int *Ptr = &val;
*p = Ptr;
}
How does by using a double pointer as a argument in my_Func function and making change of value reflects the same in the main function but if we use a single pointer in My_Func does not change the value in main?Please do explain me with examples if possible
Advanced thanks
Maddy
int **p is a pointer to a pointer-to-int. My_Func(int **p) works by changing the value of integer that the pointer-to-int points to i.e. int a.
Without changing the implementation, the function will not work with a pointer-to-int parameter int *p as there is a second level of indirection. In addition, you're setting the value to a local variable that is created on the stack. When the function is completed the memory used for the variable will be reclaimed, therefore making the value of a invalid.
void My_Func(int **p)
{
int val = 100; // Local variable.
int *Ptr = &val; // This isn't needed.
*p = Ptr;
} // val dissapears.
Remove the second level of indirection and copy val by value instead of pointing to it:
#include <stdio.h>
void My_Func(int *p)
{
int val = 100;
*p = val;
}
int main(void)
{
int a = 5;
My_Func(&a);
printf("The val of a is %d\n", a);
return 0;
}
In short, in C when you pass something as a parameter, a copy will be passed to the function. Changing the copy doesn't affect the original value.
However, if the value is a pointer, what it points to can be changed. In this case, if you want to affect the pointer, you need to pass a pointer to it down to the function.
Use it in the function declaration:
void func(int *p)
{
int val =100;
int *temp=&val;
p=temp;
}
p starts pointing to another address i.e. address of val. So it will print the value 100.
Important note: Try it in your downloaded compiler (always in case of pointers) not in the online compiler. The online compiler doesn´t keep track of lost addresses in stack.
You are assigning the address of local variable, which will soon disappear when My_Func returns. You can use following in your code. However you can do the same thing just by using single pointer, double pointer is not required in this example.
void My_Func(int **p)
{
int val = 100;
int *Ptr = &val;
**p = *Ptr;
}

Why do these pointers cause a crash?

I'm a bit confused as to why the following code crashes:
int main(){
int *a;
int *b;
*a = -2;
*b = 5; //This line causes a crash on my system.
return 0;
}
Shouldn't memory automatically be allocated for two pointers and two integers before run-time because of the declarations?
Or must you always explicitly allocate memory?
No. You've only declared the pointers, not what they point to. The pointers are allocated on the stack, and since you've not initialized them to anything, their values are garbage.
int main() {
int a = 7;
int *p_a; // p_a contains whatever garbage was on the stack at its
// location when main() is called. (Effectively points nowhere).
p_a = &a; // p_a points to (gets the address of) variable a, also on
// the stack.
printf("Before: a = %d\n", a); // prints 7
*p_a = -2;
printf("After: a = %d\n", a); // prints -2
return 0;
}
I would code up the above example, and step through it in a debugger. You'll see what I mean about what p_a is pointing to.
Shouldn't memory automatically be allocated for two pointers and two integers before run-time because of the declarations?
I only see you specifying two pointers. Where are the two integers?
Or must you always explicitly allocate memory?
Pointers have to point to something. Either local variables on the stack, or malloc'd memory from the heap.
In this code:
int* a;
*a = -2;
a is an uninitialized pointer, dereferencing of which produces undefined behavior, that you were luckily able to observe as a crash of your application.
You need to initialize the pointer (make it point to the valid memory) before you dereference it (i.e. before you use *, the dereference operator):
int a;
int* pA = &a;
*pA = -2;
Consider
int m;
int n;
m = n;
This is invalid because you're trying to use n but you haven't assigned a value to it. Now:
int *a;
*a = -2;
Likewise, this is invalid because you're trying to use a but you haven't assigned a value to it. The value of a is not an int, it's a pointer to int. For example,
int someint;
a = &someint;
*a = -2;
puts -2 into someint. Without the assignment to a, the place to put -2 is undeterminable. Also,
a = malloc(sizeof(int));
*a = -2;
Here, a is given the value of the address of some location in the heap; -2 goes into that heap location.
Perhaps an analogy would be helpful:
Consider the phrase "her dog". This is a reference to someone's' dog, but it won't do to tell me "give her dog a bone" if you haven't told me who she is. Similarly, "pointer to an int" doesn't tell the system which int it is.
Your *a and *b pointers are not initializated properly.
Try this one:
int my_a;
int my_b;
int *a;
int *b;
a = &my_a; // init the pointer a to the direction of my_a int variable
b = &my_b;
*a = 3; // set the my_a value via pointer
*b = 2;
You have just declared pointers but you haven't initialized them. So, you can't be sure that *b = 5 is causing the program to crash. It could be *a = -2 as well. To fix it, you should initialize your pointers as well.
int aval = -2;
int bval = 5;
int *a = &aval; // declared and initialized pointers
int *b = &bval;
// Now you can change the value using the pointer
*a = 15;
*b = 20;

Why does my C program crash when assigning a value to an int pointer?

I am trying to have a function take some integer pointers passed from my main() function and assign values to them. However, my program crashes when assigning values. Here is my code:
int computeMoveLocation(int* r, int* c, char* board)
{
//some code up here
*r = 0; //This breaks the program
*c = 0;
}
I'm not trying to change the address of the pointer--I'm trying to change the value of the integer being pointed to. However, I am apparently doing something wrong.
Any help would be greatly appreciated.
EDIT:
Here is the relevant code from main(). Please let me know if I should include anything else as well.
int main()
{
//initialization code
//...
while (1)
{
switch (MACHINE_STATE)
{
case COMPUTER_MOVE :
{
//check rows for three Xs
//check columns for three Xs
//check diagonals for three Xs
//otherwise, move anywhere else
int *r, *c;
computeMoveLocation(r, c, board);
computerMove(*r,*c, board);
PREVIOUS_STATE = COMPUTER_MOVE;
MACHINE_STATE = HUMAN_MOVE;
break;
}
//Other cases
}//end switch
}//end while
}//end main
You are passing in pointers but you didn't allocate memory. So they are pointing at a random location in memory.
int computeMoveLocation(int* r, int* c, char* board) {
//some code up here
*r = 0; //This breaks the program
*c = 0;
}
Bad main :
int main() {
int *r;
int *c;
char *board;
// bad, passing in pointers but didn't allocate memory
computeMoveLocation(r, c, board);
return 0;
}
Good main #1:
int main() {
int r = 5;
int c = 5;
char board = 'a';
// fine, passing address of variables on stack
computeMoveLocation(&r, &c, &board);
return 0;
}
Good main #2:
int main() {
int *r = malloc(sizeof(int));
*r = 5;
int *c = malloc(sizeof(int));
*c = 5;
char *board = malloc(sizeof(char));
*board = 'a';
// fine, passing pointers that point to heap
computeMoveLocation(r, c, board);
free(r);
free(c)
free(board);
return 0;
}
int *r, *c;
computeMoveLocation(r, c, board);
computerMove(*r,*c, board);
You define a pointer but don't make it point to anything. Thus, it is a wild or uninitialized pointer; accessing *r as you do in computeMoveLocation will cause undefined behaviour (in your case, a crash).
You have to either initialize the pointer to point at something known, or just pass the address of an existing int:
int r, c;
computeMoveLocation(&r, &c, ...);
or
static int x, y; // static: only one instance of the variable exists
int *r = &x; // initialize pointers
int *c = &y;
computeMoveLocation(r, c, ...);
or
int *r = malloc(sizeof(int));
int *c = malloc(sizeof(int));
computeMoveLocation(r, c, ...);
In that last case, make sure to free the memory afterwards.
You can always pass a pointer and modify the value that the pointer is pointing to. That is how pointers are supposed to be used. But, you should also be careful to see if the pointer does really points to something or not. The pointer should contain a valid address, the value at whose location you can change. If you don't ensure that, then Undefined Behavior will result.
For Example, when you call your computeMoveLocation function, the address which you are passing should either be of stack or of heap. You can see the code below to understand it.
First possibility
int r, c;
char board;
computeMoveLocation(&r,&c, &board);
Second Possibility
int *r, *c;
char *board;
r = malloc(sizeof(int));
c = malloc(sizeof(int));
board = malloc(sizeof(char));
computeMoveLocation(r,c,board);
Please note that char * is also generally used to pass an address to array of charaters, but, in a such a usage, generally it is ensure that it is null terminated or an accompanying length of the array is also passed.
You can anyway get more details on passing aroung pointers by a simple google search.
EDIT
Now, that you have posted your code which calls computeMoveLocation, you see that you should modify your code according to the Second Possibility shown above, since you are declaring r and c as pointers or you should declare them as integers and call as per the First Possibility shown above. But, you are not doing the same which causes the undefined behavior.
Also, in the above examples, I have allocated memory for board, but, in your case, if it originates at some other place and if it has been handled appropriately there, then it need not be malloced.

Resources