Declaring, Assigning, and Dereferencing Pointers

Pointers are basically the black magic that most of the other programming languages don’t want us to know about, or at least not be able to access directly. There’s good reason for this, actually, but let’s live dangerously.

Pointers are memory locations that store addresses. Pointers are not a data type, although they usually have the data type indicated for the purposes of dereferencing.

A data type is a memory location that can store an element taken from a set of possible values. For example, the int type can store a whole number selected from the range of whole numbers that is delimited for us in the limits.h header file.

#include <stdio.h>
#include <stdlib.h>

int main()
{
 //let's declare some basic data types
 char chValue;
 int iValue;
 double dValue;

 //now let's declare a pointer
 //we set the data type of the variable
 //the pointer is meant to point to
 //and put an * in front of the variable name
 char *chPtr;
 int *iPtr;
 double *dPtr;

 return 0;
}

To create a pointer, we simply put an asterisk, *, in front of the pointer’s variable name.

We cannot store data of a data type in a pointer. We can only store memory addresses in a pointer. To access the memory address of a variable, we use the address-of operator, &.

#include <stdio.h>
#include <stdlib.h>

int main()
{
 double dValue = 19.99;
 int iValue = 266613336;

 //to assign a memory location to a pointer
 //we use the assignment operator and the address-of 
 //operator
 double *dPtr = &dValue;
 int *iPtr = &iValue;

 printf("The address of dValue is %p\n", &dValue);
 printf("The dPtr stores the address %p\n", dPtr);

 printf("The address of iValue is %p\n", &iValue);
 printf("The address stored in iPtr is %p\n", iPtr);

 return 0;
}

The dereference operator is also an asterisk, *, which is the same character used to declare a pointer. The asterisk when placed in a declaration creates a pointer, when used with that same pointer outside the declaration, it tells the program to fetch the value stored in the memory location indicated by the pointer, rather than the memory location itself.

#include <stdio.h>
#include <stdlib.h>

int main()
{
 //declare and initialize int variable
 int iValue = 1138;
 //declare and initialize int pointer
 int *iPtr = &iValue;

 //access address using address-of operator
 printf("%d (%p)\n", iValue, &iValue);
 //access value using dereference operator
 printf("%d (%p)\n", *iPtr, iPtr);

 return 0;
}

The compiler needs to know the type of the variable the pointer points to in order to know how many bytes to read.

As we have seen, a variable is named variable location that can store a value of a certain type. Each variable consists of two parts – the value that it stores, and the memory location it stores the value at. The variable’s address in memory is called its lvalue, and the variable’s content is called its rvalue. The lvalue is what is to the left of the assignment operator, the “bucket”, and the rvalue is what is to the right of the assignment operator, “what fills the bucket”.

With functions in C that pass function arguments by value, the rvalue of the argument is copied onto the function stack. With functions in C that pass function arguments by value, the lvalue of the argument is copied onto the function stack. Passing by reference enables the function to modify the values it receives as parameters and have those changes persist beyond the lifetime of the function. Passing by reference also saves memory, since pointers are always of uniform size, which is typically either 32 or 64 bits.

#include <stdio.h>
#include <stdlib.h>


void swap(int *a, int *b) {
	printf("a points to %p and b points to %p\n", a, b);
	printf("but a is at %p and b is at %p\n", &a, &b);
	int temp = *a;
	*a = *b;
	*b = temp;
}

int main()
{
	int iA = 73;
	int iB = 1337;

	printf("iA = %d and iB = %d\n", iA, iB);
	printf("iA is at %p and b is at %p\n", &iA, &iB);

	//use address-of operator to pass in 
	//variable addresses as arguments
	swap(&iA, &iB);

	printf("Now iA = %d and iB = %d\n", iA, iB);

    return 0;
}

In fact, all functions in C pass values by value, in that a separate, distinct copy is made on the function’s stack, and exists solely for the lifetime of the function. However, when we pass by reference, we create a copy of the argument’s memory location, and not the value the argument is storing. In this way, we can modify variables that have been declared outside the called function.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s