C语言数组衰减的定义、触发时机及数组指针与二维数组的异同疑问
Hey there! Let's break down your questions about array decaying in C step by step, then dig into how those two zippo variables are interpreted.
Array decaying is a core behavior in C: when you use an array's name in most expression contexts, it automatically converts to a pointer pointing to the array's first element. It's important to note this doesn't happen in every scenario—we'll cover the triggers (and exceptions) next.
For example, if you declare int arr[5];, writing int *p = arr; works because arr decays to &arr[0] (a pointer to the first int in the array).
Here are the common scenarios that trigger array decay:
- Passing an array as a function argument: If you define
void func(int arr[]), thearrparameter is actually a pointer—this is identical tovoid func(int *arr). The array name decays when passed into the function. - Using the array name on the right side of an assignment: Like the
int *p = arr;example above, the array converts to a pointer to its first element. - Performing arithmetic operations on the array name: When you write
arr + 1,arracts as a pointer, so this expression points to the second element of the array. - Using the array name as an operand for most operators (except a few exceptions): We'll list the exceptions below.
Exceptions (No Decay Occurs)
There are three key cases where an array name does not decay:
- When used as the operand of
sizeof:sizeof(arr)returns the total byte size of the entire array, not the size of a pointer. - When used with the address-of operator
&:&arrreturns a pointer to the entire array (e.g., forint arr[5], the type isint (*)[5]), not a pointer to the first element. - When the array is a string literal initializing a character array: For
char str[] = "hello";, the string literal is used to initialize the array directly, no decay happens.
char(*zippo)[2] = NULL; and char zippo2[4][2]; Let's break down each variable's type and how they're interpreted, then highlight similarities and differences.
First: char(*zippo)[2] = NULL;
This is a pointer to a 2-element char array. When you later use malloc to allocate sizeof(char[2]) * 4 bytes and cast it to this type, zippo now points to a block of memory that can hold 4 separate 2-element char arrays—essentially mimicking the start of a 2D array.
Second: char zippo2[4][2];
This is a 2D array: it's an array of 4 elements, where each element is itself a 2-element char array. The memory for zippo2 is contiguous (8 total char bytes, assuming char is 1 byte).
How Are They Interpreted?
Similarities:
- When accessing elements with
zippo[i][j]andzippo2[i][j], the syntax looks identical, and the underlying address calculation works the same way: both first calculate the start of the i-th subarray, then offset j chars to get the target element. - If you pass
zippo2to a function, it decays to achar(*)[2]pointer—matching the type ofzippo.
Key Differences:
- Mutability:
zippois a pointer variable, so you can reassign it (e.g.,zippo = &zippo2[1];works).zippo2is an array name, which is a constant expression—you can't assign to it (e.g.,zippo2 = NULL;will throw a compile error). sizeofbehavior:sizeof(zippo)returns the size of a pointer (4 bytes on 32-bit systems, 8 on 64-bit).sizeof(zippo2)returns the total size of the 2D array (42sizeof(char) = 8 bytes).- Memory origin:
zippo2is allocated on the stack (assuming it's a local variable), whilezippopoints to heap-allocated memory after yourmalloccall.
Here's a quick code example to illustrate these points:
#include <stdio.h> #include <stdlib.h> int main() { char(*zippo)[2] = NULL; char zippo2[4][2] = {{'a','b'}, {'c','d'}, {'e','f'}, {'g','h'}}; // Allocate heap memory for zippo zippo = (char(*)[2])malloc(sizeof(char[2]) * 4); if (!zippo) { perror("malloc failed"); return 1; } // Populate zippo's memory for (int i = 0; i < 4; i++) { zippo[i][0] = 'A' + i; zippo[i][1] = 'a' + i; } // Element access works the same syntax printf("zippo[1][0]: %c\n", zippo[1][0]); // Outputs 'B' printf("zippo2[1][0]: %c\n", zippo2[1][0]); // Outputs 'c' // Size differences printf("sizeof(zippo): %zu\n", sizeof(zippo)); // Pointer size (e.g., 8) printf("sizeof(zippo2): %zu\n", sizeof(zippo2)); // 8 (4*2*1) // Reassign zippo (valid) zippo = zippo2; printf("After reassignment, zippo[1][0]: %c\n", zippo[1][0]); // Now outputs 'c' // zippo2 = zippo; // COMPILE ERROR: can't assign to array name free(zippo); // Wait, no—after reassignment, zippo points to stack memory! Don't free that. // Correct approach: free the original malloc'd pointer before reassignment return 0; }
内容的提问来源于stack exchange,提问作者이승훈

