/*
 * hello_pointers.c —— 一个完整的 C 程序：变量、地址、数组、指针运算、二维数组、堆内存
 * =====================================================================
 * 01 号脚本会把它编译成可执行文件并运行，展示"从源代码到可执行文件"的全过程。
 * 打印出来的地址每次运行都不一样（操作系统的地址空间随机化，ASLR），
 * 但地址之间的**差**是固定的——这才是我们关心的。
 */

#include <stdio.h>    /* printf */
#include <stdlib.h>   /* malloc, free */

int main(void) {
    /* 1. 变量住在内存里，每个变量都有一个地址；& 取地址 */
    int x = 42;
    int* px = &x;                         /* px 存的是 x 的地址 */
    printf("x = %d, sizeof(x) = %zu 字节\n", x, sizeof(x));
    printf("&x = %p（地址每次运行都不同）\n", (void*)px);
    *px = 7;                              /* 通过指针改 x */
    printf("通过 *px = 7 修改后，x = %d\n", x);

    /* 2. 数组：一段连续的内存；数组名可以当作首元素的地址 */
    float a[4] = {1.0f, 2.0f, 3.0f, 4.0f};
    printf("数组 a 的 4 个元素相对 a[0] 的字节偏移：");
    for (int i = 0; i < 4; i++) {
        printf("%ld ", (long)((char*)&a[i] - (char*)&a[0]));
    }
    printf("\n");
    float* p = a;                         /* 等价于 p = &a[0] */
    printf("*(p + 2) = %.1f，a[2] = %.1f（同一个东西）\n", *(p + 2), a[2]);

    /* 3. 二维数组按行优先存放：m[1][0] 紧挨在 m[0][2] 后面 */
    float m[2][3] = {{1, 2, 3}, {4, 5, 6}};
    float* flat = &m[0][0];
    printf("2×3 矩阵按内存顺序读出：");
    for (int k = 0; k < 6; k++) {
        printf("%.0f ", flat[k]);
    }
    printf("\n元素 (i, j) 的位置 = i * 3 + j，例如 (1, 2) → 第 %d 个 → %.0f\n", 1 * 3 + 2, flat[1 * 3 + 2]);

    /* 4. 堆内存：运行时才知道要多大时用 malloc，用完必须 free */
    int n = 5;
    double* heap = (double*)malloc(n * sizeof(double));
    if (heap == NULL) {
        printf("malloc 失败\n");
        return 1;
    }
    for (int i = 0; i < n; i++) {
        heap[i] = i * 0.5;
    }
    printf("堆上的 %d 个 double：", n);
    for (int i = 0; i < n; i++) {
        printf("%.1f ", heap[i]);
    }
    printf("（共 %zu 字节）\n", n * sizeof(double));
    free(heap);                           /* 归还内存；之后不能再用 heap 指向的内容 */
    heap = NULL;                          /* 好习惯：避免误用"悬空指针" */
    return 0;
}
