Pointers
This page contains examples of pointers. These examples assume the reader has the following knowledge: compiling C programs, variable creation and assignment, arrays, functions, basic I/O and an understanding of computer memory layout. These examples build from simple to more complex.
Contents |
Basic Pointers [edit]
Creating, initializing and assigning [edit]
This example shows simple pointer creation, assignment and dereference.
#include <stdio.h> /*Example showing simple pointer assignment operations. */ int main(int argc, char *argv[]) { int *intPtr1; int *intPtr2; int a = 5; int b = 10; printf("\nBefore Initializing pointers."); printf("\nintPtr1: %d, *intPtr1: %d", intPtr1, *intPtr1); printf("\nintPtr2: %d, *intPtr2: %d\n", intPtr2, *intPtr2); /*Initialize the pointers*/ intPtr1 = NULL; intPtr2 = NULL; printf("\nAfter Initializing pointers to NULL"); printf("\nintPtr1: %d", intPtr1); printf("\nintPtr2: %d\n", intPtr2); intPtr1 = &a; intPtr2 = &b; printf("\nAfter pointing intPtr1 to the address of 'a' and " "\npointing intPtr2 to the address of 'b'\n"); printf("\nintPtr1: %d, *intPtr1: %d", intPtr1, *intPtr1); printf("\nintPtr2: %d, *intPtr2: %d", intPtr2, *intPtr2); printf("\na: %d, b: %d\n", a, b); *intPtr1 = 7; *intPtr2 = 12; printf("\nAfter assigning 7 into the memory location pointed to by " "intPtr1 \n and assigning 12 into the memory location pointed to by intPtr2"); printf("\nintPtr1: %d, *intPtr1: %d", intPtr1, *intPtr1); printf("\nintPtr2: %d, *intPtr2: %d", intPtr2, *intPtr2); printf("\na: %d, b: %d\n", a, b); intPtr1 = intPtr2; printf("\nAfter storing the memory location of intPtr2 into intPtr1. \nMakes intPtr2 now point to variable 'b' as well"); printf("\nintPtr1: %d, *intPtr1: %d", intPtr1, *intPtr1); printf("\nintPtr2: %d, *intPtr2: %d", intPtr2, *intPtr2); printf("\na: %d, b: %d\n", a, b); *intPtr2 = 10; printf("\nAfter assigning '10' into the memory location pointed to by intPtr1 and intPtr2"); printf("\nintPtr1: %d, *intPtr1: %d", intPtr1, *intPtr1); printf("\nintPtr2: %d, *intPtr2: %d", intPtr2, *intPtr2); printf("\na: %d, b: %d\n", a, b); b = 25; printf("\nAfter assigning '25' into the variable 'b'"); printf("\nintPtr1: %d, *intPtr1: %d", intPtr1, *intPtr1); printf("\nintPtr2: %d, *intPtr2: %d", intPtr2, *intPtr2); printf("\na: %d, b: %d\n", a, b); }
Basic Pointers with Functions [edit]
This example shows how pointers can be used in functions. The code gives the reader some questions to consider and answer on their own.
#include <stdio.h> /*Example showing how pointers are used in functions. */ /* Only swaps the values within this fuction */ void badSwap(int c, int d); void goodSwap(int *c, int *d); void decrement(int *p); void increment(int *p); void badSwap(int c, int d) { int temp = 0; printf("\nbadSwap"); printf("\n\tBefore swapping in badSwap"); printf("\n\ttemp: %d, c: %d, d: %d", temp, c, d); temp = c; c = d; d = temp; // Why won't this work? printf("\n\tAfter swapping in badSwap"); printf("\n\ttemp: %d, c: %d, d: %d", temp, c, d); } /* Swaps the values using pointers*/ void goodSwap(int *c, int *d) { int temp = 0; printf("\ngoodSwap"); printf("\n\tBefore swapping in goodSwap"); printf("\n\ttemp: %d, c: %u, *c: %d, d: %u, *d: %d", temp, c, *c, d, *d); temp = *c; *c = *d; *d = temp; // Why does this work? printf("\n\tAfter swapping in goodSwap"); printf("\n\ttemp: %u, c: %u, *c: %d, d: %u, *d: %d", temp, c, *c, d, *d); } void badSwap2(int *c, int *d) { int *temp = NULL; printf("\nbadSwap2"); printf("\n\tBefore swapping in badSwap2"); printf("\n\ttemp: %d, c: %u, *c: %d, d: %u, *d: %d", temp, c, *c, d, *d); temp = c; c = d; d = temp; // c and d have changed values! Great! Why won't their values be changed when // we return? printf("\n\tAfter swapping in badSwap2"); printf("\n\ttemp: %u, c: %u, *c: %d, d: %u, *d: %d", temp, c, *c, d, *d); } /*Decrements the value pointed to by p */ void decrement(int *p) { // What we want *p = *p - 1; (*p)--; // What does *p-- do? } /*Increments the value pointed to by p*/ void increment(int *p) { int temp = p; // What we want *p = *p + 1 (*p)++; // What does *p++ do? printf("\nincrement"); printf("\n\t p: %u, *p: %u, &p: %u\n", p, *p, &p); p = p + 1; printf("\n\t p: %u, *p: %u, &p: %u\n", p, *p, &p); p = temp; p = *p + 1; printf("\n\t p: %u, &p: %u\n", p, &p); p = temp; p = &p + 1; printf("\n\t p: %u, *p: %u, &p: %u\n", p, *p, &p); p = temp; *p = p + 1; printf("\n\t p: %u, *p: %u, &p: %u\n", p, *p, &p); p = temp; *p = &p + 1; printf("\n\t p: %u, *p: %u, &p: %u\n", p, *p, &p); p = temp; } int main(int argc, char *argv[]) { int *aPtr; int *bPtr; int a = 5; int b = 10; /*Initialize the pointers*/ aPtr = &a; bPtr = &b; /*Before call to badSwap*/ printf("\nBefore call to badSwap"); printf("\n\taPtr: %u, *aPtr: %d", aPtr, *aPtr); printf("\n\tbPtr: %u, *bPtr: %d", bPtr, *bPtr); printf("\n\ta: %d, b: %d\n", a, b); badSwap(a, b); /* After call to badSwap */ printf("\n\nAfter call to badSwap"); printf("\n\taPtr: %u, *aPtr: %d", aPtr, *aPtr); printf("\n\tbPtr: %u, *bPtr: %d", bPtr, *bPtr); printf("\n\ta: %d, b: %d\n", a, b); /*Before call to goodSwap*/ printf("\nBefore call to goodSwap"); printf("\n\taPtr: %u, *aPtr: %d", aPtr, *aPtr); printf("\n\tbPtr: %u, *bPtr: %d", bPtr, *bPtr); printf("\n\ta: %d, b: %d\n", a, b); goodSwap(aPtr, bPtr); goodSwap(&a, &b); /* After call to goodSwap */ printf("\n\nAfter call to goodSwap"); printf("\n\taPtr: %u, *aPtr: %d", aPtr, *aPtr); printf("\n\tbPtr: %u, *bPtr: %d", bPtr, *bPtr); printf("\n\ta: %d, b: %d\n", a, b); badSwap2(aPtr, bPtr); /* After call to badSwap2*/ printf("\n\nAfter call to badSwap2"); printf("\n\taPtr: %u, *aPtr: %d", aPtr, *aPtr); printf("\n\tbPtr: %u, *bPtr: %d", bPtr, *bPtr); printf("\n\ta: %d, b: %d\n", a, b); increment(&a); return 0; }
Advanced Pointers [edit]
This section describes how to use pointers to access dynamically allocated memory, point to structures, point to other pointers, point to functions, and point to void.
Pointers with Malloc [edit]
This example show how pointers can be used with malloc to point to blocks of memory.
#include <stdlib.h> #include <stdio.h> #define NUM_ALPHA 26 typedef unsigned char uchar; typedef unsigned int uint; /* * Fills the data pointed to by cPtr with the alphabet. */ void fillWithAlpha(uchar *cPtr, int size); void printDataAsChar(uchar *cPtr, int size); /* This function shows how to malloc data. It shows that data might * be zero upon initialization, but it is not guaranteed to be 0. * */ void mallocExample(); /* This function shows malloc data can be passed to a function. */ void mallocWithFunction(); int main(int argc, char **argv) { mallocExample(); mallocWithFunction(); return 0; } void mallocExample() { /* Using malloc */ uint size, i; printf("\n Enter the desired size: "); scanf("%d", &size); uchar *data; /* Check to make sure a NULL pointer wasn't returned from malloc */ if ((data = (uchar*) malloc(size)) == NULL) exit(1); /* Raw data after first malloc. Not guaranteed to be initialized*/ printf("\n After first malloc"); for (i = 0; i < size; i++) printf("\n [%d]: %d", i, data[i]); /* Fill */ for (i = 0; i < size; i++) data[i] = i; /* After fill */ printf("\n After fill"); for (i = 0; i < size; i++) printf("\n [%d]: %d", i, data[i]); /* When data is no longer needed it MUST be freed */ free(data); if ((data = (uchar*) malloc(size)) == NULL) exit(1); /* Raw data after second malloc. Shows how there can be stuff 'left over' * in memory after malloc call*/ printf("\n Raw data after malloc"); for (i = 0; i < size; i++) printf("\n [%d]: %d", i, data[i]); free(data); } void mallocWithFunction() { uint size; printf("\n Enter the desired size: "); scanf("%d", &size); uchar *data; if ((data = (uchar*) malloc(size)) == NULL) exit(1); printDataAsChar(data, size); fillWithAlpha(data, size); printDataAsChar(data, size); } void fillWithAlpha(uchar *cPtr, int size) { int i; for (i = 0; i < size; i++) cPtr[i] = 'a' + i%NUM_ALPHA; } void printDataAsChar(uchar *cPtr, int size) { int i; for (i = 0; i < size; i++) printf("[%d]: %c \n", i, cPtr[i]); }
Pointers to Structs [edit]
Below is example showing how pointers are used with structures. It creates a classic link list which stores numbers in sorted form.
#include <stdio.h> #include <stdlib.h> /* Example showing how pointers are used with structures. */ struct LinkList { int Number; struct LinkList *Next; } insertLinkList(struct LinkList **ll,int Number) { struct LinkList *llTemp,*llSearch,*llPrev; int lastElementFlag=0; llTemp=(struct LinkList *)malloc(sizeof(struct LinkList)); llTemp->Number=Number; llTemp->Next=NULL; if (*ll==NULL) /* LinkList is empty */ *ll=llTemp; else if ((*ll)->Number>Number) {/*insert first element */ llTemp->Next=*ll; *ll=llTemp; } else { llSearch=*ll; while (llSearch->Number<Number) { if (llSearch->Next==NULL) { lastElementFlag=1; break; } llPrev=llSearch; llSearch=llSearch->Next; } if(llSearch->Number==Number) printf("Number %d already exists\n",Number); else if(lastElementFlag==1) /* Insert last element */ { llSearch->Next=llTemp; } else /* Insert between */ { llPrev->Next=llTemp; llTemp->Next=llSearch; } } } printLinkList(struct LinkList **ll) { struct LinkList *llTemp; llTemp=*ll; while (llTemp!=NULL) { printf("Address is %d and Number is %d \n",llTemp->Next,llTemp->Number); llTemp=llTemp->Next; } } main() { struct LinkList *llist=NULL,*llist2=NULL; printf("Inserting 4\n"); insertLinkList(&llist,4); printf("Inserting 1\n"); insertLinkList(&llist,1); printf("Inserting 5\n"); insertLinkList(&llist,5); printf("Inserting 9\n"); insertLinkList(&llist,9); printf("Inserting 2\n"); insertLinkList(&llist,2); printf("Inserting 9\n"); insertLinkList(&llist,9); printf("Inserting 1\n"); insertLinkList(&llist,1); printf("Inserting 5\n"); insertLinkList(&llist,5); printf("Inserting 4\n"); insertLinkList(&llist2,14); printf("Inserting 1\n"); insertLinkList(&llist2,17); printf("Printing llist \n"); printLinkList(&llist); printf("Printing llist2 \n"); printLinkList(&llist2); }
Double Pointers [edit]
TODO
Triple Pointers [edit]
TODO
Quadruple Pointers [edit]
TODO
Function Pointers [edit]
TODO
Void Pointers [edit]
TODO
Pointer Arithmetic [edit]
TODO Pointers and Arrays; Pointer Arithmetic [This section corresponds to K&R Sec. 5.3]
Pointers do not have to point to single variables. They can also point at the cells of an array. For example, we can write
int *ip; int a[10]; ip = &a[3];
and we would end up with ip pointing at the fourth cell of the array a (remember, arrays are 0-based, so a[0] is the first cell). We could illustrate the situation like this:
We'd use this ip just like the one in the previous section: *ip gives us what ip points to, which in this case will be the value in a[3].
Once we have a pointer pointing into an array, we can start doing pointer arithmetic. Given that ip is a pointer to a[3], we can add 1 to ip:
ip + 1
What does it mean to add one to a pointer? In C, it gives a pointer to the cell one farther on, which in this case is a[4]. To make this clear, let's assign this new pointer to another pointer variable: ip2 = ip + 1;
Now the picture looks like this:
If we now do *ip2 = 4;
we've set a[4] to 4. But it's not necessary to assign a new pointer value to a pointer variable in order to use it; we could also compute a new pointer value and use it immediately: *(ip + 1) = 5;
In this last example, we've changed a[4] again, setting it to 5. The parentheses are needed because the unary ``contents of operator * has higher precedence (i.e., binds more tightly than) the addition operator. If we wrote *ip + 1, without the parentheses, we'd be fetching the value pointed to by ip, and adding 1 to that value. The expression *(ip + 1), on the other hand, accesses the value one past the one pointed to by ip.
Given that we can add 1 to a pointer, it's not surprising that we can add and subtract other numbers as well. If ip still points to a[3], then
*(ip + 3) = 7;
sets a[6] to 7, and *(ip - 2) = 4;
sets a[1] to 4.
Up above, we added 1 to ip and assigned the new pointer to ip2, but there's no reason we can't add one to a pointer, and change the same pointer:
ip = ip + 1;
Now ip points one past where it used to (to a[4], if we hadn't changed it in the meantime). The shortcuts we learned in a previous chapter all work for pointers, too: we could also increment a pointer using ip += 1;
or ip++;
Of course, pointers are not limited to ints. It's quite common to use pointers to other types, especially char. Here is the innards of the mystrcmp function we saw in a previous chapter, rewritten to use pointers. (mystrcmp, you may recall, compares two strings, character by character.)
char *p1 = &str1[0], *p2 = &str2[0];
while(1) { if(*p1 != *p2) return *p1 - *p2; if(*p1 == '\0' || *p2 == '\0') return 0; p1++; p2++; }
The autoincrement operator ++ (like its companion, --) makes it easy to do two things at once. We've seen idioms like a[i++] which accesses a[i] and simultaneously increments i, leaving it referencing the next cell of the array a. We can do the same thing with pointers: an expression like *ip++ lets us access what ip points to, while simultaneously incrementing ip so that it points to the next element. The preincrement form works, too: *++ip increments ip, then accesses what it points to. Similarly, we can use notations like *ip-- and *--ip.
As another example, here is the strcpy (string copy) loop from a previous chapter, rewritten to use pointers:
char *dp = &dest[0], *sp = &src[0]; while(*sp != '\0') *dp++ = *sp++; *dp = '\0';
(One question that comes up is whether the expression *p++ increments p or what it points to. The answer is that it increments p. To increment what p points to, you can use (*p)++.)
Advanced Pointers with Arrays [edit]
Shows how arrays and pointers can be treated the same. Example: Creating an array structure with pointers. Example: Using pointer arithmetic to index array
Using Pointers to Traverse an Array [edit]
#include <stdio.h> int main() { /* Create array */ int arr[10]; /* Fill with data */ for (int i = 0; i < 10; i++) { arr[i] = i*5; } /* Create pointer to first item */ int *ptr = &arr[0]; /* Iterate through items */ for (int i = 0; i < sizeof(arr)/sizeof(int); i++) { /* Print the address and the value */ printf("%p: %d\n", ptr, *ptr); /* Increment pointer by sizeof(int) */ ptr++; } return 0; } /* OUTPUT 0x7fff69a4fa20: 0 0x7fff69a4fa24: 5 0x7fff69a4fa28: 10 0x7fff69a4fa2c: 15 0x7fff69a4fa30: 20 0x7fff69a4fa34: 25 0x7fff69a4fa38: 30 0x7fff69a4fa3c: 35 0x7fff69a4fa40: 40 0x7fff69a4fa44: 45 */
Passing arrays to functions using pointers [edit]
#include <stdio.h> void print(int *arr, int p) { for (int i = 0; i < p; i++) { printf("%p: %d\n", arr, *arr); arr++; } } void multiply(int *arr, int p) { for (int i = 0; i < p; i++) { *arr *= 5; arr++; } } int main() { int arr[10]; for (int i = 0; i < 10; i++) { arr[i] = i; } printf("Before modification: \n"); print(&arr[0], sizeof(arr)/sizeof(int)); multiply(&arr[0], sizeof(arr)/sizeof(int)); printf("\nAfter modification: \n"); print(&arr[0], sizeof(arr)/sizeof(int)); return 0; } /* OUTPUT Before modification: 0x7fff63f0aa40: 0 0x7fff63f0aa44: 1 0x7fff63f0aa48: 2 0x7fff63f0aa4c: 3 0x7fff63f0aa50: 4 0x7fff63f0aa54: 5 0x7fff63f0aa58: 6 0x7fff63f0aa5c: 7 0x7fff63f0aa60: 8 0x7fff63f0aa64: 9 After modification: 0x7fff63f0aa40: 0 0x7fff63f0aa44: 5 0x7fff63f0aa48: 10 0x7fff63f0aa4c: 15 0x7fff63f0aa50: 20 0x7fff63f0aa54: 25 0x7fff63f0aa58: 30 0x7fff63f0aa5c: 35 0x7fff63f0aa60: 40 */