What's the difference between these examples (* and &)? - c

I wanted to know what's the difference between these two versions of the main() code in C:
int main() {
uint32_t a;
f(&a);
}
and
int main() {
uint32_t *a;
f(a);
}
for a function
void f(uint32_t *pointer) {
// ...
}

In your first example, you pass a pointer to uninitialized variable a. f() could store a value there, for instance, and main() would be able to use that value later.
In your second example, you pass an uninitialized pointer a. f() can't do anything useful with it.

In the first version you pass a pointer to an un-initialized variable to f().
Don't, unless f()'s task is to initialize the variable.
In the second version you pass an uninitialized pointer to function f().
Don't.

wee pointer questions!!!
Ok so you know that the function f needs to take a pointer which is exactly as it sounds an address to that actual location in memory. For the first example(f(&a)) you have to pass the address because it lives inside the stack and really isn't shared anywhere outside the life of the function. so when the function returns the memory is destroyed and no longer available. the value of the pointer is not passed just the pointer to the value is passed. which can cause problems because if you change that value then all the things that "point to it" are now changed.
Now for the second one you get the memory from the heap or where ever but that stores the address of the value not the actual value so you can manipulate it and return nothing and the value is still there.

They are defining different types of variables, without initialization.
uint32_t a; defines uint32_t variable on the stack and the function call will pass its address to the f() function.
uint32_t *a; defines a pointer on the stack and pass its value to the function. The pointer is not initialized, thus it could point to any block and any attempt to access that address will result into undefined behavior.
From the perspective of the f() function, it sees pointer values passed to it. In the first call, it can use that address, while in the second, it cannot.

Related

Incrementation using functions

