void printArr(int *A, int size){
    printf("Elements of array: ");
    for(int i = 0; i < size; ++i){
        printf("%d\t", A[i]);
    }
    printf("\n");
}
int main()
{
    int C[3][2][2] = {{{1,2},{3,4}},{{5,6},{7,8}},{{9,10},{11,12}}};
    
    // 虽然地址相同,但代表的意义却不相同
    printf("%p\t%p\t%p\t%p\t%p\t%p \n", C, *C, C[0], C[0][0], &C[0][0], &C[0][0][0]);
    printf("%p\t%p\t%p\n", *C+1, C[0]+1, C[0][1]);
    printf("%p\t%p\n", C, C[0][0] + 1);
    printf("%p\t%p\n", C, &C[0][0] + 1);
    
    // 分配空间,但不会对元素进行初始化
    int *A = (int*)malloc(3 * sizeof(int));
    for(int i = 0; i < 3; ++i){
        A[i] = i+1;
    }
    printArr(A, 3);
    // 分配空间,并将元素初始化为0
    int *B = (int*)calloc(3, sizeof(int));
    printArr(B, 3);
    // 重新分配一块空间(新空间可大可小)
    // 并把原来的数据拷贝过来
    // 如果新空间首地址与原来空间地址不同,会将原来的内存空间释放
    // ,注意:此时不能再继续访问原来的地址,虽然原来的指针并未置空
    int *D = (int*)realloc(A, 10 * sizeof(int));
    printf("%p\t%p\n", A, D);
    printArr(A, 3);     // 此时不能访问 A 了,这是危险的行为
    printArr(D, 10);
    // 等同于重新分配了空间
    D = (int*)realloc(NULL, 3 * sizeof(int));   // int *D = (int*)malloc(3 * sizeof(int));
    printf("%p\t%p\n", A, D);
    printArr(D, 3);
    // 等同于释放了内存空间并将指针置为空值
    D = (int*)realloc(D, 0);                            // free(D);D = nullptr;
    printf("%p\n", D);
    return 0;
}

输出:

0x7fffa5635190	0x7fffa5635190	0x7fffa5635190	0x7fffa5635190	0x7fffa5635190	0x7fffa5635190 
0x7fffa5635198	0x7fffa5635198	0x7fffa5635198
0x7fffa5635190	0x7fffa5635194
0x7fffa5635190	0x7fffa5635198
Elements of array: 1	2	3	
Elements of array: 0	0	0	
0x5627f8b9c2c0	0x5627f8b9c300
Elements of array: 0	0	-122118128	
Elements of array: 1	2	3	0	0	0	0	0	0	0	
0x5627f8b9c2c0	0x5627f8b9c2c0
Elements of array: 0	0	0	
(nil)