syque.com

The Psychology of Quality and More

| Menu | Books | Share | Search | Settings |

C Style: Standards and Guidelines (contents)

CHAPTER 9 : Data Usage

PART 4 : USAGE

CHAPTER 9 : Data Usage
9.1 Declarations
9.2 Using floating point numbers
9.3 Using 'typedef'
9.4 Using global data
9.5 Using Structures
9.6 Using Unions
9.7 Using Arrays
9.8 Using Pointers
9.9 Using bit structures
9.10 Using Constants
9.11 Using 'static' declarations
9.12 Initializing variables
9.13 Summary

<--Prev page | Next page -->

 

9.8  Using Pointers

Pointers are one of the most useful and dangerous features of C. A pointer mishandled can corrupt data (or even code!) which may lie undiscovered for some time before causing unspecified and possibly unthinkable damage. This kind of problem is also very difficult to debug.

You cannot prohibit the use of pointers; they are too useful. You can, however, urge caution in their use.

9.8.1  Pointers and Arrays

Pointers and arrays in C are closely related and are sometimes used interchangeably. Their logical meaning, however, is different.

A pointer is dimensionless: it simply points to something. It has no 'home', and can be left pointing anywhere, even to nothing. Its additional flexibility means that it is often used in preference to arrays.

An array, on the other hand, has at least one dimension. It is finite, its bounds being included in its definition. It usually contains significant values.

Initialization

When initializing a pointer to point to the beginning of an array, it is using the explicitness principle is to show just this. Thus:

 

p = &a[0];      ..rather than..     p = a;

 

Beware of modifying string constants: an array initialized with a string is modifiable, but a string initializer for a pointer is a constant, and should not be changed (ANSI C allows the compiler to put it in read-only memory!). Thus:

 

char EmpName[] = "Jones, William";     /* this may be modified      */
char *EmpName  = "Jones, William";     /* this may not be modified! */

-----------------------------------------------------------------------

9.8.2  Pointers, integers, and NULL

In some implementations, pointers and integers are interchangeable. It is not, however, a very stylish or portable practice to interchange them.

The null pointer is a zero constant in the code, which the compiler translates into a (possibly non-zero) internal value. Any pointer may be compared with or be set equal to the null pointer:

 

pParaInfo = 0;
...
if ( pParaInfo == 0 )

 

Casting the pointer emphasizes the type to the reader (see 8.2.7). It may also be necessary in an actual parameter. It is common to more explicitly use the #define'd value NULL. Thus:

 

pParaInfo = (PARA_INFO *)NULL;

 

The null pointer is a flag for saying, "This is not a valid pointer," and is useful for such as marking the end of a chain or as a function error return. Although NULL is not a part of the language, it is very commonly #define'd in stddef.h (ANSI) or stdio.h. It is more explicit to use NULL than zero. Of course, nothing should ever be put where a null pointer points to.

Beware of confusing NULL with NUL, which is the character '\0'. It may even be better to #define NUL as NUL_CHAR, in order to prevent accidents (see 5.5).

9.8.3  The 'void' pointer

In the same manner that NULL is used as a parking place for a given pointer, void * (ANSI C) or char * (pre-ANSI, and more portable) can be used to indicate a pointer where the type of object that it points to is not known. It is valuable as it is guaranteed to be able to point to anything. The void pointer should never treated as pointing at anything other than 'memory'. To reference what it points to, use another pointer or a cast:

 

void    *pFreeMem;
...
pFreeMem = (void *)pFirstFreeBlock;
...
pNumbers = (int *)pFreeMem;

 

9.8.4  Changing pointer type

To enable more efficient hardware addressing, some items must be allocated on particular memory boundaries, for example an int in a 16 address-bit system must start on an even byte boundary. This means that pointers cannot be exchanged freely: a type may be safely allocated a shorter type, but not the other way around:

 

char    *pChar;
long    *pLong;
pChar = (char *)pLong;   /* always works     */
pLong = (long *)pChar;   /* not always valid */

 

The simplest approach is to always cast, unless allocating the same type.

 

<--Prev page | Next page -->

 

Site Menu

| Home | Top | Settings |

Quality: | Quality Toolbook | Tools of the Trade | Improvement Encyclopedia | Quality Articles | Being Creative | Being Persuasive |

And: | C Style (Book) | Stories | Articles | Bookstore | My Photos | About | Contact |

Settings: | Computer layout | Mobile layout | Small font | Medium font | Large font | Translate |

 

You can buy books here

More Kindle books:

And the big
paperback book


Look inside

 

Please help and share:

 

| Home | Top | Menu |

© Changing Works 2002-
Massive Content -- Maximum Speed