元芳你怎么看

本网站主要用于记录我个人学习的内容,希望对你有所帮助

0%

指针和数组

指针和数组

C 语言中指针和数组这两个概念密不可分,以至于如果没有理解其中一个概念,就无法彻底理解另一个概念。

数组

很基础的一些知识点我就不重复了。关于数组,需要注意的有两个点:

  1. C 语言中只有一维数组,而且编译期间就要知道数组的精确大小。数组的元素可以是任何类型的对象,当然也包含了数组,这也就是多维数组。
  2. 对于一个数组,我们其实只能干两件事情:确定数组的大小、获取指向该数组下标为 0 的元素的指针。看到这话你是不是要反驳我了:不对呀,你写博客写糊涂了吧?我还可以arr[1]的操作呀。其实[]操作的本质是通过指针来实现的。比如arr[i] = 1其实上是*(arr + i) = 1,这里的 arr就是指向该数组下标为 0 的元素的指针。

既然arr[0] = 1本质上是*(arr + 0) = 1,那么我们可以整个活:

1
0[arr] = 1;

读者可以自行尝试一下,这样的代码是否可行。

二维数组

二维数组内存相关
  • 第一种情况:是直接声明的二维数组

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    #include <stdio.h>

    int main() {
    int rows = 3; // 行数
    int cols = 4; // 列数
    int arr[rows][cols];

    // 初始化二维数组
    for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
    arr[i][j] = i * cols + j;
    }
    }

    // 验证地址连续性
    int *ptr = &arr[0][0];
    int isContiguous = 1;

    for (int i = 0; i < rows; i++) {
    for (int j = 0; j < cols; j++) {
    // 计算下一个元素的地址
    int *nextPtr = &arr[i][j];
    printf("%p\n",&arr[i][j]);
    if (nextPtr != ptr) {
    isContiguous = 0;
    break;
    }
    ptr++;
    }
    }

    if (isContiguous) {
    printf("二维数组的地址是连续的。\n");
    } else {
    printf("二维数组的地址不是连续的。\n");
    }

    return 0;
    }

    运行结果如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    0x7fff2f05bb80
    0x7fff2f05bb84
    0x7fff2f05bb88
    0x7fff2f05bb8c
    0x7fff2f05bb90
    0x7fff2f05bb94
    0x7fff2f05bb98
    0x7fff2f05bb9c
    0x7fff2f05bba0
    0x7fff2f05bba4
    0x7fff2f05bba8
    0x7fff2f05bbac
    二维数组的地址是连续的。
  • 第二种情况:使用malloc来分配一个二维数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <stdio.h>
#include <stdlib.h>

int main() {
int rows = 3; // 行数
int cols = 4; // 列数

// 使用malloc分配内存
int **arr = (int **)malloc(rows * sizeof(int *));
for (int i = 0; i < rows; i++) {
arr[i] = (int *)malloc(cols * sizeof(int));
}

// 初始化二维数组
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
arr[i][j] = i * cols + j;
printf("%p\n", (void *)&arr[i][j]);
}
}

// 验证地址连续性
int *ptr = &arr[0][0];
int isContiguous = 1;

for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
// 计算下一个元素的地址
int *nextPtr = &arr[i][j];
if (nextPtr != ptr) {
isContiguous = 0;
break;
}
ptr++;
}
}

if (isContiguous) {
printf("通过malloc分配的二维数组的地址是连续的。\n");
} else {
printf("通过malloc分配的二维数组的地址不是连续的。\n");
}

// 释放分配的内存
for (int i = 0; i < rows; i++) {
free(arr[i]);
}
free(arr);

return 0;
}

运行结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
0x55b2818142c0
0x55b2818142c4
0x55b2818142c8
0x55b2818142cc
0x55b2818142e0
0x55b2818142e4
0x55b2818142e8
0x55b2818142ec
0x55b281814300
0x55b281814304
0x55b281814308
0x55b28181430c
通过malloc分配的二维数组的地址不是连续的。

通过 malloc 分配的二维数组的地址在内存中通常是不连续的。malloc 函数分配的内存块是堆内存,这些内存块通常在堆中的不同位置。因此,二维数组的各行和各列在内存中可能是分散的,不一定是连续的。

当你使用 malloc 分配一个二维数组时,你实际上在堆中创建了一个指向指针的数组,其中每个指针指向一个独立的内存块(一维数组),这些内存块存储了实际的数据。因此,二维数组的不同行在堆中的不同位置,它们不是物理上连续的内存块。

如果你需要连续的内存块以便于优化访问或传递给函数,你可以使用一维数组来模拟二维数组,并在计算索引时手动进行转换,以使其在一维数组中是连续的。这将涉及到一些数学运算,但可以帮助你实现连续内存存储。

如果你需要大规模的多维数组,并且连续内存非常重要,你可能需要考虑使用静态数组或者专门设计的数据结构,而不是 malloc 动态分配的内存。