C Source Code/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.
Basic Pointers
[edit | edit source]Creating, initializing and assigning
[edit | edit source]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);
}
Pointer as function argument
[edit | edit source]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 | edit source]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 | edit source]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 | edit source]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 pointer
[edit | edit source]TODO
Void pointer
[edit | edit source]
A pointer of type void (e.g void *pointerName
) represents the address of an object, but not its type, i.e it points to a variable that can be of any type. With void*
, you can cast the type of this pointer to any other type.
#include <stdio.h>
int main () {
int a = 12;
void *pointer = &a;
printf("Value *(int *)pointer is: %d \n", *(int *)pointer); //12
printf("Value (int *)pointer is: %p \n", (int *)pointer); //0x7fff1f05ed4c
printf("Value pointer is: %p \n", pointer); //0x7fff1f05ed4c
}
Or void pointer can be defined in that way:
void *pointer;
int a = 0;
pointer = &a;
Pointer Arithmetic
[edit | edit source]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 | edit source]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 | edit source]#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 | edit source]#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
*/