Pointers in C

P

Praveen

Hi,

I came across a program as follows
main()
{
int x, y ;
int *p1 = &x;
int *p2 = &y;
printf("%d\n", p1-p2);
}

The output of the above program is 1.
Can some one explain me how it is 1.
Thanks in advance.
 
I

Ian Collins

Praveen said:
Hi,

I came across a program as follows
main()
{
int x, y ;
int *p1 = &x;
int *p2 = &y;
printf("%d\n", p1-p2);
}

The output of the above program is 1.
Can some one explain me how it is 1.

Because that's what your compiler gives as the answer, subtracting two
unrelated pointers is undefined behaviour.
 
C

Chris Dollin

Raman said:
Can Some onr tell why these are unrelated?

They're not part of the same object [1]. (Stack frames are not objects,
even in implementations that have stack frames, from C's POV.)

[1] Which covers `malloc` results too.
 
S

Stuart

Can Some onr tell why these are unrelated?

To be related they must have some common reference point - the source of the
relationship. If there is no common reference point how can there be a
relationship? The language standard will define what types of relationship
exist between different components defined in a program text.

In what way do you believe the pointers are related? What makes you believe
this? Can you find a citation in the language standard that supports this
belief?
 
K

Keith Thompson

Raman said:
Can Some onr tell why these are unrelated?

Because they point to distinct objects.

Here's what the standard says in the section on relational operators
(<, <=, >, >=) (C99 6.5.8p5):

When two pointers are compared, the result depends on the relative
locations in the address space of the objects pointed to. If two
pointers to object or incomplete types both point to the same
object, or both point one past the last element of the same array
object, they compare equal. If the objects pointed to are members
of the same aggregate object, pointers to structure members
declared later compare greater than pointers to members declared
earlier in the structure, and pointers to array elements with
larger subscript values compare greater than pointers to elements
of the same array with lower subscript values. All pointers to
members of the same union object compare equal. If the expression
P points to an element of an array object and the expression Q
points to the last element of the same array object, the pointer
expression Q+1 compares greater than P. In all other cases, the
behavior is undefined.

(A non-array object is treated as an array of one element.)
 
R

Richard Heathfield

Praveen said:
Hi,

I came across a program as follows
main()
{
int x, y ;
int *p1 = &x;
int *p2 = &y;
printf("%d\n", p1-p2);
}

The output of the above program is 1.
Can some one explain me how it is 1.

Even if the pointer arithmetic were legal (which others have already
pointed out, so I won't belabour it here), the call to printf is not.
Whether the (undefined) result of your illegal pointer arithmetic is
reported correctly by printf is undefined, because you failed to
provide a valid function prototype within the current scope at the
point of call to a variable argument function.

Headers are not decorative. They matter. In future, if you call printf,
do this:

#include <stdio.h>
 
R

rafalp

Praveen said:
I came across a program as follows
main()
{
int x, y ;
int *p1 = &x;
int *p2 = &y;
printf("%d\n", p1-p2);
}

The output of the above program is 1.
Can some one explain me how it is 1.

Well, if you change the last line to

printf("%d\n", (char*)p1-(char*)p2);

you will get 4, ie sizeof(int), instead of 1. Is that what you expected?
In pointer arithmetic the distance between two pointers is measured in
number of object of pointer's type that would fit between the memory
locations pointed by the pointers. Thus with array

int a[10]

you can access the second element by a[1] or by *(a + 1). We add 1 to
the actual pointer but in fact compiler adds 4 or sizeof(int) to the
pointer.

Hope that helps.
 
R

Richard Heathfield

rafalp said:

Well, if you change the last line to

printf("%d\n", (char*)p1-(char*)p2);

you will get 4, ie sizeof(int), instead of 1.

No, the behaviour will still be undefined, for two separate reasons.
 
R

rafalp

Richard said:
rafalp said:


No, the behaviour will still be undefined, for two separate reasons.

You're right. I should have written "you will get value >= sizeof(int)"
instead.
 
R

Richard Heathfield

rafalp said:
You're right. I should have written "you will get value >=
sizeof(int)" instead.

No, you should have written something like "the value you get, if any,
is not defined by the rules of C - to get a well-defined result, write
a well-defined program".
 
R

Richard Tobin

You're right. I should have written "you will get value >=
sizeof(int)" instead.

No, you should have written something like "the value you get, if any,
is not defined by the rules of C - to get a well-defined result, write
a well-defined program".[/QUOTE]

If the system the OP is using has a flat address space, and uses those
addresses for C pointers, and performs subtraction of pointers to
distinct objects as if they were in the same object, then he will get
sizeof(int).

-- Richard
 
R

Richard Heathfield

Richard Tobin said:
No, you should have written something like "the value you get, if any,
is not defined by the rules of C - to get a well-defined result, write
a well-defined program".

If the system the OP is using has a flat address space, and uses those
addresses for C pointers, and performs subtraction of pointers to
distinct objects as if they were in the same object, then he will get
sizeof(int).[/QUOTE]

The C Standard doesn't guarantee this, and no implementation is under
any obligation to provide that behaviour (even setting aside the fact
that there's no prototype in scope for printf and thus the behaviour is
undefined for another reason). Nothing in the rules says that x and y
have to be placed adjacently to each other in memory.

And yet I would like to provide a data point, of no relevance to the
guarantees provided by the Standard, and based purely on empirical
observation on one particular platform (a C8S16ILP32 system with a flat
address space), which seems to echo your point in a very strange way
indeed:

$ cat foo.c
#include <stdio.h>
int main(void)
{
int x;
int y = 1;
int z;
char *p = (char *)&x;
char *q = (char *)&z;
printf("%d\n", (int)(p - q) * y);
return 0;
}
$ ./foo
4

The incursion of y between x and z makes no difference, on this system.

And even if I get y's value at runtime, making it impossible to optimise
it away:

#include <stdio.h>

int main(void)
{
int x;
int y;
int z;
char *p = (char *)&x;
char *q = (char *)&z;
if(scanf("%d", &y) == 1)
{
printf("%d\n", (int)(p - q) * y);
}
return 0;
}

and provide 1 as an input, I *still* get an output of 4. Obviously the
program's behaviour is undefined, but common-sense observation suggests
that the compiler is placing x and z contiguously in memory even though
they are not defined adjacently. Incidentally, swapping y and z around
in the declaration order makes no difference. My compiler is determined
to keep x and z together, come what may. They were made for each other.
 
S

santosh

rafalp said:
Well, if you change the last line to

printf("%d\n", (char*)p1-(char*)p2);

you will get 4, ie sizeof(int), instead of 1. Is that what you expected?

The only thing you and the OP should expect is undefined behaviour.
You're both having the assumption that x and y are placed adjacently
in memory: something that's not required by the C standard.

Thus with array

int a[10]

you can access the second element by a[1] or by *(a + 1). We add 1 to
the actual pointer but in fact compiler adds 4 or sizeof(int) to the
pointer.

The Standard does not nail down the size of an int at four bytes. It
must be atleast >= sizeof(char) and 16 bits. For example under DOS
sizeof(int) is likely to be two.
Hope that helps.

Hope your post doesn't confuse the OP.
 
C

Clark S. Cox III

rafalp said:
You're right. I should have written "you will get value >= sizeof(int)"
instead.

Still not true. For instance, you have no guarantee that p2 > p1, or
that subtracting them will actually yield *any* value much less any
*particular* value. The behavior is completely undefined.
 
R

Richard Tobin

If the system the OP is using has a flat address space, and uses those
addresses for C pointers, and performs subtraction of pointers to
distinct objects as if they were in the same object, then he will get
sizeof(int).
[/QUOTE]
The C Standard doesn't guarantee this, and no implementation is under
any obligation to provide that behaviour (even setting aside the fact
that there's no prototype in scope for printf and thus the behaviour is
undefined for another reason). Nothing in the rules says that x and y
have to be placed adjacently to each other in memory.

Quite so, but we know that they are adjacent on the OP's system (given
the assumptions I listed). Of course, it's possible that adding the
casts to char * may change that, but I doubt it.

