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 |
|
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: |
|
const Modifiers |
The position of const affects meaning |
Be aware of the differences between const pointers and pointers to const data |