C/Pointers
From Attie's Wiki
(Difference between revisions)
m |
m |
||
Line 5: | Line 5: | ||
#include <stdio.h> | #include <stdio.h> | ||
#include <stdlib.h> | #include <stdlib.h> | ||
− | |||
#define P(expr) printf("%10s: 0x%02X\n", #expr, expr) | #define P(expr) printf("%10s: 0x%02X\n", #expr, expr) | ||
Line 115: | Line 114: | ||
| colspan="7" | ... | | colspan="7" | ... | ||
|- | |- | ||
− | | style="color:red" | 0x08048680 || 0x55 || || || style="color:red" | '''No''' || colspan="2" | | + | | style="color:red" | 0x08048680 || 0x55 || || || style="color:red" | '''No''' || colspan="2" | This is *p[1] or *(p[1]) |
|- | |- | ||
| colspan="7" | ... | | colspan="7" | ... | ||
|} | |} |
Revision as of 22:53, 9 March 2012
A helper for people starting out with pointers:
test.c
#include <stdio.h> #include <stdlib.h> #define P(expr) printf("%10s: 0x%02X\n", #expr, expr) int main(void) { char *s = "cba"; char **p = &s; P( s ); P( &s ); P( s[0] ); P( *s ); P( p ); P( &p ); P( p[0] ); P( *p ); P( p[1] ); P( *p[1] ); /* this probably doesn't evaulate to what you think it does... be explicit */ P( (*p)[1] ); /* you probably meant this */ P( *(p[1]) ); /* NOT this */ P( (*p) ); P( (*p)++ ); /* this will modify the s variable */ P( (*p)[0] ); P( (*p) ); P( ++(*p) ); /* this will modify the s variable */ P( (*p)[0] ); P( (*p) ); P( s ); return 0; }
Output
Note the difference between *p[1]
, (*p)[1]
and *(p[1])
.
$ gcc test.c -o test && ./test s: 0x8048734 <-- the address of the 'c' &s: 0xBF893E8C <-- the address of the variable s s[0]: 0x63 <-- the 'c' *s: 0x63 <-- the 'c' p: 0xBF893E8C <-- the address of the variable s &p: 0xBF893E88 <-- the address of the variable p p[0]: 0x8048734 <-- the address of the 'c' *p: 0x8048734 <-- the address of the 'c' p[1]: 0x8048680 <-- INVALID - the value stored just after the variable s (the program may segfault here) *p[1]: 0x55 <-- INVALID - the value stored at location 0x8048680 (again, the program may segfault here) (*p)[1]: 0x62 <-- the 'b' *(p[1]): 0x55 <-- INVALID - the same as *p[1] (*p): 0x8048734 <-- the address of the 'c' (*p)++: 0x8048734 <-- the address of the 'c' - the pointer (s) is POST incremented (*p)[0]: 0x62 <-- the 'b' (*p): 0x8048735 <-- the address of the 'b' ++(*p): 0x8048736 <-- the address of the 'a' - the pointer (s) is PRE incremented (*p)[0]: 0x61 <-- the 'a' (*p): 0x8048736 <-- the address of the 'a' s: 0x8048736 <-- the address of the 'a'
Memory Map
This map relates to the execution trace above
These values and addresses will probably be different each time you run the program
Accessing memory that has been marked as not valid in this table is a bad idea. It will very commonly make your program SEGFAULT
Address | Value | ASCII | Variable | Valid? | Notes | |
---|---|---|---|---|---|---|
... | ||||||
0xBF893E93 | 0x08 | ? (MSB) | No | |||
0xBF893E92 | 0x04 | ? | No | |||
0xBF893E91 | 0x86 | ? | No | |||
0xBF893E90 | 0x80 | ? (LSB) | No | This is p[1] | 0xBF893E8C + (sizeof(char*) * 1) → 0xBF893E8C + (4 * 1) → 0xBF893E8C + 4 → 0xBF893E90 | |
0xBF893E8F | 0x08 | s (MSB) | Yes | |||
0xBF893E8E | 0x04 | s | Yes | |||
0xBF893E8D | 0x87 | s | Yes | |||
0xBF893E8C | 0x34 | s (LSB) | Yes | This is p[0] | 0xBF893E8C + (sizeof(char*) * 0) → 0xBF893E8C + (4 * 0) → 0xBF893E8C + 0 → 0xBF893E8C | |
0xBF893E8B | 0xBF | p (MSB) | Yes | |||
0xBF893E8A | 0x89 | p | Yes | |||
0xBF893E89 | 0x3E | p | Yes | |||
0xBF893E88 | 0x8C | p (LSB) | Yes | |||
... | ||||||
0x08048737 | 0x00 | '\0' | Yes | This is s[3] | 0x08048734 + (sizeof(char) * 3) → 0x08048734 + (1 * 3) → 0x08048734 + 3 → 0x08048737 | |
0x08048736 | 0x61 | 'a' | Yes | This is s[2] | 0x08048734 + (sizeof(char) * 2) → 0x08048734 + (1 * 2) → 0x08048734 + 2 → 0x08048736 | |
0x08048735 | 0x62 | 'b' | Yes | This is s[1] | 0x08048734 + (sizeof(char) * 1) → 0x08048734 + (1 * 1) → 0x08048734 + 1 → 0x08048735 | |
0x08048734 | 0x63 | 'c' | Yes | This is s[0] | 0x08048734 + (sizeof(char) * 0) → 0x08048734 + (1 * 0) → 0x08048734 + 0 → 0x08048734 | |
... | ||||||
0x08048680 | 0x55 | No | This is *p[1] or *(p[1]) | |||
... |