Pointers and Arrays --- the C programming language

In ANSI C, generic pointer is void *;

The unary operator & gives the address of an object, so the statement p = &c; assigns the address of c to the variable p, and p is said to “point to” c. The & operator only applies to objects in memory: variables and arrays element. It cannot be applied to expressions, constants, or register variables.

The unary operator * is the indirection or dereferencing operator; when applied to a pointer, it accesses the object the pointer points to.

int x = 1, y = 2, z[10];

int *ip; /* ip is a pointer to int */

ip = &x; /*ip now points to x */

y = *ip; /*y is now 1 */

*ip = 0; /* x is now 0*/

ip = &z[0]; /* ip now points to z[0] */

You should also not the implication that a pointer is constrained to point to a particular kind of object: every pointer points to a specific data type. (There is one exception: a “pointer to void” is used to hold any type of pointer but cannot be dereferenced iteself.)

If ip points to the integer x, then *ip can occur in any context where x could, so

*ip = *ip + 10;

increments *ip by 10.

The unary operators * and & bind more tightly than arithmetic operators, so the assignment

y = *ip + 1

takes whatever ip points at, adds 1, and assigns the result to y , while

*ip += 1

incrments what ip points to, as do

++*ip

and (*ip)++

The parentheses are necessary in this last example; without them, the expression would increment ip instead of what it points to , beacuse unary operators like * and ++ associate right to left.

Finally, since pointers are variables, they can be used without dereferencing. For example, if iq is another pointer to int, iq = ip

copies the contents of ip into iq, thus making iq point to whatever ip point to whatever ip pointed to.

Pointers and Arrays

Any operation that can be achieved by array subscripting can also be done with pointers. The pointer version will in general be faster but, at least to the uninitiated, somewhat harder to understand.

If pa points to a particular element of an arrya, then by definition pa+1 points to the next element, pa+i points i elements after pa, and pa-i points i elements before. Thus, if pa points to a[0],

*(pa + 1)

refers to the contents of a[1], pa+i is the address of a[i], and *(pa+i) is the contents of a[i].

The correspondence between indexing and pointer arithmetic is very close. By definition, the value of a variable or expression of type array is the address of element zero of the array. Thus after the assignment pa = &a[0]; pa and a have identical values. Since the name of an array is a synonym for the location of the initial element, the assignment pa = &a[0] can also be written as pa = a;

In short, an array-and-index expression is equivalent to one written as a pointer and offset.

There is one difference between an array name and a pointer that must be kept in mind. A pointer is a variable, so pa=a and pa++ are legal. But array name is not a variable;constructions like a=pa and a++ are illegal.

When an array name is passed to a function, what is passed is the location of the initial element. Within the called function, this argument is a local variable, and so an array name parameter is a pointer, that is, a variable containing an address.

Address Arithmetic

Pointer arithmetic is consistent: if we had been dealing with floats, which occupy more storage than chars, and if p were a pointer to float, p++ would advance to the next float. Thus we could write another version of alloc that maintains floats instead of chars, merely by changing char to float throughout alloc and afree. All the pointer manipulations automatically take into account the size of the object pointed to.

The valid pointer operations are assignment of pointers of the same type, adding or subtracting a pointer and an integer, subtracting or comparing two pointers to members of the same array, and assigning or comparing to zero. All other pointer arithmetic is illegal. It is not legal to add two pointers, or to multiply or divide or shift or mask them, or to add float or double to them, or even, except for void *, to assign a pointer of one type to a pointer of another type without a cast.

Pointer Arrays

initialization of pointer arrays:

The syntax is similar to previous initializations:

/* month_name: return name of n-th month */

char *month_name(int n)

{

static char *name[] = {

    "Illegal month",

    "January", "February", "March",

    "April", "May", "June",

    "July", "August", "September",

    "October", "November", "December"

};

return (n < 1 || n > 12) ? name[0] : name[n];

}

Pointers vs. Multi-dimensional Arrays

Newcomers to C are sometimes confused about the difference between a two-dimensional array and an array of pointers, such as name in the example above. Given the definitions

int a[10][20];

int *b[10];

then a[3][4] and b[3][4] are both syntactically legal references to a single int. But a is a true two-dimensional array: 200 int-sized locations have been set aside, and the conventional rectangular subscript calculation 20xrow+col is used to find the element a[row][col]. For b, however, the definition only allocates 10 pointers and does not initialize them; initialization must be done explicitly, either statically or with code. Assuming that each element of b does point to a twenty-element array, then there will be 200 ints set aside, plus ten cells for the pointers. The important advantage of the pointer array is that the rows of the array may be of different lengths. That is, each element of b need not point ot a twenty-element vector; some may point to two elements, some to fifty, and some to none at all.