I want to increment the value of a integer using functions in C.
So first I wrote a function inc where I incremented the value of integer v. Then in main function I declared a new variable a and incremented using inc(a) function.
Here is my code:
#include<stdio.h>
void inc(int v)
{
v++;
}
int main()
{
int a;
scanf("%d",&a);
inc(a);
printf("%d",a);
return 0;
}
But the output is same as the input value. It is not incrementing.
i.e If I give the input as 45,I am expecting the value 46 as output. But the output is still 45. Where am I going wrong? Someone please explain.
So I've done some research and found that the expected answer is coming when pointers are used and here is the code for that
#include<stdio.h>
void inc(int *v) {
(*v)++;
}
int main() {
int a;
scanf("%d", &a);
inc(&a);
printf("%d", a);
return 0;
}
Why is the method without pointers is not correct?
Also in the second method why are we passing the argument as address i.e &a. Why can't we pass it as a?
I'm a newbie to C .So please help me with my doubts
The problem is that by default c uses pass by value for functions. That means that if your calling the function the following way in your main,
int a = 45;
inc(a);
the function only gets to know the value 45 but not the variable a. It will therefore make a new local variable (int v in your case) that stores the value 45 and gets incremented. Since the function does not know anything about a, in particular not where a is located in memory it can not modify it. There are generally two ways to solve this:
Using returns:
In this case the function keeps manipulating a local copy with the values of the arguments passed. In the end it can return the desired output of the function. This would be implemented the following way:
#include<stdio.h>
void inc(int v)
{
v++;
return v
}
int main()
{
int a;
scanf("%d",&a);
a = inc(a);
printf("%d",a);
return 0;
}
Passing the argument as a pointer:
In the second case, that you already found, your passing your argument by reference. This way the function gets to know the memory address of a and can therefore manipulate the value stored at a directly. The little star icon next to v in the function definition void inc(int *v) defines that the function takes an address as an input. Therefore, you have to pass the address of a by using &a as done in the code you posted.
Summary:
Your function, or any future functions you implement can be one of the two types above according to your needs. It should however, as a guideline, never manipulate values at passed addresses and return something at the same time. This can lead to confusion and results in a less readable code in general.
"Why is the method without pointers not correct?"
If you use a pointer parameter, your intention is to point to an object in the caller. You can then modify this object in the called function. This is what is called pass by reference. You pass a reference to an object in the caller.
If you don't use a pointer, you just pass the value of the variable by value to the function, which means the value of the argument is assigned to a function-local variable. Inside of the function you can modify only the value of this function-local variable, but not an object in the caller.
What's the difference between passing by reference vs. passing by value?
Also in the second method why are we passing the argument as address i.e &a. Why can't we pass it as a?"
The & operator gains in this case the address of a, which is needed to be assigned to the pointer parameter.
A pointer always stores an address of an object to point to, not a value of the pointed object.
Without address, the pointer doesn't denote an object.
Please learn more about pointers and read a good C starting book like Modern C (You can get a free copy of it there).
This and others you can also find here:
The Definitive C Book Guide and List
It is usually explained in the first few chapters about functions and argument passing.
You always pass a copy of your variable, value or reference, to the function. So, sending a copy of the value will not affect the main function. However sending a copy of its reference will affect the main function because you say where your variable is in the memory.
Also in the second method why are we passing the argument as address i.e &a. Why can't we pass it as a?
You're here manipulating with pointer, when you change the value of address to that pointer, then the original value is also get changed.
In the other hand, when you pass the variable a by-value, it'll just make a copy and increment it in the function call, no changes will occur in the original value. The first method doesn't works because the variable passed in the function was pass-by-value type.
Edit: This question is now only tagged in C. But for extra inforamtion, there's a method to do it without pointers in C++, it's called pass-by-reference (manipulates with original copy of variables) which could be represented by an ampersand sign on the function signature, something like:
void changeRealValue(int& value) {
// _____________________^________
value++; // original value is incremented now
}
Short answer:
C is default pass by value. If pointer is not specified, a v in inc is just a copy of a in main with the same value.
That is, v++ would increase v in scope of inc but effects no others.
For pointer, (*v)++ means "add one value to where v points to"
If you're using C++, passying by reference is another solution.
Pointer is a variable containing the address of an object. The pointer does not carry information about the contents of the object, but contains information about where the object is located.
Pointers are widely used in C programming.
Pointers are often used when working with arrays.
Computer memory can be thought of as a sequence of numbered single-byte cells that can be accessed individually or in blocks.
Each variable in memory has its own address - the number of the first cell where it is located, as well as its value. A pointer is also a variable that is allocated in memory. It also has an address, and its value is the address of some other variable. A variable declared as a pointer occupies 4 bytes in RAM (in the case of a 32-bit version of the compiler).
A pointer, like any variable, must be declared.
сhar c; // variable
char *p; // pointer
p = &c; // p = address of c
Look at this exammple:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a, *b;
system("chcp 1251");
system("cls");
a = 134;
b = &a;
// %x = display the number in hexadecimal form
printf("\n The value of the variable a is %d = %x hex.", a,a);
printf("\n The address of the variable a is %x hex.", &a);
printf("\n Data at pointer address b are equal %d = %x hex.", *b,*b);
printf("\n The value of b pointer is %x hex.", b);
printf("\n Location address of pointer b is %x hex.", &b);
getchar();
return 0;
}

Pointers, structure, passing arguments, recursion

