下面将详细介绍指针的核心内容，包括指针声明、指针运算、指针与数组的关系以及二级指针，并结合代码示例和内存图进行说明。

### 1. 指针声明：`int *p` 的正确写法

在 C 和 C++ 中，指针声明的语法是 `数据类型 *指针变量名`。`int *p` 是一个常见的声明方式，它声明了一个名为 `p` 的指针变量，该指针指向 `int` 类型的数据。以下是几种常见的写法及其含义：

```c
#include <stdio.h>

int main() {
    int num = 10;
    // 写法一：常见写法
    int *p1;
    p1 = &num;
    // 写法二：声明并初始化
    int *p2 = &num;

    printf("p1 指向的值: %d\n", *p1);
    printf("p2 指向的值: %d\n", *p2);

    return 0;
}
```

### 2. 指针运算：`p++` 在不同类型下的地址变化

指针运算主要包括指针的加减操作。当对指针进行 `p++` 操作时，指针会根据其所指向的数据类型的大小向前移动相应的字节数。以下是不同类型指针 `p++` 后的地址变化示例：

```c
#include <stdio.h>

int main() {
    int arr_int[3] = {1, 2, 3};
    char arr_char[3] = {'a', 'b', 'c'};

    int *p_int = arr_int;
    char *p_char = arr_char;

    printf("p_int 初始地址: %p\n", (void *)p_int);
    p_int++;
    printf("p_int 自增后地址: %p\n", (void *)p_int);

    printf("p_char 初始地址: %p\n", (void *)p_char);
    p_char++;
    printf("p_char 自增后地址: %p\n", (void *)p_char);

    return 0;
}
```

在上述代码中，`int` 类型通常占 4 个字节，`char` 类型占 1 个字节。所以 `p_int++` 会使指针地址增加 4 个字节，而 `p_char++` 会使指针地址增加 1 个字节。

### 3. 指针与数组：`arr[i]` 与 `*(arr + i)` 的等价性

在 C 和 C++ 中，数组名本质上是一个指向数组首元素的常量指针。`arr[i]` 和 `*(arr + i)` 是完全等价的，它们都表示访问数组中第 `i` 个元素。以下是示例代码：

```c
#include <stdio.h>

int main() {
    int arr[5] = {1, 2, 3, 4, 5};

    // 使用 arr[i] 访问元素
    for (int i = 0; i < 5; i++) {
        printf("arr[%d] = %d\n", i, arr[i]);
    }

    // 使用 *(arr + i) 访问元素
    for (int i = 0; i < 5; i++) {
        printf("*(arr + %d) = %d\n", i, *(arr + i));
    }

    return 0;
}
```

### 4. 二级指针：画内存图理解指针的指针

二级指针是指向指针的指针。通过二级指针，可以间接访问和修改另一个指针的值。以下是一个二级指针的示例代码，并给出对应的内存图解释。

```c
#include <stdio.h>

int main() {
    int num = 10;
    int *p = &num;
    int **pp = &p;

    printf("num 的值: %d\n", num);
    printf("p 指向的值: %d\n", *p);
    printf("pp 间接指向的值: %d\n", **pp);

    return 0;
}
```

#### 内存图解释

```plaintext
+----------------+
| 内存地址        | 变量名 | 存储内容
+----------------+--------+-----------------
| 0x1000          | num    | 10
| 0x2000          | p      | 0x1000 (指向 num 的地址)
| 0x3000          | pp     | 0x2000 (指向 p 的地址)
+----------------+--------+-----------------
```

在这个内存图中，`num` 存储在地址 `0x1000` 处，值为 10。指针 `p` 存储在地址 `0x2000` 处，它指向 `num` 的地址 `0x1000`。二级指针 `pp` 存储在地址 `0x3000` 处，它指向 `p` 的地址 `0x2000`。通过 `*pp` 可以得到 `p` 的值（即 `num` 的地址），再通过 `**pp` 可以得到 `num` 的值。

通过以上内容，你应该对指针的核心概念有了更深入的理解。指针是 C 和 C++ 中非常强大的特性，但也需要谨慎使用，避免出现内存错误。