Pointer arithmetic

Sep 7, 2011 at 8:43am
Hello.

Today in my C++-lesson I tought pointer arithmetic.
This was my example:
1
2
3
4
5
6
7
8
9
int main(){	
	int a = 7;
	int b = 5;
	int c = 4;
	int* x = &c;		
	x++;	
	cout << "Adresse " << &x << " : " << x <<  " Deref: " << *x <<endl ;	
	return 0;
}

The output is:
Adresse 0x22ff30 : 0x22ff38 Deref: 5

The value 5 is in my opinion the correct output of *x .

Than I tried a shorter output (without address and value of x). This is the code:

1
2
3
4
5
6
7
8
9
int main(){	
	int a = 7;
	int b = 5;
	int c = 4;
	int* x = &c;		
	x++;	
	cout << *x <<endl; //In my opinion no big difference to the first code	
	return 0;
}

The output is:
2293572


I can't explain myself the different output (*x --> 2293572???). Who can explain this behaviour?

Thanks.

Daniel
Last edited on Sep 7, 2011 at 9:07am
Sep 7, 2011 at 9:17am
My guess - and thats all what it is, I'm no expert, but programmed some assembler before -

It's somehow random but reproducible - more precisely I think its because the way a CPU stores stuff in it's registers. As far as I know a variable declared does not always need to have a memory address (if it fits the registers). Once you created a second pointer ( by << &x) somehow your variables a, b were pushed to memory. A proof for this theory might be that the memory addresses of a, b, c are reversed! So in your sec example your pointer *x just points to some random value @ &c+4 now in your first example thats the exact position where b is pushed to and you get some defined output!
Last edited on Sep 7, 2011 at 9:18am
Sep 7, 2011 at 9:40am
random in this case means: don't use such undefined behavior! Who knows where the compiler decides to store it's data? So x++ just points to randomness!
Sep 7, 2011 at 9:50am
closed account (1vRz3TCk)
It is possibly to do with debug settings. Have you run both pieces of code with the same settings?

In release mode you may expect that the memory would be laid out something like this:
+---+---+---+---+---+---+---+---+---+---+---+---+
|     x     |     c     |     b     |     a     |
+---+-|-+---+---+---+---+---+---+---+---+---+---+
      |       ^
      +-------+

When you increment x by one int [1] you would expect the following
+---+---+---+---+---+---+---+---+---+---+---+---+
|     x     |     c     |     b     |     a     |
+---+-|-+---+---+---+---+---+---+---+---+---+---+
      |                   ^
      +-------------------+


Now in debugging the memory is likely to have some 'padding' between variables to aid debugging, so may look like this:
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|     x     |  pad  |     c     |  pad  |     b     |  pad  |     a     |
+---+-|-+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
      |               ^
      +---------------+

but now when you increment the point by an int (3 bytes) it points to the padding not the next int.
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|     x     |  pad  |     c     |  pad  |     b     |  pad  |     a     |
+---+-|-+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
      |                           ^
      +---------------------------+


Edit:
There is also no guarantee that the variables will be placed next to each other in memory anyway.
_______________________
[1] this fictional view has a 3 byte int.
Last edited on Sep 7, 2011 at 10:13am
Sep 7, 2011 at 9:55am
The value 5 is in my opinion the correct output of *x .


That's not correct. You increment the pointer not the pointed to value.
If you want *x to be 5 use this code.
1
2
3
4
5
6
7
8
9
int main(){	
	int a = 7;
	int b = 5;
	int c = 4;
	int* x = &c;		
	(*x)++;
	cout << "Adresse " << &x << " : " << x <<  " Deref: " << *x <<endl ;	
	return 0;
}
Sep 7, 2011 at 10:58am
closed account (1vRz3TCk)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>

using namespace std;

int main()
{	
		
	int a = 1;
	int b = 2;
	int c = 3;
	int* x = &c;		

    cout << "Address of a : " << &a << endl ;
    cout << "Address of b : " << &b << " (" << int(&a) - int(&b) << " byte from previous address)" << endl ;
    cout << "Address of c : " << &c << " (" << int(&b) - int(&c) << " byte from previous address)" << endl ;
    cout << "Address of x : " << &x << " (" << int(&c) - int(&x) << " byte from previous address)" << endl ;

    cout << "x = &c" << endl;
	cout << "x points to address : " << x <<  " That has the value " << *x << endl ;	

    x++;
    cout << "x++" << endl;
    cout << "x points to address : " << x <<  " That has the value " << *x << endl ;

    cout << *x << endl ;

	return 0;

}

