Click here to Skip to main content
Click here to Skip to main content
Go to top

Hardwired's Pointers - C Approach

, 23 Feb 2005
Rate this:
Please Sign up or sign in to vote.
Introduction to pointers - If you have no idea what are they and how to use them, read this!

Introduction

The Pointer is probably a most useful and smart thing that came along with the C language. Those who don’t realize this has no idea of what coding means (I always have the definition: “to Code” = “programming in C or C++ language”). The Pointer is a very powerful tool and can be used in various ways. More about this you’ll find out in this material.

Premises

I will begin with the most common and known definition: A Pointer is a type-variable in which is stored the memory address of an object. This means that the value contained in this variable is an address. Now, don’t think of those commonly used hexadecimal values, like 0x440562 that you have seen in various open-sources.

Let’s say that the third value, 156, is the value of a variable Var. So, we have:

int    Var;

Var    = 156;

The value of Var is stored at the address 102. Now, we’ll declare a pointer:

int    *pVar;

The following step is to assign a “value” to this pointer. If we assume that we know the memory address where the value of Var is stored then we can do:

pVar    = 102;
// this is a correct assignment only in case we know the address

This is not at all recommended, because in most of the cases you don’t know the address. A code line like the one above, will give you a message of “Segmentation fault”, if you compile it and run it under Unix-like systems. What you can do is:

pVar    = &Var;

The translation of the symbol “&” is “address of”. So, this means that pVar = address of Var. Now, in the pVar variable we have the value 102. We can say now that “pVar points to Var”, which means that the address of Var is contained in the pVar variable. The next step is to access the value stored at the address pointed to by pVar. We do this by using the “*” symbol:

int    NewVar;    // another variable

NewVar    = *pVar;

Now, we have assigned the value contained at the address pointed to by pVar to the NewVar variable. So, the translation of “*” is “value at the address”. The output of:

printf( "value of NewVar = %d", NewVar );

will be:

value of NewVar = 156

Also, you can assign a value to the Var variable by using the pVar pointer. That’s because the address in which Var is stored will not change and the pVar is pointing at that address:

*pVar    = 173;

So, “the value at address” pVar is now 173 and the memory will look like this:

Types of pointers

There are different types of pointers. As I said before, a pointer is a variable that contains a memory address. But the value stored at that memory address can be of a specific type, like double, int or char. That’s why there are different types of pointers.

int    SomeVar;    // a variable of int type
int    *pSV;    // a pointer

pSV    = &SomeVar;

In the example above, we have assigned to pSV the address of SomeVar. To be able to do this (and not to get a nasty error message or warning – depending on the compiler), we have to declare: int *pSV, which means that pSV will point to a value of type int.

Never try to do something like:

float    AnotherVar;    // avariable
long    *pAV;        // a pointer

pAV    = &AnotherVar;    // !!! no way !!!

This means that in pAV you are about to store the address of a float variable. But pAV type is long, and the ANSI standard tells us that something like this is not possible.

Operations with pointers

There are two categories of operations:

  • Pointer operations.
  • Operations with the values pointed by pointers.

The last category is already known, because those are same like the ones with normal variables:

double    AVar;    // first variable
double    BVar;    // second variable

double    *pA;    // first pointer
double    *pB;    // second pointer

AVar    = 20;    // we assign a value to first variable
BVar    = 12;    // we assign a value to the second variable

pA    = &AVar;    // make pA to point to AVar address
pB    = &BVar;    // same for pB

//
// now we'll do several operations over the values of AVar and BVar:
//
(*pA)++;
(*pB)--;

(*pA)    -= (*pB);

printf( "value of AVar = %lf\n", *pA );
printf( "value of BVar = %lf\n", *pB );

The output will be:

value of AVar = 10
value of BVar = 11

Now, let’s see what operation we can do with the pointers, or better said, with the addresses stored in the pointers. But, before we start, we have to define the “address” word. To define it, we need to know the representation of memory and how the operating system works with it.

The memory can be “seen” as an array of bytes (1 byte = 8 bits). That’s for almost all of the computers, and this representation is related to physical, economical restrictions and practical reasons. The dimension of this array is equal to the amount of physical memory your computer may have. This doesn’t mean only the RAM that you install on it, but there is some extra memory to add here, like video ones and swap. So, the memory is an array of bytes and its elements can be accessed specifying an index. This index is called address. And here comes the first restriction:

You cannot assign to a pointer a negative value (look at the value as an address, not the value contained at that address). That's because the memory starts at 0 and ends at whatever your computer may have.

