VOOZH about

URL: https://en.wikiversity.org/wiki/Pointers

⇱ C Source Code/Pointers - Wikiversity


Jump to content
From Wikiversity
(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 | 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.
 */
intmain(intargc,char*argv[])
{
int*intPtr1;
int*intPtr2;

inta=5;
intb=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 */
voidbadSwap(intc,intd);
voidgoodSwap(int*c,int*d);
voiddecrement(int*p);
voidincrement(int*p);

voidbadSwap(intc,intd){
inttemp=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*/
voidgoodSwap(int*c,int*d){
inttemp=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);
}

voidbadSwap2(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 */
voiddecrement(int*p){
// What we want *p = *p - 1;
(*p)--;
// What does *p-- do?
}


/*Increments the value pointed to by p*/
voidincrement(int*p){
inttemp=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;
}

intmain(intargc,char*argv[]){
int*aPtr;
int*bPtr;

inta=5;
intb=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);
return0;
}

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

typedefunsignedcharuchar;
typedefunsignedintuint;

/*
 * Fills the data pointed to by cPtr with the alphabet.
 */
voidfillWithAlpha(uchar*cPtr,intsize);

voidprintDataAsChar(uchar*cPtr,intsize);

/* This function shows how to malloc data. It shows that data might
 * be zero upon initialization, but it is not guaranteed to be 0.
 * */
voidmallocExample();

/* This function shows malloc data can be passed to a function.
 */
voidmallocWithFunction();

intmain(intargc,char**argv){
mallocExample();
mallocWithFunction();
return0;
}

voidmallocExample(){
/* Using malloc */
uintsize,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);
}

voidmallocWithFunction(){
uintsize;
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);

}

voidfillWithAlpha(uchar*cPtr,intsize){
inti;
for(i=0;i<size;i++)
cPtr[i]='a'+i%NUM_ALPHA;
}

voidprintDataAsChar(uchar*cPtr,intsize){
inti;
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.
 */

structLinkList
{
intNumber;
structLinkList*Next;
}

insertLinkList(structLinkList**ll,intNumber)
{
structLinkList*llTemp,*llSearch,*llPrev;
intlastElementFlag=0;

llTemp=(structLinkList*)malloc(sizeof(structLinkList));

llTemp->Number=Number;
llTemp->Next=NULL;

if(*ll==NULL)
/* LinkList is empty */
*ll=llTemp;
elseif((*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);
elseif(lastElementFlag==1)
/* Insert last element */
{
llSearch->Next=llTemp;
}
else
/* Insert between */
{
llPrev->Next=llTemp;
llTemp->Next=llSearch;
}



}
}

printLinkList(structLinkList**ll)
{
structLinkList*llTemp;
llTemp=*ll;
while(llTemp!=NULL)
{
printf("Address is %d and Number is %d \n",llTemp->Next,llTemp->Number);
llTemp=llTemp->Next;
}
}


main()
{
structLinkList*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>

intmain(){
inta=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;
inta=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>

intmain(){

/* Create array */
intarr[10];

/* Fill with data */
for(inti=0;i<10;i++){
arr[i]=i*5;
}

/* Create pointer to first item */
int*ptr=&arr[0];

/* Iterate through items */
for(inti=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++;
}
return0;
}

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

voidprint(int*arr,intp){
for(inti=0;i<p;i++){
printf("%p: %d\n",arr,*arr);
arr++;
}
}
voidmultiply(int*arr,intp){
for(inti=0;i<p;i++){
*arr*=5;
arr++;
}
}
intmain(){
intarr[10];
for(inti=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));
return0;
}

/* 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 | edit source]