Pointers The Pointer Defined int *x; Read as: declare x as a - - PowerPoint PPT Presentation
Pointers The Pointer Defined int *x; Read as: declare x as a - - PowerPoint PPT Presentation
Pointers The Pointer Defined int *x; Read as: declare x as a pointer to a 32-bit integer Interpretation: declare x as a variable on the stack that holds the numeric address of the location in memory at which are 32 bits that we intend
The Pointer Defined
- int *x;
- Read as: declare x as a pointer to a 32-bit integer
- Interpretation: declare x as a variable on the stack that holds the
numeric address of the location in memory at which are 32 bits that we intend to manipulate as a signed integer
- sizeof(x) is the word-size of the machine in bytes
- on a 32 bit machine that can address 2^32 bytes of memory, 4
- on a 64 bit machine, 8
- etc
- sizeof(*x) is 4, or sizeof(int)
Pointer Dereferencing
- There are two fundamental ways to manipulate or obtain
(dereference) memory through this pointer:
- *x
- Read as: dereference x
- Interpretation: set(if left of equals) or get(if right of equals) 32 bits of
memory interpreted as a signed integer beginning at the memory address contained in variable x
Pointer Dereferencing Continued
- x[i]
- Read as: the (i + 1)st element of array x (indices start at 0)
- Interpretation: set or get 32 bits of memory interpreted as a signed
integer beginning at the memory address computed as address + (i * sizeof(type))
- For all examples that follow, assume x contains the value 10000, i.e.
x refers to the 10000th byte of memory
- x[5] will manipulate or obtain the 32 bit signed integer beginning at
address (10000 + (5 * 4)), or 10020
Arrays Versus Pointers
- int x[256];
- This is a declaration of 256 contiguous 4-byte integers on the stack (1024 bytes total)
- The identifier x is a pointer to an integer that points to this stack location, and it can never point anywhere
else
- int *x;
- This is a declaration of a pointer to an integer that does not refer to any location until it is assigned a value (for
example using the & operator or via malloc)
- It can point to any address in memory, stack or heap, and its value can be changed dynamically
- RHS use of either identifier x operates almost identically; use either as a pointer to one-to-many
integers, or deference either to obtain an single integer
- Can’t put the array-char-pointer on the LHS (i.e. can’t say x = something, but can say
x[index] = something) (this makes sense if you think about it)
- Compiler generates instructions to compute the exact stack-pointer-relative address for any
chosen element of the array when using an array; it can do this because it knows it’s contiguous
- Compiler generates instructions to compute the pointer-value-relative address for any chosen
element of the array when using a pointer
Array Storage
10000 10004 10008 10012 10016 10020 10024 10028 10032 10036 10040 int *x; 10000 1st 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 1 2 3 4 5 6 7 8 9 10 11 10044 100 x[5]=100;
Implications of the Pointer-type
- The CPU *does not* make any assumptions about how to interpret
any piece of memory, you must explicitly tell it how to do so
- The compiler does all pointer arithmetic using the guidance you gave
it via the type you declared that the pointer points to
- The compiler chooses machine instructions to generate for the CPU
based upon the type you declared that the pointer points to
Implications of the Pointer-Type continued
- Previous example demonstrated operations on 4 byte values and pointer
arithmetic by 4-byte values because an int is represented as 4 bytes
- If x were declared as: char *x;
- Operations on 1 byte signed integers
- *x refers to address 10000
- x[5] refers to address 10005
- If x were declared as: short *x;
- Operations on 2 byte signed integers
- *x refers to address 10000
- x[5] refers to address 10010
- If x were declared as unsigned long long *x;
- Operations on 8 byte unsigned integers
- *x refers to address 10000
- x[5] refers to address 10040
Pointer Manipulation
- C allows you to “add-to” or “subtract-from” a pointer by using
mathematical operators + and –
- C doesn’t add the addend to the address directly, but performs the
following computation:
- address = address + (addend * sizeof(type))
- Interpretation: when you add one to a pointer, it causes the pointer to
point to the address of the next contiguous piece of memory of sizeof(type)
- Semantic equivalent: were x pointing to the ith element of an array in
memory, it’s the equivalent of setting x to point to the (i+1)st element
- As discussed, dereferencing an array causes a comparable computation:
- &x[i] = x + (i * sizeof(type)
Pointers to Pointers
- int **x;
- Read as: declare x as a pointer to a pointer to a 32-bit integer
- Interpretation: declare x as a variable on the stack that holds the
numeric address at which is another numeric address at which are 32 bits that we intend to manipulate as a signed integer
- sizeof(x) is the word size of the machine in bytes
- sizeof(*x) is also the word size of the machine (it’s an int*)
- sizeof(**x) is 4, or sizeof(int)
Multi-Dimensional Arrays Versus Pointers
- int x[256][10];
- This is a declaration of a contiguous pool of stack memory that we intend to interpret as 256 “rows” of 10 “columns”, each
holding a 4-byte integer for a total of 256*10*4 = 10240 bytes of memory.
- The identifier x is a pointer to a pointer to an integer that points to the beginning of this pool on the stack, and it can never
point anywhere else
- int **x;
- This is a declaration of a pointer to a pointer to an integer that does not refer to any location until it is assigned a value (for
example using the & operator or via malloc)
- It can point to any address in memory, stack or heap, and its value can be changed dynamically
- RHS use of either identifier x operates almost identically; use either as a pointer to pointer to one-to-many
integers, or deference either twice to obtain an single integer
- Can’t put the array-char-p2p on the LHS (i.e. can’t say x = something, but can say x[index] =
something)
- Compiler generates instructions to compute the exact stack-pointer-relative address for any chosen element
- f the array when using an array; it can do this because it knows it’s contiguous
- Compiler generates instructions to compute the pointer-value-relative addresses for any chosen element of
the array when using a pointer
Stack-Based Multi-Dimensional Array Storage
int x[4][6]; 10000 10000 10004 10008 10012 10016 10020 10024 10048 10072
7th 8th 9th 10th 11th 12th 1st 2nd 3rd 4th 5th 6th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 1 2 3 4 5
x[3][2] = 100; 100
Allocated & deallocated automatically via stack advancement & retreat Total storage of a 3x5 array of integers is (3x5) * 4
Heap-Based Multi-Dimensional Array Storage
Must be allocated iteratively via malloc Must be freed iteratively via free Total storage of a 3x5 array of integers is (3x(5+1)) * 4
10000 10004 10008 10012 10016 10020 10024 10028 10032 10036 10040 int **x; 10000 1st 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 1 2 3 4 5 6 7 8 9 10 11 10044 100000 100004 100008 100012 100016 100020 1st 2nd 3rd 4th 5th 1 2 3 4 5 100000 int *x; 100 x[5][2] = 100
Pointer Casting
- int i = 5;
- char *y = (char *)(&i);
- Declares i as an integer on the stack and puts 5 in that location, then
declares y as a pointer to a character and assigns the address of i casted (interpreted as) to a pointer to a character to it.
- &i and y both have the same numeric value pointing to the same
piece of memory
- Dereferencing y hereafter generates instructions that operate on
chars at i’s memory address instead of integers
Pointer Casting Example
enum integral_type { ITYPE_CHAR = 0, ITYPE_SHORT, ITYPE_INT, ITYPE_LONGLONG }; void doublevalue(void *pointer_to_integral_type, enum integral_type data_type) { if(pointer_to_integral_type == NULL) return; switch(data_type) { case ITYPE_CHAR: // doubles the 8-bit value found at pointer *((char *)pointer_to_integral_type) *= 2; break;
case ITYPE_SHORT: // doubles the 16 bit value found at pointer *((short *)pointer_to_integral_type) *= 2; break; case ITYPE_INT: // doubles the 32 bit value found at pointer *((int *)pointer_to_integral_type) *= 2; break; case ITYPE_LONGLONG: // doubles the 64 bit value found at pointer *((long long *)pointer_to_integral_type) *= 2; break; default: return; } }