But this one is not the only restriction. Because the memory is being used, also by other processes (applications or OS managing operations), you cannot assign random values to the pointer, because you’ll probably crush the system (MS-DOS, Win 95, ’98, ME) or your application will get crushed (Unix-like systems and WinNT-based).

int    *pC;    // some pointer

pC    = 15;    // assign some address

(*pC)    = 200;    // !!! now, you've done it !!!

So, it’s better to let the system to manage the memory. You just work with it.

Now, we can get back to what this topic is all about: operations with pointers. There are not much: four of them: “+”, “++”, “-”, “--”. You can add two pointers, increment a pointer, subtract a pointer from another one, decrement a pointer. For a better understanding, let’s take an example:

float    A;
float    B;
float    C;

float    *pA;
float    *pB;
float    *pC;

A    = 100;    // assign some value
B    = 150;    // same thing
C    = 14;    // blah blah

pA    = &A;    // you already know what this does
pB    = &B;
pC    = &C;

pC    = pA + pB;    // add two pointers (1)
pC++;            // increment pointer(2)
pA    = pA - pB;    // subtract(3)
pB--;            // decrement(4)
  1. Here we add two pointers, pA and pB, and the result goes to pC. This means that we are adding the address contained by the pointer pA with the address contained in pB, and the result is stored in pC. This is a pretty dangerous thing to do, if you don’t know anything about the resulting address. This is just for example and you have to understand that an operation like this one is allowed, but you have to know how to use it in safe conditions.
  2. We can increment a pointer. The following explanations apply to the 4th case, too. When we’re incrementing an address, we have to be aware of the pointer’s type. In the case of a char type pointer – a char variable is stored in 1 byte. So, a char pointer will point to a char value. If we are incrementing the pointer, then it’ll point to the next char value. This means that if the address contained in the pointer is, let’s say, 100; and we’re incrementing it, the new value will be 101. This is not the same thing for a long or float type pointer. For most operating systems (Unix-like and Windows suite), variables of long and float type are stored using 4 bytes. Now, let’s say we have a float pointer = 100. If we’re incrementing it then the new value will be 104. It is very important for you to understand this, before you start using pointers in your applications. Also, when you use pointers, maybe you’d like to know what is the amount of bytes used to store a variable of a specific type. You can find out this with the sizeof() function.
  3. In this case, the rules are the same like for case 1. In addition, you’ll have to be careful no to get a negative value for the address. This means that the value of the pointer from which we are subtracting is not to be smaller than the value of the pointer subtracted.
  4. Like I have said before, the rules from case 2 apply in this case, too. Additionally, we have to check out if the pointer will be negative after decrementing it. If so, the operation is not allowed. Also, the address is an integer value and you cannot make operations like adding to or subtracting from a pointer a non-integer value, like in the following example:
    double    *pD;    // a pointer
    
    pD    = pD - 100.32; // !!!wrong!!!

    Be aware that the pointer is double. That doesn’t mean that the address is double. This means the value contained at that address is double.

Independent pointers

That’s not a correct term, but I have considered it appropriate to be used in this case. In all the above topics, I explained only the cases in which we are assigning to the pointer the address of an already defined variable. But what can we do with pointers when we do not assign any address? How can they be used?

As I said before a pointer value is an address. That address can be an existing one, like the address of an already defined variable. You, also, allocate memory to it and work with the pointer. This means that you’ll not have to assign an address to it anymore… but allocate to it an address of its own. This way you’ll work with the pointer as it is and not define any unnecessary variable:

int    *pVar;

//
// allocate momory for the pointer
// why? because this pointer does not POINT to an already existing
// data, so, we at least could kind enough to give it some memory
// to work with:)
//
pVar    = (int*)malloc( sizeof(int) );

*pVar    = 56;

By saying “allocating memory”, you have to understand that the system will make some space, somewhere in the memory, for the pointer, and will automatically assign the address of that location to the pointer. The malloc() function makes all this. If some problem occurs during this operation then the address assigned to the pointer will be NULL, which means no address. You can check this using the following method:

pVar    = (int*)malloc( sizeof(int) );

if( NULL == pVar )            // !!!this is not required, but highly recommended!!!
    return <some error>;     // if yes, return or do something about it,
                // anyway, DO NOT work with the pointer!!!

*pVar    = 56;

… and with this, you are prepared for the next topic:

Pointers to arrays

