Chapter 11: Pointers
The chapter introduces pointers as references to other objects and shows how they let a function change objects belonging to its caller.
After this chapter you will be able to
- Pointer and pointed-to object. Distinguish a pointer from the object it points to, and describe a pointer type as a derived type with a referenced type.
- Changing a caller's objects. Explain how the proposed double_swap function can change two double objects belonging to its caller without changing the pointers it receives.
- Address and object access. Trace how a call to double_swap can pass the addresses of d0 and d1, and how the function uses those pointers to access the original objects without knowing their names.
- Unsafe pointer dereferencing. Explain what the section says happens when * is used with a null or invalid pointer, including why the two cases may appear different in practice.
- Pointer and array relationship. Explain how C treats a valid pointer as referring to the first element of an array of its reference type, potentially of unknown length, and how adding i produces a pointer to the ith element.
- Pointer traversal and endpoint. Trace how the summing examples advance a pointer through array elements and use a+len as the stopping value. Distinguish the example that advances p from the one that advances a while retaining the end in aStop.
- Pointer length and interfaces. Explain why a function receiving an array through a pointer must also receive its length, and why the book prefers array notation for such interfaces even though it specifies the same interface as pointer notation.
- Same-array pointer difference. Explain what subtracting two pointers computes and when that subtraction is defined, including why p-a gives an array element's position.
- Pointer state and null. Explain why pointer variables should be initialized to null unless they hold the address of a valid object, and how a pointer’s truth value helps check its state.
- Pointed-to object type. Explain why dereferencing a pointer requires the pointed-to object to have the designated type, and what can go wrong when a representation is interpreted as another type.
- Array pointer boundary. Distinguish a pointer value that may be computed from one that may be dereferenced at an array boundary, and explain why computing a value farther outside the array fails.
- Null values and constants. Distinguish a pointer object whose value is null from a null pointer constant. Explain that “constant” means a compile-time constant, not a const-qualified object, and describe the permitted pre-C23 forms given here.
- NULL versus nullptr. Explain why the section recommends nullptr instead of NULL: the standard does not prescribe NULL’s underlying type, and its possible expansions can obscure what an expression means.
- Structure member access through pointers. Explain how the -> operator accesses a member through a pointer to a structure, and distinguish the resulting member from the pointer itself.
- Null-safe structure pointer functions. Describe how the rational-number functions check a pointer before referring to its object, and why returning the pointer argument helps compose calls.
- Opaque structure pointer interfaces. Explain how an interface can use pointers to a structure whose definition is unavailable to its users.
- Array and pointer connections. State that C uses the same syntax to access array and pointer elements and rewrites function array parameters as pointers. Explain that these shortcuts are convenient for experienced programmers but can be difficult for novices.
- Indexed pointer access equivalence. Explain that A[i] and *(A+i) are equivalent whether A is an array or a pointer. Describe why indexing a pointer is only an alternative notation, not the creation of an array object.
- Array-to-pointer decay. Explain that when an array A occurs where a value is required, it decays to a pointer to its first element, &A[0]. Describe how this accounts for *(A+i) with an array and why additional array information is lost.
- Array parameter rewriting. Explain why an array argument reaches a function as a pointer and why an array parameter declaration is rewritten as a pointer declaration.
- Multidimensional parameter types. Describe what remains of a multidimensional array parameter after rewriting and distinguish a pointer to an array from a pointer to a pointer.
- Length-aware array interfaces. Explain why length parameters should precede array parameters and how array notation helps describe variable-length matrix parameters.
- Array argument validity. Explain who must ensure that array arguments satisfy the lengths stated in a function interface and when a compiler might help.
- Function decay and calls. Explain how a function name becomes a function pointer and how a call can use that pointer.
- Generic searching and sorting. Describe how bsearch and qsort use array information and a comparison function to work with different element types, and state the sorted-array requirement and result of bsearch.
- Comparison function contract. State the required meaning of a comparison function's return value and explain why subtracting integer elements is not a safe general implementation.
- Exact function pointer types. Explain why a function supplied as a callback must have the expected function pointer type rather than merely similar parameter types.
What it builds on
- Pointers as opaque types (chapter 6) · Earlier use of pointers as opaque types.
- Simple functions (chapter 7) · The distinction between a function's arguments and variables in its caller.
- Arrays (chapter 6) · It assumes familiarity with array elements and their order.
- Array length (chapter 6) · It contrasts pointers with the earlier sizeof technique for array length.
- Basic types (chapter 5) · Basic integer types, including the distinction between signed and unsigned types.
- Binary representations (chapter 5) · The discussion of how values are represented.
- Simple structures to access fields by name (chapter 6) · Accessing structure fields by name.
- Pure functions (chapter 10) · The earlier pure functions for rational numbers.
Section by section
Introduction
The chapter introduces pointers as references to other objects and shows how they let a function change objects belonging to its caller.
- Pointer and pointed-to object: Distinguish a pointer from the object it points to, and describe a pointer type as a derived type with a referenced type.
Why it matters: Keeping the pointer separate from its referent makes later pointer operations easier to reason about. - Changing a caller's objects: Explain how the proposed double_swap function can change two double objects belonging to its caller without changing the pointers it receives.
Why it matters: This is why a function can swap its caller's values rather than only work with values inside the function.
Key terms: pointer, referenced type, pointed-to object, double_swap, caller, pure function
11.1 Pointer operations
This section previews the pointer operations and states explained in the following subsections.
11.1.1 Address-of and object-of operators
This subsection shows how address-of and object-of operators let a function access a caller’s objects through pointers, and warns against dereferencing null or invalid pointers.
- Address and object access: Trace how a call to double_swap can pass the addresses of d0 and d1, and how the function uses those pointers to access the original objects without knowing their names.
Why it matters: This explains how a function can work on objects that are not its own variables. - Two roles of asterisk: Distinguish what * means in a pointer declaration from what it means in an expression such as *p0.
Why it matters: Recognizing the two roles prevents confusion when reading pointer parameters and expressions. - Unsafe pointer dereferencing: Explain what the section says happens when * is used with a null or invalid pointer, including why the two cases may appear different in practice.
Why it matters: It explains why a pointer’s validity matters before using it to access an object.
Key terms: address-of operator, object-of operator, address, pointer, pointer type, dereferences, declaration, expression, invalid pointer, null pointer
11.1.2 Pointer addition
This section explains how pointer addition accesses and traverses array elements, while distinguishing a pointer from an array object.
- Pointer and array relationship: Explain how C treats a valid pointer as referring to the first element of an array of its reference type, potentially of unknown length, and how adding i produces a pointer to the ith element.
Why it matters: This connection explains why adding to a pointer can select an array element. - Pointer traversal and endpoint: Trace how the summing examples advance a pointer through array elements and use a+len as the stopping value. Distinguish the example that advances p from the one that advances a while retaining the end in aStop.
Why it matters: It lets you follow pointer-based loops without losing track of where the array ends. - Pointer length and interfaces: Explain why a function receiving an array through a pointer must also receive its length, and why the book prefers array notation for such interfaces even though it specifies the same interface as pointer notation.
Why it matters: Passing the length explicitly keeps a function informed of the array's extent.
Key terms: valid pointer, reference type, pointer addition, a+len, aStop, array object, pointer, sizeof, array notation, len
11.1.3 Pointer subtraction and difference
This section explains subtracting an integer from a pointer, finding the distance between pointers in the same array, and using the appropriate types and format for those results.
- Backward pointer movement: Describe how subtracting an integer from a pointer can move backward through an array, as in the example that starts at a+(len-1).
Why it matters: It gives you a way to reason about a pointer moving through an array in reverse. - Same-array pointer difference: Explain what subtracting two pointers computes and when that subtraction is defined, including why p-a gives an array element's position.
Why it matters: Pointer difference can locate an element, but its same-array restriction is essential to using it correctly. - Pointer difference type: State the type of a pointer difference and explain why ptrdiff_t, rather than int, is used for signed differences of positions or sizes.
Why it matters: Using ptrdiff_t avoids assuming that int can represent every pointer difference. - Pointer printing recipe: State the section's recipe for printing a pointer value for debugging.
Why it matters: This is the printing convention used by the section's debugging example.
Key terms: pointer arithmetic, subtract an integer from a pointer, pointer difference, same array object, ptrdiff_t, <stddef.h>, size_t, %p, void*
11.1.4 Pointer validity
This section explains how to keep pointer values valid, why a pointed-to object’s type matters, and how array bounds limit both pointer arithmetic and dereferencing.
- Pointer state and null: Explain why pointer variables should be initialized to null unless they hold the address of a valid object, and how a pointer’s truth value helps check its state.
Why it matters: A known pointer state helps prevent accidental use of an invalid address. - Pointed-to object type: Explain why dereferencing a pointer requires the pointed-to object to have the designated type, and what can go wrong when a representation is interpreted as another type.
Why it matters: Having an address is not enough to make access through a pointer meaningful or valid. - Array pointer boundary: Distinguish a pointer value that may be computed from one that may be dereferenced at an array boundary, and explain why computing a value farther outside the array fails.
Why it matters: The distinction lets you reason about pointer-based loops without confusing a permitted boundary value with a permitted access.
Key terms: pointer variables, null, truth value, valid object, representation, non-value representation, designated type, dereferenced, array bounds, one element beyond
11.1.5 Null pointers
The section distinguishes null pointer values from null pointer constants and explains why it recommends nullptr instead of NULL.
- Null values and constants: Distinguish a pointer object whose value is null from a null pointer constant. Explain that “constant” means a compile-time constant, not a const-qualified object, and describe the permitted pre-C23 forms given here.
Why it matters: It prevents you from treating every pointer that holds a null value as a null pointer constant. - NULL versus nullptr: Explain why the section recommends nullptr instead of NULL: the standard does not prescribe NULL’s underlying type, and its possible expansions can obscure what an expression means.
Why it matters: The spelling NULL does not reliably tell you the type of the expression it produces.
Key terms: null pointer, null pointer constant, compile-time constant, const-qualified object, NULL, nullptr
11.2 Pointers and structures
This section explains how to access structures through pointers, use pointer-based functions safely, and design interfaces that expose or hide structure definitions.
- Structure member access through pointers: Explain how the -> operator accesses a member through a pointer to a structure, and distinguish the resulting member from the pointer itself.
Why it matters: It lets you read structure-pointer code without confusing the pointer with the member it accesses. - Null-safe structure pointer functions: Describe how the rational-number functions check a pointer before referring to its object, and why returning the pointer argument helps compose calls.
Why it matters: It explains why these functions can be chained without assuming every argument refers to an object. - Opaque structure pointer interfaces: Explain how an interface can use pointers to a structure whose definition is unavailable to its users.
Why it matters: It shows how a library can offer operations on a structure without exposing its contents. - Visible pointers in type aliases: Justify the advice not to hide a pointer inside a typedef, distinguishing that from giving the structure itself a typedef name.
Why it matters: Visible pointer types make an interface's pointer arguments, including possible null arguments, easier to recognize.
Key terms: pointer to structure, -> operator, member, object, pointer argument, null, validity, compose, opaque structures, interface
11.3 Pointers and arrays
The section introduces two facts that make arrays and pointers closely related in C, while noting that their convenience can confuse beginners.
- Array and pointer connections: State that C uses the same syntax to access array and pointer elements and rewrites function array parameters as pointers. Explain that these shortcuts are convenient for experienced programmers but can be difficult for novices.
Why it matters: These two connections explain why array and pointer code can look alike without requiring you to treat arrays and pointers as identical.
Key terms: pointer and array element access, array parameters, pointers
11.3.1 Array and pointer access are the same
This subsection explains why indexed access works for both arrays and pointers, and how array-to-pointer decay makes the equivalence possible for arrays.
- Indexed pointer access equivalence: Explain that A[i] and *(A+i) are equivalent whether A is an array or a pointer. Describe why indexing a pointer is only an alternative notation, not the creation of an array object.
Why it matters: It lets you read indexed pointer access without mistaking the notation for a guarantee that an array exists. - Array-to-pointer decay: Explain that when an array A occurs where a value is required, it decays to a pointer to its first element, &A[0]. Describe how this accounts for *(A+i) with an array and why additional array information is lost.
Why it matters: Array decay explains how pointer-style access applies to arrays and why the resulting pointer does not retain the array’s additional information.
Key terms: A[i], *(A+i), array access, null, array-to-pointer decay, array decay, &A[0], array values
11.3.2 Array and pointer parameters are the same
This section explains how C treats array parameters as pointers, how that rule applies to multidimensional arrays, and what programmers must do to describe and validate array sizes.
- Array parameter rewriting: Explain why an array argument reaches a function as a pointer and why an array parameter declaration is rewritten as a pointer declaration.
Why it matters: It explains why a parameter written with array notation does not receive an array by value. - Multidimensional parameter types: Describe what remains of a multidimensional array parameter after rewriting and distinguish a pointer to an array from a pointer to a pointer.
Why it matters: The distinction preserves the array shape used for ordinary matrix indexing inside a function. - Length-aware array interfaces: Explain why length parameters should precede array parameters and how array notation helps describe variable-length matrix parameters.
Why it matters: A well-ordered declaration communicates expected dimensions while keeping matrix access straightforward. - Array argument validity: Explain who must ensure that array arguments satisfy the lengths stated in a function interface and when a compiler might help.
Why it matters: A size written in an interface is useful information, not a substitute for checking that callers supply a valid array. - Array notation conventions: Describe the book's convention for choosing array or pointer notation in function parameters.
Why it matters: The notation can communicate intended use even when the parameter types are equivalent. - C23 qualified matrix parameters: State what changed in C23 for the const-qualified matrix parameters discussed here.
Why it matters: The language version affects whether the illustrated const-qualified matrix interface can be used as shown.
Key terms: decay, array parameter, pointer, innermost dimension, pointer to an array, two-dimensional arrays, length parameters, array notation, VLAs, conventional indexing
11.4 Function pointers
This section explains how function pointers work and how they enable generic library operations and dynamically chosen function calls.
- Function decay and calls: Explain how a function name becomes a function pointer and how a call can use that pointer.
Why it matters: It connects ordinary function calls with calls made through function pointers. - Generic searching and sorting: Describe how bsearch and qsort use array information and a comparison function to work with different element types, and state the sorted-array requirement and result of bsearch.
Why it matters: The comparison function supplies the ordering that lets the same library interfaces handle different data types. - Comparison function contract: State the required meaning of a comparison function's return value and explain why subtracting integer elements is not a safe general implementation.
Why it matters: An incorrect comparison result can undermine the ordering on which searching and sorting rely. - Exact function pointer types: Explain why a function supplied as a callback must have the expected function pointer type rather than merely similar parameter types.
Why it matters: Matching the callback's declared type avoids calls that cannot be guaranteed correct across C platforms. - Dynamic function selection: Describe how storing and assigning a function pointer permits a program to choose a function dynamically, and identify the cost of calling through it.
Why it matters: Dynamic selection is useful, but its call overhead may matter in time-critical code.
Key terms: function decay, function pointer, function call operator, bsearch, qsort, array base, void pointer, compare, comparison function, INT_MAX
11.5 Summary
Where this is used later
- (chapter intro) (chapter 12) · Using the address-of operator to obtain a pointer to an object.
- Arithmetic violations (chapter 15) · Adding an integer to a pointer.
- Pointers to unspecific objects (chapter 12) · Explains void pointers in more detail.
- Access violations (chapter 15) · Assumes the earlier discussion of pointer validity.
- Effective types (chapter 12) · The treatment of effective types develops the concern about accessing an object through the appropriate type.
- A detour: Variadic functions (chapter 17) · NULL is only guaranteed to be a null pointer constant.
- malloc and friends (chapter 13) · Library interfaces for obtaining and managing storage can use structure pointers.
- Type violations (chapter 15) · Function pointers
Concepts explained in this chapter
- referenceA pointer type is a C type whose values designate objects or functions in storage.
- function pointer typeA function pointer is a C pointer value that designates a function and can be used to invoke or pass that function indirectly.
- bsearchbsearch is the C standard-library function that performs a binary search on a sorted array using a comparison function.
- callA function call is an expression or statement that requests execution of a function with supplied arguments.
- comparison functionA comparison function is a caller-supplied function that determines the ordering or equality of two data elements for an algorithm such as sorting or searching.
- function decayFunction decay is the C conversion in which an expression designating a function is converted to a pointer to that function in applicable contexts.
- qsortqsort is a C standard library function that sorts the elements of an array using a caller-supplied comparison function.
- indexingArray indexing is the C operation of selecting an array element with an index expression, such as A[i].
- valid pointerA valid pointer is a pointer value whose state permits the pointer operations defined by the C language.
- array parameterAn array parameter is a function parameter declared with array notation whose array-bound information is adjusted or lost when used in a function definition or call.
- pointer arithmeticPointer arithmetic is the C operation of forming pointer values by adding or subtracting integer offsets relative to elements of an array object.
- opaque objectAn opaque structure is a C structure type whose complete member definition is hidden from code that uses its interface.
- non-value representationA non-value representation is a bit pattern that does not represent any valid value of its object type.
- arrayAn array is an aggregate object containing a fixed sequence of items of the same type, accessed by numeric indices.
- array lengthArray length is the number of elements contained in an array object.
- address-of operatorThe address-of operator is the C unary operator that obtains a pointer to an object or function designated by its operand.
- invalid pointerAn invalid pointer is a pointer value whose state does not permit reliable evaluation or use according to the C language rules.
- missing valuenullptr is the C23 null pointer constant used to represent a null pointer value.
- ptrdiff_tptrdiff_t is a signed integer type capable of representing the difference between pointers to elements of the same array.
- null pointer constantA pre-C23 null pointer constant is a compile-time constant expression of integer type and value zero or an expression of type void* that can be converted to a null pointer.
- void pointerA void pointer is a C pointer to void that can hold the address of an object of any object type, subject to valid conversions and qualification rules.
- pure functionA pure function is a function whose interactions with the rest of a program occur only through its interface and whose behavior has no other observable effects.
- format stringA format string is a character sequence containing literal text and format specifiers that controls formatted output conversion.
These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.
