C/C++ Array and Pointer Traps

In C/C++, arrays and pointers are fundamental and powerful tools, but they are also often sources of programming errors. Because they can be interchangeable in certain situations (such as when passing function parameters), developers can easily confuse their essence, leading to various “traps”. Here are some common traps of arrays and pointers, along with brief explanations:

1. Arrays Are Not Pointers (But Sometimes Act Like Them)

Trap 1: Array names often decay to pointers in most cases

  • Phenomenon: In most expressions, the array name is implicitly converted to a pointer to its first element (i.e., <span>&array[0]</span>).

  • Misunderstanding: Many people think that the array name is a pointer, but it is not. The array name is a constant address representing the starting position of the entire array’s storage, while a pointer is a variable that can point to different addresses.

  • Example:

int arr[3] = {1, 2, 3};int *p = arr;  // The array name decays to a pointer, equivalent to &arr[0]// arr = p;    // Error! The array name is not an lvalue and cannot be assigned

2. Differences in sizeof Behavior

Trap 2: Using sizeof on arrays and pointers yields different results

  • Array:<span>sizeof(array)</span> returns the total number of bytes occupied by the entire array.

  • Pointer:<span>sizeof(pointer)</span> returns the number of bytes occupied by the pointer variable itself (usually 4 or 8 bytes, depending on the system).

  • Example:

int arr[10];int *p = arr;printf("%zu\n", sizeof(arr));  // Could be 40 (assuming int is 4 bytes)printf("%zu\n", sizeof(p));    // Usually 4 or 8 (pointer size)

Trap: When an array is passed as a parameter to a function, using <span>sizeof</span> inside the function gives the size of the pointer, not the size of the array.

Trap 3: Function parameter declared as an array is actually a pointer

  • Phenomenon: When an array is passed as a function parameter, C/C++ actually passes a pointer, not the entire array.

  • Misunderstanding: You might think you are passing an array, but you are actually just passing a pointer to it.

  • Example:

void func(int arr[]) {  // Equivalent to int *arr    printf("%zu\n", sizeof(arr));  // Size of pointer, not array size}int main() {    int a[10];    func(a);}

Advice: If you need to know the size of the array, you should pass the size as an additional parameter to the function.

3. Array Out-of-Bounds Access

Trap 4: Arrays do not have boundary checks; out-of-bounds access is undefined behavior

  • Phenomenon: Accessing <span>arr[10]</span> when the array size is only 10 (valid indices 0~9) is out-of-bounds.

  • Consequences: This can lead to program crashes, unintended data modifications, security vulnerabilities (such as buffer overflow attacks), etc.

  • Note: C/C++ does not automatically check array boundaries; it is the developer’s responsibility.

4. Confusion Between String Arrays and Character Pointers

Trap 5: The relationship between string literals and character arrays/pointers is easily confused

  • Example Comparison:

char str1[] = "hello";  // Writable character array, size 6char *str2 = "hello";   // Points to read-only string literal (constant area), cannot modify!str1[0] = 'H';          // Legal// str2[0] = 'H';       // Illegal! May crash at runtime
  • Trap: Misunderstanding that a <span>char*</span> pointing to a string can be modified, when in fact it may point to read-only memory.

5. The Complex Relationship Between Multidimensional Arrays and Pointers

Trap 6: Errors are easy to make when passing multidimensional arrays as function parameters

  • Passing Two-Dimensional Arrays:

void func(int arr[][N]);     // Legal, the second dimension must be specifiedvoid func(int (*arr)[N]);    // Equivalent notation, pointer to an array of N ints// void func(int **arr);     // Error! Cannot be used for true two-dimensional arrays
  • Trap: You cannot directly pass a statically allocated two-dimensional array to a function expecting <span>int**</span> because the memory layout is completely different.

6. Array Initialization and Uninitialized Variables

Trap 7: Local arrays are uninitialized, and their contents are undefined

  • Example:

int arr[5];         // Local array, uninitialized, random valuesint arr2[5] = {0};  // All initialized to 0
  • Trap: Misunderstanding that local arrays will automatically initialize to 0; in fact, only global/static arrays are default initialized to 0.

7. Equivalence of Array Indexing and Pointer Arithmetic (But Also Confusing)

Trap 8:<span>arr[i]</span> is equivalent to <span>*(arr + i)</span>, but the concepts must be distinguished

  • Although syntactically equivalent, one is array access and the other is pointer arithmetic; understanding their essence helps avoid misuse.

  • Pointers can be incremented or decremented, but array names cannot (they are not lvalues).

8. Pointer Arrays vs. Array Pointers

Trap 9: Pointer arrays ≠ Array pointers

  • Pointer Array: An array that contains pointers. For example:<span>int *arr[10];</span>

  • Array Pointer: A pointer that points to an array. For example:<span>int (*arr)[10];</span>

  • Confusion Consequences: Type mismatch leading to compilation errors or logical errors.

9. Traps of const Modifiers

Trap 10: Misuse of const pointers and const arrays

  • <span>const int *p</span>: The content pointed to by the pointer is immutable, but the pointer itself can change.

  • <span>int *const p</span>: The pointer itself is immutable, but the content it points to can change.

  • <span>const int arr[]</span>: The elements of the array cannot be modified.

  • Confusing these can lead to compilation errors or unintended violations of constness.

Conclusion: How to Avoid the Traps of Arrays and Pointers?

Trap Category

Key Points

Advice

Essence of Arrays and Pointers

The array name is not a pointer, but in many cases, it decays to a pointer

Clearly distinguish the concepts of the two

sizeof Behavior

sizeof of arrays and pointers is different

Be aware of the sizeof(array) trap inside functions

Function Parameters

Passing arrays actually passes pointers

If array size is needed, pass it explicitly

Out-of-Bounds Access

Arrays do not check for out-of-bounds

Always ensure indices are within valid ranges

String Literals

String literals are usually read-only

Do not modify string literals with non-const pointers

Multidimensional Arrays

When passing multidimensional arrays, specify all dimensions except the first

Be cautious using <span>int**</span> to receive two-dimensional arrays

Initialization

Local arrays are not automatically initialized

Explicitly initialize, especially since global/static arrays default to 0

Pointer Arithmetic

Pointers and array indexing can be interchangeable but are fundamentally different

Understand the meaning of pointer arithmetic

Pointer Arrays vs. Array Pointers

It is easy to confuse their declarations and uses

Remember:<span>int *arr[10]</span><span> vs </span><span>int (*arr)[10]</span>

const Modifiers

The position of const affects meaning

Be aware of the differences between const pointers and pointers to const data

Leave a Comment