pointers chainging in a function call?


D

David Jackson

I'm having a weird problem where a function gets a different value of a
pointer than what was passed to it. I haven't been able to make a small
example that duplicates the error but here's an example to show what I mean:

#include <stdio.h>

void f(int * p);

int main(void) {
int x;
int * px = &x;

x = 23;
printf("px=%p\n", px);

f(px);

return 0;
}

void f(int * p) {
printf("p=%p\n", p);
}

So if this example would behave the way my program does, when I pass a
pointer to a function like this it prints out a different address in the
printf statement inside the function, so somehow the function recieves a
different value than what was passed to it! There are no statements
between the printf in the main function and the program is not
multithreaded so its not a case of the pointer being overwritten
somewhere in between. Does anybody have any idea what could cause this
to happen? This is probably a stupid mistake on my part but I'm really
stuck so if anybody has a suggestion please tell me.

If it makes any difference, in my program the function f is in a
different file.
 
Ad

Advertisements

M

Mark A. Odell

I'm having a weird problem where a function gets a different value of a
pointer than what was passed to it. I haven't been able to make a small
example that duplicates the error but here's an example to show what I
mean:

#include <stdio.h>

void f(int * p);

int main(void) {
int x;
int * px = &x;

x = 23;
printf("px=%p\n", px);

I think px should be cast to (void *) for the %p format specifier.
f(px);

return 0;
}

void f(int * p) {
printf("p=%p\n", p);
}

What happens if you change f() to:

void f(int **p)
{
printf("*p=%p\n", (void *) *p);
}

Remember, pointers are variables too, so if you want to see the pointers
value and not what it points to then pass a pointer to a pointer. E.g. in
this case you really had pointer 'a' pointing to 'x' and pointer 'b'
pointing to 'x'.
 
D

David Rubin

David said:
I'm having a weird problem where a function gets a different value of a
pointer than what was passed to it. I haven't been able to make a small
example that duplicates the error but here's an example to show what I mean:

#include <stdio.h>

void f(int * p);

int main(void) {
int x;
int * px = &x;

x = 23;
printf("px=%p\n", px);

printf("px=%p\n", (void *)px);
f(px);

return 0;
}

