What happened here: when you switch to the function conferir
the variable p
, it does just that: the value of p
. However, any change that affects the value of p
within the function does not interfere in the world outside the function. In compensation, you change a value pointed by p
is quite different.
Shall we do a table test? I will "run" the program and track its internal states, as it would run after being compiled by GCC or equivalent. Consider here integers and pointers with 1 bytes for simplicity
First, we start the program. We have the following stack:
00: $$1 # v,v[0]
01: $$2 # v[0]
02: $$3 # v[1]
03: $$4 # v[1]
04: $$5 # v[2]
05: $$6 # v[2]
06: $$7 # v[3]
07: $$8 # v[3]
08: $$9 # v[4]
09: $$A # v[4]
0A: $$B # num
0B: $$C # num
0C: $$D # p
0D: $$E # p
All with junk in memory (because they haven’t been initialized). So let’s go to scanf(&num)
. Let’s assume the person came in with 1
:
00: $$1 # *v,v[0]
01: $$2 # v[0]
02: $$3 # v[1]
03: $$4 # v[1]
04: $$5 # v[2]
05: $$6 # v[2]
06: $$7 # v[3]
07: $$8 # v[3]
08: $$9 # v[4]
09: $$A # v[4]
0A: 1 # num
0B: 0 # num
0C: $$D # p
0D: $$E # p
So we call the function conferir
. In this case, the compiler understands that we should copy the values of the variables and indicate to the function that they are in their range. We would see globally so the memory:
00: $$1 # v,v[0]
01: $$2 # v[0]
02: $$3 # v[1]
03: $$4 # v[1]
04: $$5 # v[2]
05: $$6 # v[2]
06: $$7 # v[3]
07: $$8 # v[3]
08: $$9 # v[4]
09: $$A # v[4]
0A: 1 # num
0B: 0 # num
0C: $$D # p
0D: $$E # p
0E: $$D # (conferir) p
0F: $$E # (conferir) p
10: 1 # (conferir) numero
11: 0 # (conferir) numero
12: &0G # (conferir) vetor
13: &0G # (conferir) vetor
14: 0 # (conferir) i
15: 0 # (conferir) i
16: 0 # (conferir) flag
17: 0 # (conferir) flag
Note that I am using the notation "&0G
" to indicate that it is a pointer to the "memory position" "0" in the "global" scope, not to be confused with whole variables or with the "local positioning" shown below
Locally, we would see something like this:
-6: $$D # p
-5: $$E # p
-4: 1 # numero
-3: 0 # numero
-2: &0G # vetor
-1: &0G # vetor
00: 0 # i
01: 0 # i
02: 0 # flag
03: 0 # flag
In doing p = &i
, this is what happens:
-6: &14G # p
-5: &14G # p
-4: 1 # numero
-3: 0 # numero
-2: &0G # vetor
-1: &0G # vetor
00: 5 # i
01: 0 # i
02: $$X # flag
03: $$Y # flag
In the global vision:
00: $$1 # v,v[0]
01: $$2 # v[0]
02: $$3 # v[1]
03: $$4 # v[1]
04: $$5 # v[2]
05: $$6 # v[2]
06: $$7 # v[3]
07: $$8 # v[3]
08: $$9 # v[4]
09: $$A # v[4]
0A: 1 # num
0B: 0 # num
0C: $$D # p
0D: $$E # p
0E: &14G # (conferir) p
0F: &14G # (conferir) p
10: 1 # (conferir) numero
11: 0 # (conferir) numero
12: &0G # (conferir) vetor
13: &0G # (conferir) vetor
14: 5 # (conferir) i
15: 0 # (conferir) i
16: $$X # (conferir) flag
17: $$Y # (conferir) flag
Note that the memory value at the positions 0C
and 0D
were unchanged. When the call returns, we "virtually" lose the function stack, getting just that:
00: $$1 # v,v[0]
01: $$2 # v[0]
02: $$3 # v[1]
03: $$4 # v[1]
04: $$5 # v[2]
05: $$6 # v[2]
06: $$7 # v[3]
07: $$8 # v[3]
08: $$9 # v[4]
09: $$A # v[4]
0A: 1 # num
0B: 0 # num
0C: $$D # p
0D: $$E # p
Which is exactly the previous state. But, how to solve this? The desired behavior would somehow make "global" the value of i
without using a return
.
To this end, the first thing to pay attention is that we do not wish to change the value of p
within of the function, but the value pointed for p
. That means what to do p = XXX;
is a sin because it would be altering the value of p
. To change the value pointed by p
, we need to do *p = XXX;
. Read more.
The other thing we need to take care of is that we need a memory region adequate to that end. And a junk in the pointer variable will not help us with that. So we have two options:
- point to a known local variable (should be created at that time)
- dynamically create a memory space to receive this value
The second approach I won’t even explore here, I just quoted it so you can study further later. In the case of the first, my suggestion is:
- have any variable integer in
main
(let’s call it qualquer
)
- no pointer type variables in
main
- move to function
conferir
the address of the variable qualquer
This would be the modified section:
int conferir(int vetor[], int numero, int *p)
{
int i=0, flag=0;
for(i = 0;i < 5; i++){
if(numero == vetor[i]){
flag = 1;
break;
}
}
*p = i;
return flag;
}
int main()
{
int v[5], num=0;
int qualquer;
printf("Digite o número para ser conferido com o vetor:\n");
scanf("%d", &num);
if(conferir(v,num,&qualquer) == 1){
...
Running the table test:
00: $$1 # v,v[0]
01: $$2 # v[0]
02: $$3 # v[1]
03: $$4 # v[1]
04: $$5 # v[2]
05: $$6 # v[2]
06: $$7 # v[3]
07: $$8 # v[3]
08: $$9 # v[4]
09: $$A # v[4]
0A: $$B # num
0B: $$C # num
0C: $$D # qualquer
0D: $$E # qualquer
All with junk in memory (because they haven’t been initialized). So let’s go to scanf(&num)
. Let’s assume the person came in with 1
:
00: $$1 # *v,v[0]
01: $$2 # v[0]
02: $$3 # v[1]
03: $$4 # v[1]
04: $$5 # v[2]
05: $$6 # v[2]
06: $$7 # v[3]
07: $$8 # v[3]
08: $$9 # v[4]
09: $$A # v[4]
0A: 1 # num
0B: 0 # num
0C: $$D # qualquer
0D: $$E # qualquer
So we call the function conferir
. In this case, the compiler understands that we should copy the values of the variables and indicate to the function that they are in their range. We would see globally so the memory:
00: $$1 # v,v[0]
01: $$2 # v[0]
02: $$3 # v[1]
03: $$4 # v[1]
04: $$5 # v[2]
05: $$6 # v[2]
06: $$7 # v[3]
07: $$8 # v[3]
08: $$9 # v[4]
09: $$A # v[4]
0A: 1 # num
0B: 0 # num
0C: $$D # qualquer
0D: $$E # qualquer
0E: &CG # (conferir) p
0F: &CG # (conferir) p
10: 1 # (conferir) numero
11: 0 # (conferir) numero
12: &0G # (conferir) vetor
13: &0G # (conferir) vetor
14: 0 # (conferir) i
15: 0 # (conferir) i
16: 0 # (conferir) flag
17: 0 # (conferir) flag
Note that I am using the notation "&0G
" to indicate that it is a pointer to the "memory position" "0" in the "global" scope, not to be confused with whole variables or with the "local positioning" shown below
Locally, we would see something like this:
-6: &CG # p
-5: &CG # p
-4: 1 # numero
-3: 0 # numero
-2: &0G # vetor
-1: &0G # vetor
00: 0 # i
01: 0 # i
02: 0 # flag
03: 0 # flag
In doing *p = i
, this is what happens:
-6: &CG # p
-5: &CG # p
-4: 1 # numero
-3: 0 # numero
-2: &0G # vetor
-1: &0G # vetor
00: 5 # i
01: 0 # i
02: $$X # flag
03: $$Y # flag
In the global vision:
00: $$1 # v,v[0]
01: $$2 # v[0]
02: $$3 # v[1]
03: $$4 # v[1]
04: $$5 # v[2]
05: $$6 # v[2]
06: $$7 # v[3]
07: $$8 # v[3]
08: $$9 # v[4]
09: $$A # v[4]
0A: 1 # num
0B: 0 # num
0C: 5 # qualquer
0D: 0 # qualquer
0E: &CG # (conferir) p
0F: &CG # (conferir) p
10: 1 # (conferir) numero
11: 0 # (conferir) numero
12: &0G # (conferir) vetor
13: &0G # (conferir) vetor
14: 0 # (conferir) i
15: 0 # (conferir) i
16: $$X # (conferir) flag
17: $$Y # (conferir) flag
When returning from the function and "pop" its variables, we have:
00: $$1 # v,v[0]
01: $$2 # v[0]
02: $$3 # v[1]
03: $$4 # v[1]
04: $$5 # v[2]
05: $$6 # v[2]
06: $$7 # v[3]
07: $$8 # v[3]
08: $$9 # v[4]
09: $$A # v[4]
0A: 1 # num
0B: 0 # num
0C: 5 # qualquer
0D: 0 # qualquer
With due side effect, which was to change the value of the variable qualquer
.
Wow, I was hoping for a solution, but not as well-crafted and didactic, thank you very much for the answer and the attention!
– placementw
@placementw, my answer is more didactic than strictly correct. Expecting a technically perfect response from Maniero
– Jefferson Quesado