In C language, there is an enclose relation between pointer and array, these two entities being almost interchangeable. This relation is probably a most powerful and unique tool. When you use an array without index, you are in fact generating a pointer to the first element in the array, so the compiler will actually take everything till it encounters the first NULL:

char    szMessage[] = "this manual is great!";    //:)

printf( "%s\n", message );

In the example above, I have passed to printf() an array of chars. The function takes the address of the first element, this by converting it to a char pointer. That’s because in C language it is impossible to pass to a function an array. You are only passing the address of the first element of it. Even if you weren’t aware of it, you already have used pointers. Because the name of an array without an index represents the address of the first element, you can assign this address to a pointer and you’ll have access through it, to any element in the array. These kind of pointers are named arithmetic pointers.

int    Array[ 6 ] = { 1, 2, 3, 12, 54, 5 };
int    *pArray;
int    i;

// assign to the pointer the address
// of the array's first element
pArray    = Array;

//
// the following code is the classic method
// of accessing the elements of the array:
//
for( i = 0; i < 6; i++ )
    printf( "%d\n", Array[ i ] );

//
// now, use the arithmetic pointer:
//
for( i = 0; i < 6; i++ )
    printf( "%d\n", *(pArray + i) );

Pointers to structures

A commonly used C technique is to access a structure via a pointer. Declaring a pointer to a structure is done in the same way as for any other data-type described above.

struct SomeStruct
{
    int    AVar;    // a int member of the structure
    double    BVar;    // a double member
}   AStruct, *pAStruct;

AStruct is a variable of type struct SomeStruct and pAStruct is a pointer to a structure of this type. So, now we are allowed to assign to pAStruct the address of the variable AStruct.

pAStruct    = &AStruct; 

To access the members of the structure using the pointer, we will have to use the arrow operator “->”.

pAStruct->AVar    = 12;

This means that we have assigned the value “12” to the AVar member of the structure AStruct, using the pAStruct pointer. Like the use of all the other kind of pointers I have described above, this one is very important, too. Let’s say you’re passing a structure, as a parameter, to a function. What the C compiler does is this: transfers the entire structure to the function that is being called. When we have very large structures, like the ones you can see in the WinAPI, there can be a very large loss of memory and processing time. Here comes the use of pointers to structures. If you will pass that structure to the function by using a pointer to it, the compiler will then only transfer the address of the structure. In very complex applications, this kind of techniques are vital.

Conclusions

A wise man has once said that “we are jumping to conclusions when we are bored of thinking”. The C language has become one of the most powerful non-Object-Oriented languages just because of the pointers. They offer you low-level access to the memory resources and a lot of speed in complex applications. I hope this material made you understand the power of pointers. If you will use them correctly at least once, I am sure that you’ll see why I am such a big fan of them.

Points of Interest

Well... if you had no idea what a pointer is, then, hopefully, you've learned from this material.

History

  • Version 1.0 - 23 February 2005 - This material was posted three years ago on a different site. But that community does not have too much activity, so I don't like them anymore Smile | :) .

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Inocentric
Web Developer
Romania Romania
Programming C\C++ since 1995. Live to code another day!Smile | :) . Basicly I code anything in C/C++ with API, Platform SDK, Windows DDK, ODBC, OpenGL SDK, DirectX SDK, etc.
 
For the last six years(starting with 1999) I worked as freelancer.
In 2003 I have co-founded ICode&Ideas SRL, Romania, focusing on security software solutions (Project Manager and Lead Developer of Prisma Firewall).
Starting with 2005 I am the founder and president of Inocentric SRL, Romania.
Group type: Organisation (No members)



Comments and Discussions

 
Generaladdress of struct element Pinmemberkhcon26-Sep-05 23:48 
GeneralRe: address of struct element PinmemberHardwired4-Oct-05 8:37 
GeneralRe: address of struct element Pinmemberkhcon4-Oct-05 13:34 
GeneralRe: address of struct element PinmemberHardwired5-Oct-05 0:23 
GeneralRe: address of struct element Pinmemberkhcon5-Oct-05 0:52 
GeneralOnly criticismbefore voting Pinmembernorm.net23-Feb-05 21:51 
GeneralRe: Only criticismbefore voting PinmemberHardwired24-Feb-05 4:02 
GeneralBad usage of CSS ! PinmemberKochise24-Feb-05 5:48 
GeneralRe: Bad usage of CSS ! PinmemberHardwired24-Feb-05 7:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140916.1 | Last Updated 23 Feb 2005
Article Copyright 2005 by Inocentric
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid