Unable to modify pointer variable passed as argument to a function - c

I have this function
int rt_exist(struct route_entry* prev_rte) {
prev_rte = rte_head; //This doen't assigns rte_head to prev_rte
return 0;
}
where rte_head is an initialized struct route_entry* pointer variable.
But in the above case "prev_rte" is not assigned the value of rte_head.
By the way ,I if I do something like this
int rt_exist(struct route_entry* prev_rte) {
struct route_entry* rte_new;
rte_new = rte_head; //But this can
return 0;
}
The above assignment occurs smoothly . The problem arises when pointer variable is passes as function argument.
It's a weird question with little details ,but can someone point me to a possible direction or something wrong I might be doing.

Consider this:
void foo (int j)
{
j = 7;
}
foo (8);
What do you expect to happen here? A function can't change a value in the caller this way.
What should happen here:
rt_exist (NULL);
For C++, you can use references:
int rt_exist(struct route_entry*& prev_rte) {
prev_rte = rte_head; //This doen't assigns rte_head to prev_rte
return 0;
}
For C, you need to pass a pointer to the thing you want to change:
int rt_exist(struct route_entry** prev_rte_ptr) {
*prev_rte_ptr = rte_head; //This doen't assigns rte_head to prev_rte
return 0;
}

Yes! in first case you are using temporary portion of a stack. But in the second case you are using allocating. Which means that you are using a portion of memory which is from heap. It will obviously affect the value. This is like a new variable in a new block. In this scope it will have the assigned value.
But in rt_exist the copy of the variable is passed. So any change in that will not affect the actual one. But you can pass it's address and change it easily like this.
int rt_exist(struct route_entry** prev_rte)
{
*prev_rte = rte_head; //This does assign rte_head to prev_rte.
return 0;
}

Related

Pass by reference for pointers in C

I was trying to understand the concept of passing by reference. When I do this,
#include<stdio.h>
int recent (int *a)
{
*a = 20;
return 0;
}
int main()
{
int bee;
bee=5;
int *val = &bee;
printf("Value is %d\n", *val);
recent(val);
printf("Now Value is %d\n", *val);
return 0;
}
Basically I am making the pointer val point to the memory location of bee, and then when I pass it to recent function, and change the value, that change gets reflected in the calling function, so the value changes to 20. But when I do this,
#include<stdio.h>
int check = 20;
int recent (int *a)
{
a = &check;
return 0;
}
int main()
{
int bee;
bee=5;
int *val = NULL;
recent(val);
printf("Now Value is %d\n", *val);
return 0;
}
I get segmentation fault.
Is it because I didn't initialize the pointer to point to any location, and then I passed the value to recent function, and even though I made it point to a memory location (check variable), the calling function didnt catch that because I was passing by value?
Is this completely true or I misinterpreted something and got lucky with the answer?
Your problem is that you are printing the output of dereferencing the pointer val in the main function. The value of the pointer val in the main function is NULL. Thus the program is trying to print the thing at memory location 0, which is inaccessible to your program and results in a segmentation fault.
First you create the val pointer and assign it the value NULL.
int *val = NULL;
Then you call recent, passing it the pointer val, which still holds NULL.
recent(val);
Finally you print *val. val still holds NULL, and the * operator tells the compiler to "dereference" val, meaning to use the value of the thing that val is pointing to.
printf("Now Value is %d\n", *val);
In response to the question of whether your description is correct, the answer is sort of, but your description is imprecise. You made the function's copy of the pointer point to something. When you implement a pass-by-reference function in C using pointers, you are still passing the pointers themselves by value: a copy of the pointer is made, pushed onto the stack, and sent to the function. If you update the value of the pointer in the called function, the value of the pointer in the calling function will not be changed.
The reason has to do with your function recent(). When you pass in "a" you are passing in an int* (i.e. int pointer) which is an address to a location in memory. However, "a" as you have it, is local to this function (the pointer is pass by value).
Thus when you set "a = &check", you are only changing the local pointer value. As soon as recent() returns, "a" goes out of scope. In this context, you are never changing what "a" actually points to.
Thus, you segfault because val is still null, and you are trying to dereference a NULL pointer.
val is still a null pointer after leaving the function. The pointer itself is (as you correctly guessed) only passed by value, not by reference. Inside the function you are only modifying the pointer (which only lives insides the function), not the pointer target.
Besides that, please be careful with passing around memory locations to automatic stack variables. At least coming from a C++ background, it's considered bad style. Since you don't explicitly control the life cycle of a stack variable yourself (as you would do with malloc/free), you can easily shoot yourself in the foot by accidentally dereferencing pointers which have already been cleaned from the stack.
Is it because I didn't initialize the pointer to point to any location,
Code well initialized with int *val = NULL;, yet NULL is not a valid location. It isn't the NULL is a location or not. It is the NULL is the null pointer constant. As a null pointer, it "is guaranteed to compare unequal to a pointer to any object or function."
... and even though I made it point to a memory location (check variable), the calling function didn't catch that because I was passing by value?
Yes. With a = &check;, only the local a was affected, not the val in which a was copied from as the actual augment val was passed by value (copied) to the formal parameter a.
Is this completely true ...
IMO: Yes
... I misinterpreted something and got lucky with the answer?
It appears no misinterpretation. Lucky - hard to rate.
Here is what is going on in your code:
#include<stdio.h>
int check = 20;
int recent (int *a)
{
a = &check;
return 0;
}
int main()
{
// memory is allocated to hold an integer
int bee;
// the number 5 is written into that memory space
bee = 5;
// memory is allocated to hold a memory address
// the value of null (which is a invalid address) is written into it
int *val = NULL;
// more memory is allocated to hold a memory address (int* a)
// the address in val (which is null) is written into it
// the new memory address (a) now points to the address of check
recent(val);
// val is still NULL
// BOOOM!
printf("Now Value is %d\n", *val);
return 0;
}
Long story short, you are correct! :)
It's basically what all have answered. It's because you are passing the address pointed by pointer a using Pass By Value method. That is your sending in a copy of the address. If you want the second code to work you need to change the code to the following,
#include<stdio.h>
int check = 20;
int recent(int **a)
{
*a = &check;
return 0;
}
int main()
{
int bee;
bee = 5;
int *val = NULL;
recent(&val);
printf("Now Value is %d\n", *val);
return 0;
}
That is you have to Pass the address pointed by a by using C version of "Pass By Reference".

Returned array in C doesn't contain same values

I'm in the process of teaching myself C and I'm mistified as to what's causing the following issue: when I create an array in a method and return it as a pointer to the calling function, none of the content is correct. I've boiled down this problem to the following example:
char * makeArr(void){
char stuff[4];
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
printf("location of stuff:%p\n",stuff);
int i;
for(i = 0; i < 4; i++){
printf("%c\n",stuff[i]);
}
return stuff;
}
int main(void){
char* myarr;
myarr = makeArr();
int i;
printf("\n");
printf("location of myarr:%p\n", myarr);
for(i = 0; i < 4; i++){
printf("%c\n",myarr[i]);
}
}
The output returns the following:
location of stuff:0028FF08
a
b
c
d
location of myarr:0028FF08
Ä
ÿ
(
(a null character)
So I've verified that the locations between the two values are the same, however the values differ. I imagine that I'm missing some critical C caveat; I could speculate it's something to do with an array decaying into a pointer or a problem with the variable's scope, but and any light that could be shed on this would be much appreciated.
What you're attempting to do is return the address of a local variable, one that goes out of scope when the function exits, no different to:
char *fn(void) {
char xyzzy = '7';
return &xyzzy;
}
That's because, other than certain limited situations, an array will decay into a pointer to the first element of that array.
While you can technically return that pointer (it's not invalid in and of itself), what you can't do is dereference it afterwards with something like:
char *plugh = fn();
putchar (*plugh);
To do so is undefined behaviour, as per C11 6.5.3.2 Address and indirection operators /4 (my bold):
If an invalid value has been assigned to the pointer, the behaviour of the unary * operator is undefined.
Among the invalid values for dereferencing a pointer by the unary * operator are a null pointer, an address inappropriately aligned for the type of object pointed to, and the address of an object after the end of its lifetime.
Having stated the problem, there are (at least) two ways to fix it.
First, you can create the array outside of the function (expanding its scope), and pass its address into the function to be populated.
void makeArr (char *stuff) {
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
}
int main(void) {
char myarr[4];
makeArr (myarr);
// Use myarr here
}
Second, you can dynamically allocate the array inside the function and pass it back. Items created on the heap do not go out of scope when a function exits, but you should both ensure that the allocation succeeded before trying to use it, and that you free the memory when you're finished with it.
char *makeArr (void) {
char *stuff = malloc (4);
if (stuff != NULL) {
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
}
return stuff;
}
int main(void) {
char *myarr;
myarr = makeArr();
if (myarr != NULL) {
// Use myarr here
free (myarr);
}
}
stuff[] only exists on the stack during function call, it gets written over after return. If you want it to hold values declare it static and it will do what you want.
However, the whole idea is fundamentally lame, don't do that in real life. If you want a function to initialize arrays, declare an array outside of the function, pass a pointer to this array as a parameter to the function and then initialize an array via that pointer. You may also want to pass the size of the array as a second parameter.
Since you're learning, a sample code is omitted intentionally.
Your array stuff is defined locally to the function makeArr. You should not expect it to survive past the life of that function.
char * makeArr(void){
char stuff[4];
Instead, try this:
char * makeArr(void){
char *stuff=(char*)calloc(4, sizeof(char));
This dynamically creates an array which will survive until you free() it.

Changing arrays inside a function in C w/o a pointer using memory addresses

While learning about pointers, arrays and functions on tutorials point I realised that I could achieve my goal of returning an array from a function by creating a new array in the main function, creating a pointer and assigning the return value of the function to this pointer and then using a for loop in the main function incrementing the pointer to reassign the values of the array to the array internal to the sorting function.
However I was wondering since the memory is returned to the stack after the function returns how come the values in the array aren't reassigned to something else and secondly is there a way I could using memory addresses change the actual array in the main function inside the sorting functions and then return void? I am using a bubble sort algorithm, this is my current sorting function;
#include <stdbool.h>
int *arr_sort(int *arr){
int *ptr = arr;
bool flag = true;
while(flag){
flag = false;
int i = 0;
for(i;i<4;i++){
if(arr[i]>arr[i+1]){
flag = true;
arr[i]+=arr[i+1];
arr[i+1] = arr[i]-arr[i+1];
arr[i]-= arr[i+1];
}
// printf("%d : %d\t%d : %d \n",i,arr[i],i+1,arr[i+1]); *Included to display the values as they are being switched
}
printf("\n\n");
}
return arr;
}
Then the for loop in the main that assigned my array (called unsorted_array) to the pointer as it is incremented through the array created inside the sorting function
ptr = arr_sort(unsorted_array);
for(j;j<5;j++){
unsorted_array[j]=*(ptr+j);
The whole thing works as a program but I was just wondering in the interest of building up knowledge (Haven't been programming in C for long), is there a better way to do this?
No need to return array from your function. Just define your function as
void arr_sort(int *arr){
bool flag = true;
while(flag){
flag = false;
int i;
for(i = 0; i < 4; i++){
if(arr[i] > arr[i+1]){
flag = true;
arr[i]+=arr[i+1];
arr[i+1] = arr[i]-arr[i+1];
arr[i]-= arr[i+1];
}
}
printf("\n\n");
}
}
Any and all changes to arr will be made to the array in main.
I assume that you, with "creating a new array in the main function" mean something like this:
int main(int argc, const char *argv[])
{
char unsorted_array[ARRAY_SIZE];
// ... Code
}
Any variable, (trivial, pointer or array) located on the stack is kept while calling another function, but any variable located on the stack by the called function is invalidated when the function returns.
But: a pointer located on the stack may point to an array on the heap. That is if the array is either allocated by malloc(), being declared as static inside the function, or being a global variable. In that case, the content of the array is of course kept as the function returns, and can be made available to the calling function by e.g returning the pointer. Only the pointer (e.g. typically 4 bytes) is copied to the calling function stack as the function returns, not the array which the pointer points to.
Similarly, an array located on the stack may be made available to a called function, by supplying the called function with a pointer to the array, just as you do. What is copied to the called function's stack, is only the pointer (4 bytes), hence the called function may access and modify the array, and the array itself is not invalidated as the function returns.
NB: in C, when invoking a function declared as
void afun(char anarray[ARRAY_SIZE);
the compiler implicitly treats the function as if it was declared as
void afun(char *anarray);
i.e. calling afun only copies the pointer, not the array to the called function's stack.

why can't i free the memory?

I wrote a simple counter structure in C:
typedef struct{
int value;
}Counter;
then, I wrote some simple implementations:
void createCounter(Counter *dCount)
{
dCount = (Counter*)malloc(sizeof(Counter));
dCount->value = 0;
}
void FreeResource(Counter *dCount)
{
free(dCount);
}
now in the main, i wanted to free the pointer i created and it complained that the pointer being freed was not allocated.I am looking at the code and I thought I allocated memory for it when I called the createCounter() function?
int main()
{
Counter m;
CreateCounter(&m);
FreeResource(&m); //run time error given here..
return 0;
}
You are trying to pass the address of a variable allocated in stack and then trying to assign an address allocated by malloc to it which won't get reflected in the caller. So, when you try to free it, you are effectively passing a stack variable's address to free due to which you get undefined behavior.
Change the function
void createCounter(Counter *dCount)
{
dCount = (Counter*)malloc(sizeof(Counter));
dCount->value = 0;
}
as
void createCounter(Counter **dCount)
{
*dCount = (Counter*)malloc(sizeof(Counter));
(*dCount)->value = 0;
}
In your case, the pointer gets passed by value and the new memory address allocation doesn't reflect in the caller.
The main function must be changed as:
int main()
{
Counter *m;
CreateCounter(&m);
FreeResource(m); //run time error given here..
return 0;
}
dCount = (Counter*)malloc(sizeof(Counter));
There are multiple problems:
dCount = ... has absolutely no effect for the caller., i.e. the pointer is unchanged.
You passed a pointer to an already allocated structure, you don't need to malloc anything
You're trying to free something (&m) you didn't obtain from malloc
The only sane suggestion at this point is to review a chapter on pointers.
The problem is that in CreateCounter the variable dCount is a local variable. That means changes to the variable won't be visible when the function returns.
There are two common solutions to this:
Return the pointer:
Counter *CreateCounter()
{
Counter *dCounter = malloc(sizeof(Counter));
dCounter->value = 0;
return dCounter;
}
Pass the argument as a reference, i.e. a pointer to the pointer:
void CreateCounter(Counter **dCounter)
{
*dCounter = malloc(sizeof(Counter);
(*dCounter)->value = 0;
}
And call it as this:
Counter *m;
CreateCounter(&m);

Modifying struct members through a pointer passed to a function

for instance this code:
struct test{
int ID;
bool start;
};
struct test * sTest;
void changePointer(struct test * t)
{
t->ID = 3;
t->start = false;
}
int main(void)
{
sTest->ID = 5;
sTest->start = true;
changePointer(sTest);
return 0;
}
If I was to execute this code, then what would the output be? (i.e. if I pass a pointer like this, does it change the reference or is it just a copy?)
Thanks in advance!
Your program doesn't have any output, so there would be none.
It also never initializes the sTest pointer to point at some valid memory, so the results are totally undefined. This program invokes undefined behavior, and should/might/could crash when run.
IF the pointer had been initialized to point at a valid object of type struct test, the fields of that structure would have been changed so that at the end of main(), ID would be 3. The changes done inside changePointer() are done on the same memory as the changes done in main().
An easy fix would be:
int main(void)
{
struct test aTest;
sTest = &aTest; /* Notice the ampersand! */
sTest->start = true;
changePointer(sTest);
return 0;
}
Also note that C before C99 doesn't have a true keyword.
The only question is why do you need a test pointer in a global name space? Second is that you do not have any memory allocation operations. And you have a pointer as an input parameter of your function. Therefore structure where it points to will be changed in "changePointer".
1) First thing your code will crash since you are not allocating memory for saving structure.. you might need to add
sText = malloc(sizeof(struct test));
2) After correcting the crash, you can pass structure pointer and the changes you make in changePointer function will reflect in main and vizeversa..
3) But since you are not printing anything, there wont be any output to your program..

Resources