For years, the unix crypt program relied on two arrays being contiguous.
A case of unwarranted chumminess with the compiler, which worked until
someone used a different compiler.

-- Richard
 
S

santosh

santosh said:
rafalp wrote:
Thus with array

int a[10]

you can access the second element by a[1] or by *(a + 1). We add 1 to
the actual pointer but in fact compiler adds 4 or sizeof(int) to the
pointer.

The Standard does not nail down the size of an int at four bytes. It
must be atleast >= sizeof(char) and 16 bits. For example under DOS
sizeof(int) is likely to be two.

Correction. sizeof(int) must be atleast >= sizeof(short).
 
R

Richard Heathfield

santosh said:
santosh said:
rafalp wrote:
Thus with array

int a[10]

you can access the second element by a[1] or by *(a + 1). We add 1
to the actual pointer but in fact compiler adds 4 or sizeof(int) to
the pointer.

The Standard does not nail down the size of an int at four bytes. It
must be atleast >= sizeof(char) and 16 bits. For example under DOS
sizeof(int) is likely to be two.

Correction. sizeof(int) must be atleast >= sizeof(short).

Not quite. It is true that the range of values of int must equal or
exceed the range of values of short, but the Standard does not forbid
the presence of padding bits in short, such that sizeof(short) >
sizeof(int). Weird but true. (I doubt very much whether any implementor
would be silly enough to do this, however.)
 
S

santosh

Richard said:
santosh said:
santosh said:
rafalp wrote:

Thus with array

int a[10]

you can access the second element by a[1] or by *(a + 1). We add 1
to the actual pointer but in fact compiler adds 4 or sizeof(int) to
the pointer.

The Standard does not nail down the size of an int at four bytes. It
must be atleast >= sizeof(char) and 16 bits. For example under DOS
sizeof(int) is likely to be two.

Correction. sizeof(int) must be atleast >= sizeof(short).

Not quite. It is true that the range of values of int must equal or
exceed the range of values of short, but the Standard does not forbid
the presence of padding bits in short, such that sizeof(short) >
sizeof(int). Weird but true. (I doubt very much whether any implementor
would be silly enough to do this, however.)

Thanks. Something slightly related: does CHAR_BIT include padding bits?
 
R

rafalp

santosh said:
The only thing you and the OP should expect is undefined behaviour.
You're both having the assumption that x and y are placed adjacently
in memory: something that's not required by the C standard.

We should expect that pointer difference between two distinct objects of
the same type is greater or equal than size of that object type. And
that is what the question was about. The question, put it in other
words, might be: "the program outputs 1 and sizeof(int) == 4 (in this
case), so does it mean that x and y overlap in memory?". I think that it
is common among beginners to assume that pointer arithmetic works just
like int arithmetic.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,076
Latest member
OrderKetoBeez

Latest Threads

Top