C Source Code/Pointers

(Redirected from 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

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);
}

Pointer as function argument

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 pointer

edit

TODO

Void pointer

edit

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

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
*/

Function Pointers

edit