views:

306

answers:

6

Given this code:

int *p, *q;

p = (int *) 1000;
q = (int *) 2000;

What is q - p and how?

A: 

As p is pointing to an int and so q, q-p will be 1000.

Algorist
divided by sizeof(int)
Pascal Cuoq
I'm sorry, but this is wrong.
Randy Stegbauer
@Pascal Why do we need to divide it by sizeof(int)?
NLV
They're pointers, so you're risking a lot by doing it this way... but yeah, integer math is integer math whether you're doing it right or not...
GalacticCowboy
Leaving to others the considerations about casts between `int` and `int*`, there remains the fact that `(int)(p+1)` is equal to `((int)p)+sizeof(int)`. Similarly, when you subtract pointers, as in `(p+1)-p`, you get the result `1`. But if you subtract after casting, as in `((int)(p+1)) - ((int)p)`, you get `sizeof(int)`.
Pascal Cuoq
+14  A: 

It's actually undefined, according to the standard. Pointer arithmetic is not guaranteed to work unless the pointers are pointing to either an element in the same array or just beyond the last element of the array.

The relevant section of the standard is 6.5.6:9 (n1362 draft of c1x but this hasn't changed since c99) which states:

When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; the result is the difference of the subscripts of the two array elements.

You'll most likely get 250 if your int datatype is 4 bytes but there's no guarantee. Undefined behaviour (unlike implementation-defined behaviour) means just that. Anything can happen, up to an including the total destruction of a large proportion of space-time.

A refresher course:

  • Defined behaviour is what is mandated by the standard. Implementations must do this to be conformant.
  • Implementation-defined behaviour is left up to the implementation but it must document that behaviour clearly. Use this if you don't care too much about portability.
  • Undefined behaviour means anything can happen. Don't ever do that!
paxdiablo
This is the right answer, however I guess everyone wants to believe that the answer will be 1000/sizeof(int) anyway. Oh well!
Alok
+7  A: 

q - p is 250.

2000 - 1000 = 1000
1000 / sizeof(int) = 250

pointer arithmetic, assuming sizeof(int) is 4.


Edit: OK, to clarify. In C when two pointers are of the same type then the difference between them is defined the number of things of the pointed-to type between them. For example,

struct foo { int ar[1000]; } big[10];
char small[10];

struct foo *fs, *fe;
char *ss, *se;

fs = &big[0]; fe = &big[9];
ss = &small[0]; se = &small[9];

fe - fs == se - ss;

That is, the difference between the two pointers in this case is the number of array elements between them. In this case it is 0, 1, ... 8 or 9 elements.

Richard Pennington
This is what i was looking for. I dont bother about the -1 for my question. Why are you dividing 1000/sizeof(int)?
NLV
You're better off stating "if sizeof(int) is 4". That's because sizeof(char) is *always* 1.
paxdiablo
@paxdiablo: Right. Brain freeze.
Richard Pennington
+2  A: 

Those are pointers ... assigned to the address 1000, and 2000 ... looking for troubles?

fabrizioM
+2  A: 

q-p supposed to return how many steps with increment you should do to go from p to q. Which is 1000 / sizeof(int) and equals 250. Remember q++ will actually go to the next element of type int, not in the middle of it, so it should add 4 to the actual value of the pointer. Hence the result.

vava
+2  A: 

The answer: q-p is going to be 250, assuming you're on a machine where an int is 4 bytes.

The calculation is:

q - p = 1000 1000 / 4 (size of an int) = 250

The idea behind it:

The idea behind pointer arithmetic is that, if you have an int pointer to 1000 and an int pointer to 2000, and ask for the difference, you're not asking what's 2000-1000. What you're asking is, how many int's can I fit between the two.

This is very convenient for all sorts of operations, for example:

int *i = 100;
i++; // This is **not** 101, it is 104, cause you actually want the next place an int could fit in memory.

This especially comes in handy when dealing with arrays. An array of ints (defined int arr[10]) is basically treated like a pointer. When you write arr[5], the compiler translates it to *(arr + 5), i.e., add 5 to the int pointer called arr, and get the value at that address.

The reason this works, is because arr + 5 does not mean "add 5 to the value of arr", it means "add whatever is neceassary to the value of arr to go forward 5 ints", or, more precisely, "add 5 * sizeof(int) to the value of arr"

Edan Maor