Release mode output:
Address of a : 0036FBA4
Address of b : 0036FBA0 (4 byte from previous address)
Address of c : 0036FB9C (4 byte from previous address)
Address of x : 0036FB98 (4 byte from previous address)
x = &c
x points to address : 0036FB9C That has the value 3
x++
x points to address : 0036FBA0 That has the value 2
2


debug mode output:
Address of a : 0030FD14
Address of b : 0030FD08 (12 byte from previous address)
Address of c : 0030FCFC (12 byte from previous address)
Address of x : 0030FCF0 (12 byte from previous address)
x = &c
x points to address : 0030FCFC That has the value 3
x++
x points to address : 0030FD00 That has the value -858993460
-858993460
Sep 7, 2011 at 2:56pm
Thanks for your answers.

@onur: I want to increase the pointer, not the value. My aim was to point after this operation on memory slot of variable b. So the first behavior is the aimed behavior.

@CodeMonkey: I compiled this code with MinGw. Both programms with the same settings. I also watched the address in both programms. In all cases it is the address of variable b, so &b == x is true.
@ZED0815: In both programms the variables have correct addresses, the condition &b == x is in both cases true. I'm not sure, but I think in both case the CPU should store this variables immediately to the memory. But I never programmed assembler. Such behaviour would be dangerous.

Thanks for your ideas.

Last edited on Sep 7, 2011 at 8:13pm
Sep 7, 2011 at 4:46pm
Pointer arithmetic is a dangerous thing and except rare cases when dealing directly with hardware (e.g. writing a device driver that need to send some data to the given address) there is no use for it in application programming.
Sep 7, 2011 at 5:43pm
Pointer arithmetic [..] there is no use for it in application programming.

That's simply not true.
Sep 7, 2011 at 5:49pm
Pointer arithmetic is a dangerous thing and except rare cases when dealing directly with hardware (e.g. writing a device driver that need to send some data to the given address) there is no use for it in application programming.


Ah, I think I see the problem here. Firstly, "Pointer arithmetic" is not used when sending data to a given address. That is simply manually setting a pointer value, for example like this:

somePointer = (int*)0xFFEE1000; This is not pointer arithmetic.

The second issue here is that our chum has decided that because he finds little use for something, it's useless. I see this a lot; it's generally born of very narrow experience. It's right up there with comments like "Nobody codes in C anymore" and "There's no need for low-level languages because processors are fast these days".

I expect to be reading this sort of thing forever :)
Last edited on Sep 7, 2011 at 5:51pm
Sep 7, 2011 at 6:11pm
closed account (D80DSL3A)
Any program which uses an array will make use of pointer arithmetic.
Examples:
1
2
3
int x[] = {2,4,6,8,10};
int y = x[3];// pointer arithmetic is used here. Dereference is implicit with this "array notation".
y = *(x+2);// here y=6. This pointer notation makes the pointer arithmetic being done obvious. 

Try writing a sort routine without using pointer arithmetic!

Regarding the original example: Is it safe to assume that several int variables will be assigned to adjacent memory addresses? I thought that this is far from guaranteed .
Sep 7, 2011 at 8:13pm
Until today I has thought variables which are declared in succession will be assigned to adjacent memory. I thought a variable will push to stack at the moment of declaration. So their addresses should be successive. But now I'm uncertain.
Last edited on Sep 7, 2011 at 8:20pm
Sep 7, 2011 at 8:41pm
Actually I was told a few days ago when asking a related question that declaring three different variables and assuming them to be in a row in memory is dangerous business!!!
Sep 7, 2011 at 9:06pm
Yes. It's horribly dangerous.
Sep 9, 2011 at 7:13am
I know such ussage of pointer arithmetic is very dangerous and nobody should do that (excepted handling arrays). But I'm still suprised about this different behaviour of this nearly equal code. Sorry, but that's why C++ is not my favourite language for programming user programms.
Last edited on Sep 9, 2011 at 7:16am
Sep 9, 2011 at 7:16am
But I'm still suprised about this different behaviour of this nearly equal code.


That's because relying on undefined behavior is...undefined.
Sep 9, 2011 at 7:29am
Sorry, but that's why C++ is not my favourite language for programming user programms.


The only way to have such consistency is to have guarantees about the hardware and the operating system's use of the hardware, or to abstract that away with some kind of intermediate layer. That's an enormous additional burden with the associated costs.
Topic archived. No new replies allowed.