220 likes | 867 Views
Pointer Arithmetic. A pointer variable stores the address of a memory location. Adding an integer k to a pointer variable p with base type t makes p point to the memory location k *sizeof( t ) bytes below.
E N D
Pointer Arithmetic • A pointer variable stores the address of a memory location. • Adding an integer k to a pointer variable p with base type t makes p point to the memory location k*sizeof(t) bytes below. • For example, adding 1 to an integer pointer will make it point 4 bytes (or, in other words one int-size slot) away int arr[10]; /* arrray of 10 integers */ int *pnum; /* pointer to int */ pnum = arr; /* now pnum contains the address of (it points to) the first element of the array */ pnum = pnum +2; /* now pnum contains the address of the array element at index 2. For example, if originally pnum contained address 100, now it contains address 100 + 2 * 4 = 108 */
Example 1 code memory int *pnum, *plist, number; int array[4] = {10,20,30,40}; 100 pnum: junk 104 plist: junk 108 number: junk array, 112 10 116 20 120 30 124 40 continued on next slide
Example 1 code memory 100 pnum: 108 pnum = &number; *pnum = 16; 104 plist: junk 108 number: 16 array, 112 10 * says: follow the arrow to get to the memory location that this pointer is pointing to. 116 20 120 30 124 40 continued on next slide
Example 1 code memory 100 pnum: 108 plist = array + 1; *(plist + 1) = 17; *(plist + 2) = *(plist + 1) - 5 ; 104 plist: 116 108 number: 16 array, 112 10 116 20 120 17 124 12
Example 2 int main () { double grades[5], *pgrade; int i; pgrade = grades; for (i = 0; i < 5; i++) { printf("Type a grade: "); scanf("%Lf", pgrade + i); printf("You typed %d\n", *(pgrade+i)); } return 0; } scanf takes as argument the address where the value should be stored
Pointers vs. arrays • The name of an array represents the address where the array begins. • In other words, the name of an array is a pointer. • HOWEVER, it is a const pointer. It cannot be changed! • Pointer variables on the other hand allow greater flexibility since they are not constant. int numbers[10], list[10]; numbers = list; ILLEGAL!
Pointers vs. arrays • When declaring an array, we need to specify its size at the time we write the program. • The size of an array cannot change when the program runs (it is static) • Pointers allow us to create structures like arrays whose size can be determined dynamically (at the time the program runs) ILLEGAL! int size; int numbers[size]; scanf("%d", &size);
Pointers vs. arrays • Arrays : the name of an array represents the address in memory where the array begins. • Our goal : Allocate a block of memory as big as we want (dynamically, at runtime) and get the address where this block begins. • We can then use this block as if it was an array • This can be done by using function malloc
malloc • Takes as argumentthe size of the block that we want to allocate. • Returns a pointer to the beginning of the block (in other words, it returns the address of the first byte of the block). • If the allocation has not been successful, it returns NULL. • NULL is a special location in memory that is guaranteed to NOT contain any valid data. • To use malloc, #include<stdlib.h>
malloc int *pnums; pnums = (int *)malloc (10 * sizeof(int)); allocate 10 "boxes" in memory, each one of which should be large enough for an int. Return a pointer (address) to the first box Typecast it as (int*) since it points to an int. Assign the returned address to pnums
malloc int *pnums; pnums = (int *)malloc (10 * sizeof(int)); Why do we need the typecast? malloc has to be able to return a pointer to any type. Its return value is actually void * void * is a generic declaration. It needs to be cast to a specific pointer type
malloc int *pnums; pnums = (int *)malloc (10 * sizeof(int)); sizeof() is a function that returns the size (in bytes) of its argument. e.g. sizeof(int) returns 4 So we are allocating a total of 40 bytes.
malloc int *pnums; pnums = (int *)malloc (10 * sizeof(int)); A snapshot of memory: pnums, 100: 512 512: 40 bytes
malloc and free When memory that has been allocated using malloc is not needed any longer it should be released. This is done using function free() int main () { int *pnums; pnums = (int *) malloc (10 * sizeof(int)); /* ... */ free(pnums); /* deallocate memory */ return 0; } There should be one free() for every malloc() !
malloc and free CAREFUL! The parameter of free() should be a pointer that points to the beginning of the space that needs to be deallocated! int main () { int *pnums; pnums = (int *) malloc (10 * sizeof(int)); pnums++; free(pnums); /* WRONG! pnums does not point to the beginning of the space allocated by malloc! */ return 0; }
malloc and free CAREFUL! The parameter of free() should be a pointer that points to the beginning of the space that needs to be deallocated! int main () { int *pnums, *plist; pnums = (int *) malloc (10 * sizeof(int)); plist = pnums; pnums++; free(plist); /* CORRECT! plist points to the beginning of the space allocated by malloc! */ return 0; }
malloc and free CAREFUL! There should be exactly one free() for each malloc() int main () { int *pnums, *plist; pnums = (int *) malloc (10 * sizeof(int)); plist = pnums; free(plist); free(pnums); /* WRONG! The space has already been deallocated! */ return 0; }
malloc and free #include<stdlib.h> #include<stdio.h> #define SIZE 5 int main () { int *pnumbers, i; pnumbers = (int *) malloc(SIZE * sizeof(int)); if (pnumbers == NULL) { printf("Out of memory\n"); exit(1); } for (i=0; i<SIZE; i++) { *(pnumbers + i) = i*2; } free(pnumbers); return 0; } A snapshot of memory after the for-loop: pnumbers, 100: 512 512: 0 2 4 6 8