C/Pointers
From Attie's Wiki
(Difference between revisions)
m |
m (Attie moved page C\Pointers to C/Pointers without leaving a redirect) |
||
(14 intermediate revisions by one user not shown) | |||
Line 1: | Line 1: | ||
− | A helper for people starting out with pointers | + | A helper for people starting out with pointers.<br> |
+ | For more guidance and words, see [[Pointers with words]] | ||
==test.c== | ==test.c== | ||
Line 5: | Line 6: | ||
#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 26: | Line 26: | ||
P( p[1] ); | P( p[1] ); | ||
− | P( *p[1] ); | + | P( *p[1] ); /* this probably doesn't evaulate to what you think it does... be explicit */ |
− | P( (*p)[1] ); | + | P( (*p)[1] ); /* you probably meant this */ |
− | P( *(p[1]) ); | + | P( *(p[1]) ); /* NOT this */ |
P( (*p) ); | P( (*p) ); | ||
− | P( (*p)++ ); | + | P( (*p)++ ); /* this will modify the s variable */ |
P( (*p)[0] ); | P( (*p)[0] ); | ||
P( (*p) ); | P( (*p) ); | ||
− | P( ++(*p) ); | + | P( ++(*p) ); /* this will modify the s variable */ |
P( (*p)[0] ); | P( (*p)[0] ); | ||
P( (*p) ); | P( (*p) ); | ||
+ | |||
+ | P( s ); | ||
return 0; | return 0; | ||
Line 43: | Line 45: | ||
==Output== | ==Output== | ||
+ | Note the difference between <code>*p[1]</code>, <code>(*p)[1]</code> and <code>*(p[1])</code>. | ||
<source lang="text"> | <source lang="text"> | ||
$ gcc test.c -o test && ./test | $ gcc test.c -o test && ./test | ||
Line 53: | Line 56: | ||
p[0]: 0x8048734 <-- the address of the 'c' | p[0]: 0x8048734 <-- the address of the 'c' | ||
*p: 0x8048734 <-- the address of the 'c' | *p: 0x8048734 <-- the address of the 'c' | ||
− | p[1]: 0x8048680 <-- INVALID - the value stored just after the variable | + | 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]: 0x55 <-- INVALID - the value stored at location 0x8048680 (again, the program may segfault here) | ||
(*p)[1]: 0x62 <-- the 'b' | (*p)[1]: 0x62 <-- the 'b' | ||
*(p[1]): 0x55 <-- INVALID - the same as *p[1] | *(p[1]): 0x55 <-- INVALID - the same as *p[1] | ||
(*p): 0x8048734 <-- the address of the 'c' | (*p): 0x8048734 <-- the address of the 'c' | ||
− | (*p)++: 0x8048734 <-- the address of the 'c' - the pointer is POST incremented | + | (*p)++: 0x8048734 <-- the address of the 'c' - the pointer (s) is POST incremented |
(*p)[0]: 0x62 <-- the 'b' | (*p)[0]: 0x62 <-- the 'b' | ||
(*p): 0x8048735 <-- the address of the 'b' | (*p): 0x8048735 <-- the address of the 'b' | ||
− | ++(*p): 0x8048736 <-- the address of the 'a' - the pointer is PRE incremented | + | ++(*p): 0x8048736 <-- the address of the 'a' - the pointer (s) is PRE incremented |
(*p)[0]: 0x61 <-- the 'a' | (*p)[0]: 0x61 <-- the 'a' | ||
(*p): 0x8048736 <-- the address of the 'a' | (*p): 0x8048736 <-- the address of the 'a' | ||
+ | s: 0x8048736 <-- the address of the 'a' | ||
</source> | </source> | ||
==Memory Map== | ==Memory Map== | ||
− | {| | + | This map relates to the execution trace above<br> |
− | | | + | These values and addresses will probably be different each time you run the program<br> |
+ | Accessing memory that has been marked as not valid in this table is a '''bad''' idea. It will very commonly make your program SEGFAULT | ||
+ | {|border="1" cellpadding="0" | ||
+ | ! Address !! Value !! ASCII !! Variable !! Valid? !! colspan="2" | Notes | ||
+ | |- | ||
+ | | colspan="7" | ... | ||
+ | |- | ||
+ | | 0xBF893E93 || style="color:red" | 0x08 || ||? (MSB) || style="color:red" | '''No''' || colspan="2" | | ||
|- | |- | ||
− | | | + | | 0xBF893E92 || style="color:red" | 0x04 || ||? || style="color:red" | '''No''' || colspan="2" | |
|- | |- | ||
− | | | + | | 0xBF893E91 || style="color:red" | 0x86 || ||? || style="color:red" | '''No''' || colspan="2" | |
|- | |- | ||
− | | | + | | 0xBF893E90 || style="color:red" | 0x80 || ||? (LSB) || style="color:red" | '''No''' || This is p[1] || 0xBF893E8C + (sizeof(char*) * 1) → 0xBF893E8C + (4 * 1) → 0xBF893E8C + 4 → 0xBF893E90 |
|- | |- | ||
− | | | + | | 0xBF893E8F || style="color:#4B2" | 0x08 || || s (MSB) || Yes || colspan="2" | |
|- | |- | ||
− | | | + | | 0xBF893E8E || style="color:#4B2" | 0x04 || || s || Yes || colspan="2" | |
|- | |- | ||
− | | | + | | 0xBF893E8D || style="color:#4B2" | 0x87 || || s || Yes || colspan="2" | |
|- | |- | ||
− | | | + | | style="color:blue" | 0xBF893E8C || style="color:#4B2" | 0x34 || || s (LSB) || Yes || This is p[0] || 0xBF893E8C + (sizeof(char*) * 0) → 0xBF893E8C + (4 * 0) → 0xBF893E8C + 0 → 0xBF893E8C |
|- | |- | ||
− | | | + | | 0xBF893E8B || style="color:blue" | 0xBF || || p (MSB) || Yes || colspan="2" | |
|- | |- | ||
− | | | + | | 0xBF893E8A || style="color:blue" | 0x89 || || p || Yes || colspan="2" | |
|- | |- | ||
− | | | + | | 0xBF893E89 || style="color:blue" | 0x3E || || p || Yes || colspan="2" | |
|- | |- | ||
− | | | + | | 0xBF893E88 || style="color:blue" | 0x8C || || p (LSB) || Yes || colspan="2" | |
|- | |- | ||
− | | | + | | colspan="7" | ... |
|- | |- | ||
− | | | + | | 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 |
|- | |- | ||
− | | | + | | style="color:#4B2" | 0x08048734 || 0x63 || 'c' || || Yes || This is s[0] || 0x08048734 + (sizeof(char) * 0) → 0x08048734 + (1 * 0) → 0x08048734 + 0 → 0x08048734 |
|- | |- | ||
− | | | + | | colspan="7" | ... |
|- | |- | ||
− | | | + | | style="color:red" | 0x08048680 || 0x55 || || || style="color:red" | '''No''' || colspan="2" | This is *p[1] or *(p[1]) |
|- | |- | ||
− | | | + | | colspan="7" | ... |
|} | |} |
Latest revision as of 17:09, 14 February 2013
A helper for people starting out with pointers.
For more guidance and words, see Pointers with words
[edit] 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; }
[edit] 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'
[edit] 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]) | |||
... |