I have code like this:
typedef struct _Statistics {
Some code here
} Statistics;
void function1(char *string, Statistics *statistic){
Some code here
function1(string1, statistic);
}
int main(){
Statistics statistic;
function1(string, &statistic);
}
This is probably idiotic question, but I don't understand pointers completely:
I understand why I use & in main function, & send address of variable statistic, so that in function1 I can modify it. But why don't I use & in recursive function1?
Because &statistic (in function1()) is the memory address of the pointer, not the address contained by the pointer.
The type of &statistic is Statistics** in function1().
Few words about pointers
Let's say we define the following variables:
char c = 'a';
char *p_c = &c;
Now, we will print the values and memory addresses of p_c and c:
printf("%c\n", c); // will print 'a'
printf("%c\n", *p_c); // will print 'a'
printf("%p\n", &c); // will print the memory address of c
printf("%p\n", p_c); // will print the memory address of c
printf("%p\n", &p_c); // will print the memory address of p_c
Finally we define a char**, a pointer to a pointer to char:
char **p_pc = &p_c;
printf("%c\n", **p_pc); // will print 'a'
printf("%p\n", *p_c); // will print the memory address of c
printf("%p\n", p_c); // will print the memory address of p_c
Sometimes it helps to write it this way:
void function1(char* string, Statistics* statistic){
The variable statistic is a pointer to Statistics, not the Statistics itself. If you did this in function1:
function1(string1, &statistic);
You would be passing a pointer to (because of the &) a pointer to (because of the * in the declaration) Statistics, which would be incorrect.
Your declaration of statistic in main as Statistic adds to the confusion: you're using the same variable name with different types in the two scopes.
With different variable names it's clearer:
typedef struct _Statistics {
Some code here
} Statistics;
void function1(char* string, Statistics* ptrstat){
Some code here
function1(string1, ptrstat);
}
int main(){
Statistics statistic;
function1(string, &statistic);
}
In general (i.e. most languages), you can pass by value or pass by reference. It will depend on the definition of the function and its 'signature'; i.e. the way it and its arguments are declared.
Pass-by-value is like an assignment and, if copying a larger structure, it will take longer. Also, the function only receives a copy, so you can make changes to the argument in the function, but that will only effect the function's local copy (the argument) and will make NO change to the original value (in the caller) that was passed to you.
By contrast, pass-by-reference simply passes a pointer (the address in memory) of the original value. This is much faster, (4 or 8 bytes), but it does means that the function can not only read but also write the caller's value. Sometimes you want this! Sometimes you don't.
In your main, you have the value of statistics. The function you are calling expects the address (*), so instead of passing the value, (statistic), you need to pass its address, (&statistic).
In the function, calling itself, you have a pointer to statistic (Statistics *) and you must pass a pointer to statistic (Statistics *): hence, just pass it, the pointer 'statistic'.

parameter passing in C function

I have a function written in C
FindBeginKey(KeyListTraverser, BeginPage, BeginKey, key1);
BeginKey is a pointer before function invoking, and I didn't initiate it, like
BeginKey = NULL;
In the FindBeginKey() function, I assign BeginKey to another pointer, and try to print out the current address of BeginKey in the function, it works correct.
But when code returns from function, I try to print out the address of BeginKey again, it shows 0x0.
Why does this happen, and if I want to preserve the address assigned in the function, what should I do?
To pass a value out of a function you have to pass by reference rather than by value as is normally the case with C functions. TO do this make the parameter a pointer to the type you want to pass out. Then pass the value into the call with the & (address operand).
e.g.
FindFoo(FOO** BeginKey);
and call it:
FindFoo(&BeginKey);
and in the function:
*BeginKey = 0xDEADC0DE;
From what I understand, you are calling the function like:
FindBeginKey(KeyListTraverser, BeginPage, BeginKey, key1);
However, when you try to write at the BeginKey address, you're basically passing in a pointer to 0x00. Rather, you need to pass a pointer to BeginKey.
FindBeginKey(KeyListTraverser, BeginPage, &BeginKey, key1);
If this is isn't what you meant, it would certainly help if you posted a code sample.
If you want to modify a parameter in a subroutine, you should pass a pointer of the thing you wanna modify.
void subroutine(int* x) {
*x = 5; // will modify the variable which x points to
x = 5; // INVALID! x is a pointer, not an integer
}
I don't know what all the C parameter passing rules are now, so this answer might be a little dated. From common practice in building applications and libraries that those applications called, the return from a C function would contain status, so the caller of the function could make a decision depending on the status code.
If you wanted the function to modify its input parameters, you would pass those parameters by reference &my_val, where int my_val;. And your function must dereference my_val like this *my_val to get its value.
Also, for performance reasons, and address (by reference) might be preferable, so that the your application did not bother copying the parameter's value into a local variable. That prolog code is generated by the compiler. Single parameters, char, int, and so on are fairly straight forward.
I am so used to C++ that passing by reference in C++ does not require dereferencing. The compiler's code takes care of that for you.
However, think about passing a pointer to a structure.
struct my_struct
{
int iType;
char szName[100];
} struct1;
struct my_struct *pStruct1 = &struct1;
If the structure contains lookup data that is filled in once on initialization and then referenced throughout your program, then pass a pointer to the structure by value pStruct1. If you are writing a function to fill that structure or alter already present data, then pass a pointer to the structure by value. You still get to alter what the structure pointer points to.
If on the other hand you are writing a function to assign memory to the pointer, then pass the address of the pointer (a pointer to the pointer) &pStruct1, so you will get your pointer pointing to the right memory.

What could be the possible reason behind the warning which comes up when the following piece of code is compiled

This is a simple piece of code which i wrote to check whether it is legitimate to return the address of a local variable and my assumptions were proved correct by the compiler which gives a warning saying the same:
warning: function returns address of local variable
But the correct address is printed when executed... Seems strange!
#include<stdio.h>
char * returnAddress();
main()
{
char *ptr;
ptr = returnAddress();
printf("%p\n",ptr);
}
char * returnAddress()
{
int x;
printf("%p\n",&x);
return &x;
}
The behaviour is undefined.
Anything is allowed to happen when you invoke undefined behaviour - including behaving semi-sanely.
The address of a local variable is returned. It remains an address; it might even be a valid address if you're lucky. What you get if you access the data that it points to is anyone's guess - though you're best off not knowing. If you call another function, the space pointed at could be overwritten by new data.
You should be getting warnings about the conversion between int pointer and char pointer - as well as warnings about returning the address of a local variable.
What you are trying to do is usually dangerous:
In returnAddress() you declare a local, non-static variable i on the stack. Then you return its address which will be invalid once the function returned.
Additionally you try to return a char * while you actually have an int *.
To get rid of the warning caused by returning a pointer to a local var, you could use this code:
void *p = &x;
return p;
Of course printing it is completely harmless but dereferencing (e.g. int x = *ptr;) it would likely crash your program.
However, what you are doing is a great way to break things - other people might not know that you return an invalid pointer that must never be dereferenced.
Yes, the same address is printed both times. Except that, when the address is printed in main(), it no longer points to any valid memory address. (The variable x was created in the stack frame of returnAddress(), which was scrapped when the function returned.)
That's why the warning is generated: Because you now have an address that you must not use.
Because you can access the memory of the local variable, doesn't mean it is a correct thing to do. After the end of a function call, the stack pointer backtracks to its previous position in memory, so you could access the local variables of the function, as they are not erased. But there is no guaranty that such a thing won't fail (like a segmentation fault), or that you won't read garbages.
Which warning? I get a type error (you're returning an int* but the type says char*) and a warning about returning the address of a local variable.
The type error is because the type you've declared for the function is lies (or statistics?).
The second is because that is a crazy thing to do. That address is going to be smack in the middle (or rather, near the top) of the stack. If you use it you'll be stomping on data (or have your data stomped on by subsequent function calls).
Its not strange. The local variables of a function is allocated in the stack of that function. Once the control goes out of the function, the local variables are invalid. You may have the reference to the address but the same space of memory can be replaced by some other values. This is why the behavior is undefined. If you want reference a memory throughout your program, allocate using malloc. This will allocate the memory in heap instead of stack. You can safely reference it until you free the memory explicitly.
#include<stdio.h>
#include<stdlib.h>
char * returnAddress();
main()
{
char *ptr;
ptr = returnAddress();
printf("%p\n",ptr);
}
char * returnAddress()
{
char *x = malloc(sizeof(char));
printf("%p\n",x);
return x;
}

C stack/scope, variable's lifetime after functions ends

void someFunc()
{
int stackInt = 4;
someOtherFunc(&stackInt);
}
Is it the case that stackInt's address space could be reallocated after someFunc ends, making it unsafe to assume that the value passed to someOtherFunc represents the stackInt variable with value 4 that was passed to it? In other words, should I avoid passing stack variables around by address and expecting them to still be alive after the function they were initialised in has ended?
Yes, definitely.
You don't have to avoid passing stack-allocated variables by reference/pointer altogether, though, just storing pointers or references to stack-allocated variables.
After someFunc() returns and another function is called, the space that was used for stackInt will be used for some other variable in the new function. Therefore, the function someOtherFunc() cannot safely assume that if it keeps a copy of the pointer it is passed, that pointer will remain valid. If it stashes a copy of the value that was pointed at, that is fine.
So, although it is fine to pass stack variables around by address (so, for example someOtherFunc() could modify the value of stackInt and, if there was code in someFunc() that accessed it after the call, the value might not be 4 still), it is not safe to store the pointer and expect it to point to anywhere valid after someFunc() returns.
It is absolutely fine to pass stack variables as parameters in all possible ways
The stack allocated variables will be overwritten only when the function declaring those variables is completed its execution.
So until you return from someFunc() there is no harm to stackInt.
As long as you don't spawn new thread from someOtherFunc and use stackInt there, this will work.

Resources