void f(int * p) {
printf("p=%p\n", p);

printf("p=%p\n", (void *)p);

Your compiler should have warned you:

pbv.c: In function `f':
pbv.c:10: warning: void format, different type arg (arg 2)
pbv.c: In function `main':
pbv.c:18: warning: void format, different type arg (arg 2)

Otherwise, you are invoking UB.

/david
 
E

Eric Sosman

David said:
I'm having a weird problem where a function gets a different value of a
pointer than what was passed to it. I haven't been able to make a small
example that duplicates the error but here's an example to show what I mean:

There's nothing (much) wrong with the paraphrase you provide,
so the problem most likely lies elsewhere in your program. For
what it's worth:
int * px = &x;
[...]
printf("px=%p\n", px);

.... is incorrect, because the "%p" conversion takes a corresponding
`void*' argument and `px' is not a `void*' but an `int*'. On most
machines nowadays you'll get away with this, but it *is* wrong and
there's a small chance this error has something to do with the
problem you're seeing. When something mysterious is going on, it's
a good idea to fix *all* detected problems, even if you can't see
how they'd have anything to do with the mystery -- after all, it's
a mystery, meaning that you don't really understand it, meaning
that you're not in a good position to rule out its interaction
with other flaws.
[...]
void f(int * p) {
printf("p=%p\n", p);
}
[...]
If it makes any difference, in my program the function f is in a
different file.

It might make a difference, if (for example) the other file
failed to #include <stdio.h>. You'd get more answers and fewer
speculations if you posted actual code instead of approximations.
 
C

crazy

David Jackson said:
I'm having a weird problem where a function gets a different value of a
pointer than what was passed to it. I haven't been able to make a small
example that duplicates the error but here's an example to show what I mean:

#include <stdio.h>

void f(int * p);

int main(void) {
int x;
int * px = &x;

x = 23;
printf("px=%p\n", px);

f(px);

I think there is your problem. You are passing by value.
Hence variable int *p is a copy of this variable with same value
but different address.
use f(&px); instead
 
E

Eric Sosman

crazy said:
I think there is your problem. You are passing by value.
Hence variable int *p is a copy of this variable with same value
but different address.
use f(&px); instead

No; there's nothing wrong with the call. Since `px' has
already been set equal to `&x', f(px) and f(&x) are identical.
The situation is analogous to

void g(int x);
...
int i = 4;
g(i); // same as below
g(4); // same as above
 
Ad

Advertisements

C

crazy

crazy said:
I think there is your problem. You are passing by value.
Hence variable int *p is a copy of this variable with same value
but different address.
use f(&px); instead

sorry. don't know what i was thinking.
 
M

Michael Str.

David Jackson said:
I'm having a weird problem where a function gets a different value of a
pointer than what was passed to it. I haven't been able to make a small
example that duplicates the error but here's an example to show what I mean:

#include <stdio.h>

void f(int * p);

int main(void) {
int x;
int * px = &x;

x = 23;
printf("px=%p\n", px);

f(px);

return 0;
}

void f(int * p) {
printf("p=%p\n", p);
}

So if this example would behave the way my program does, when I pass a
pointer to a function like this it prints out a different address in the
printf statement inside the function, so somehow the function recieves a
different value than what was passed to it! There are no statements
between the printf in the main function and the program is not
multithreaded so its not a case of the pointer being overwritten
somewhere in between. Does anybody have any idea what could cause this
to happen? This is probably a stupid mistake on my part but I'm really
stuck so if anybody has a suggestion please tell me.

Hi !
I feel your problem is here:
If it makes any difference, in my program the function f is in a
different file.

Be sure, that you have not problems with function prototypes.
For example, in your file, that contain main() function, there are no
prototype
for function f(). Or, file that contains function f() doesn't include
<stdio.h> or something else. So, when calling f(),his argument may
treaten not as a pointer type either as an integer.

Try to avoid "any difference". The problem may be exactly there.
By the way, your code as you write here is complete right.

Regards
Michael
 
D

David Jackson

Thanks for the tips. I found out it was because the function was being
called with an extra argument which wasn't supposed to be there which
caused one pointer to be replaced with another and I didn't notice
because I didn't have a template in the header file for that function.
 
C

CBFalconer

Michael Str. said:
.... snip ...

By the way, your code as you write here is complete right.

Not quite. He should cast the pointer arguments to printf to
(void *). Then his code is correct, and gives the expected
results. The OP should create a simplified complete set of files
that exhibit his problem and post those (NOT attached).
 
M

Michael Str.

CBFalconer said:
Not quite. He should cast the pointer arguments to printf to
(void *). Then his code is correct, and gives the expected
results. The OP should create a simplified complete set of files
that exhibit his problem and post those (NOT attached).


I just want refer you to [email protected] 2nd edition:

"A.6.8 Pointers to Void
Any pointer to an object may be converted to type void * without loss
of information. If the result is
converted back to the original pointer type, the original pointer is
recovered. Unlike the pointer-topointer
conversions discussed in Par.A.6.6, which generally require an
explicit cast, pointers may be
assigned to and from pointers of type void *, and may be compared with
them."

So, because in "printf" %p defined as a poiner to void, you can pass
pointer of any type without explicit casting.

Other examles - functions "malloc" and "free".

Regards
Michael
 
Ad

Advertisements

B

Barry Schwarz

I just want refer you to [email protected] 2nd edition:

"A.6.8 Pointers to Void
Any pointer to an object may be converted to type void * without loss
of information. If the result is
converted back to the original pointer type, the original pointer is
recovered. Unlike the pointer-topointer
conversions discussed in Par.A.6.6, which generally require an
explicit cast, pointers may be
assigned to and from pointers of type void *, and may be compared with
them."

So, because in "printf" %p defined as a poiner to void, you can pass
pointer of any type without explicit casting.
This would be true if the prototype for printf indicated the parameter
was a pointer to void. Since printf is actually a variadic function,
the prototype does specify the type of the parameters so you must
convert the argument explicitly in the function call by using a cast.

Consider the following:
int i, *pi = &i;
char format1[] = "This statement stores a result in %p.%n\n";
/* some non-trivial code */
printf(format1, /* (void*) */ pi, pi);

The first format specification requires the corresponding argument to
be void*. The second specification requires its argument to be int*.
The compiler would have no way of knowing if format1 had been modified
and therefore could not determine that the second argument should be
converted to void*. Nor could it convert all pointers in a printf
call since the third argument must not be converted from int* to
void*. **You** have to provide the cast so the compiler knows exactly
what should be done.


<<Remove the del for email>>
 
C

CBFalconer

Michael Str. said:
.... snip ...
.... snip ...

So, because in "printf" %p defined as a poiner to void, you can pass
pointer of any type without explicit casting.

Other examles - functions "malloc" and "free".

malloc and free are not variadic functions. The only means printf
has to know the type of an argument is the conversion
specification, which is NOT known at compile time (the spec may be
a variable string). Thus a parameter referenced via %p MUST be
cast to void *.
 
M

Micah Cowan

I just want refer you to [email protected] 2nd edition:

"A.6.8 Pointers to Void
Any pointer to an object may be converted to type void * without loss
of information. If the result is
converted back to the original pointer type, the original pointer is
recovered. Unlike the pointer-topointer
conversions discussed in Par.A.6.6, which generally require an
explicit cast, pointers may be
assigned to and from pointers of type void *, and may be compared with
them."

So, because in "printf" %p defined as a poiner to void, you can pass
pointer of any type without explicit casting.

Other examles - functions "malloc" and "free".

There is a huge difference here. The problem is that printf() is
a variadic function, and so the compiler will not perform such
implicit conversions, because the prototype of printf() doesn't
say it takes a (void*) for that argument, it says "...", which
means it'll take pretty much anything you give it (after certain
promotions). Now, if pointers-to-int happen to be represented
differently from pointers-to-void, you're screwed, since the
compiler had no way to know what printf() happened to expect
there, so it won't convert it to void*.

And your quote above has actually nothing to do with any of
this. Just because something may be converted to void* without
loss of information, doesn't mean it will automajically be
converted in that way when you don't tell it to. Implicit
conversions aren't defined in that way: they are defined in terms
of the operators used to do the conversion (notably the =
operator, which is also used to define what conversions are made
to function arguments--but only when the type of the expected
argument is known, which in this case it is not).

malloc() and free() work fine for non-pointers-to-void, not
because a pointer-to-object can be converted to pointer-to-void
without loss of information (though that plays an important
role), but because the appropriate prototype is (hopefully) in
scope, and the conversion is done "as if by assignment" due to
completely other rules.

-Micah
 
Ad

Advertisements

M

Michael Str.

I just want refer you to [email protected] 2nd edition:

"A.6.8 Pointers to Void
Any pointer to an object may be converted to type void * without loss
of information. If the result is
converted back to the original pointer type, the original pointer is
recovered. Unlike the pointer-topointer
conversions discussed in Par.A.6.6, which generally require an
explicit cast, pointers may be
assigned to and from pointers of type void *, and may be compared with
them."

So, because in "printf" %p defined as a poiner to void, you can pass
pointer of any type without explicit casting.

Other examles - functions "malloc" and "free".

Regards
Michael


Thank you so much.

I was wrong.
It is really need explicit casting.
If "int*" has other internal representation or size than "void*" ,
it may be conflict. And pointer will not be treaten right in "printf".

Michael

regards
Michael
 

Top