一维数组与指针
数组名代表的数组的首地址,通过这个首地址我们可以对这块内存区域进行访问,因为数组分配空间是按照顺序依次分配的。
1 2 3 4 5 6 7 8
| int a[] = {1, 2, 3, 4, 5};
std::cout << "show array a : "; for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i) { std::cout << a[i] << "\t"; } std::cout << std::endl;
|
输出:
1
| show array a : 1 2 3 4 5
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| int a[] = {1, 2, 3, 4, 5};
PRINT_INFO("a = " << a);
for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i) { PRINT_INFO("----------------------------"); PRINT_INFO("&a[" << i << "] = " << &a[i]); PRINT_INFO("a[" << i << "] = " << a[i]); PRINT_INFO("a + " << i << " = " << a + i); PRINT_INFO("*(a+" << i << ") = " << *(a + i)); PRINT_INFO("----------------------------"); }
PRINT_INFO("&a = " << &a); PRINT_INFO("&a + 1 = " << &a + 1);
PRINT_INFO("(&a + 1) - &a = " << (char* )(&a + 1) - (char* )&a);
|
输出:
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
| [INFO]: a = 0x7fff1b9e6300 [INFO]: ---------------------------- [INFO]: &a[0] = 0x7fff1b9e6300 [INFO]: a[0] = 1 [INFO]: a + 0 = 0x7fff1b9e6300 [INFO]: *(a+0) = 1 [INFO]: ---------------------------- [INFO]: ---------------------------- [INFO]: &a[1] = 0x7fff1b9e6304 [INFO]: a[1] = 2 [INFO]: a + 1 = 0x7fff1b9e6304 [INFO]: *(a+1) = 2 [INFO]: ---------------------------- [INFO]: ---------------------------- [INFO]: &a[2] = 0x7fff1b9e6308 [INFO]: a[2] = 3 [INFO]: a + 2 = 0x7fff1b9e6308 [INFO]: *(a+2) = 3 [INFO]: ---------------------------- [INFO]: ---------------------------- [INFO]: &a[3] = 0x7fff1b9e630c [INFO]: a[3] = 4 [INFO]: a + 3 = 0x7fff1b9e630c [INFO]: *(a+3) = 4 [INFO]: ---------------------------- [INFO]: ---------------------------- [INFO]: &a[4] = 0x7fff1b9e6310 [INFO]: a[4] = 5 [INFO]: a + 4 = 0x7fff1b9e6310 [INFO]: *(a+4) = 5 [INFO]: ---------------------------- [INFO]: &a = 0x7fff1b9e6300 [INFO]: &a + 1 = 0x7fff1b9e6314 [INFO]: (&a + 1) - &a = 20
|
数组名 a 代表着数组的首地址,a[i] <==> *(a+i) 这个表达式是等价的,a+i 表示的是以内存地址a 移动了 i 个 int 的地址。
a,&a[0],&a 这三个元素打印的地址是相同的,但是他们三个的意义却是有很大的不同。a 代表数组的首地址,在其是一维数组时,与 &a[0] 代表的意义一样,首地址。
&a 代表的是把数组看成一个整体取地址 &a + 1 则表示数组作为一个整体移动了一个元素(数组),其实相当于移动了 5 * 4 = 20 个字节
利用数组名,指针变量来访问数组元素:
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
| int a[] = {1, 2, 3, 4, 5}; int *p = NULL;
for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i) { PRINT_INFO("a[" << i << "] = " << a[i]); }
PRINT_INFO("----------------------------");
for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i) { PRINT_INFO("*(a + " << i << ") = " << *(a + i)); }
PRINT_INFO("----------------------------");
p = &a[0];
for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i) { PRINT_INFO("*(p + " << i << ") = " << *(p + i)); }
|
输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| [INFO]: a[0] = 1 [INFO]: a[1] = 2 [INFO]: a[2] = 3 [INFO]: a[3] = 4 [INFO]: a[4] = 5 [INFO]: ---------------------------- [INFO]: *(a + 0) = 1 [INFO]: *(a + 1) = 2 [INFO]: *(a + 2) = 3 [INFO]: *(a + 3) = 4 [INFO]: *(a + 4) = 5 [INFO]: ---------------------------- [INFO]: *(p + 0) = 1 [INFO]: *(p + 1) = 2 [INFO]: *(p + 2) = 3 [INFO]: *(p + 3) = 4 [INFO]: *(p + 4) = 5
|
二维数组与指针
二维数组的各个地址的含义
数组名代表了数组的首地址,也代表了第一行的首地址。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| int a[][3] = {{1, 2, 3}, {4, 5, 6}};
PRINT_INFO("a = " << a); PRINT_INFO("a + 1 = " << a + 1); PRINT_INFO("a[0] = " << a[0]); PRINT_INFO("a[1] = " << a[1]); PRINT_INFO("a[0] + 1 = " << a[0] + 1); PRINT_INFO("a[1] + 1 = " << a[1] + 1); PRINT_INFO("&a[0] = " << &a[0]); PRINT_INFO("&a[1] = " << &a[1]); PRINT_INFO("&a[0] + 1 = " << &a[0] + 1); PRINT_INFO("&a[1] + 1 = " << &a[1] + 1); PRINT_INFO("&a[0][0] = " << &a[0][0]); PRINT_INFO("&a = " << &a); PRINT_INFO("&a + 1 = " << &a + 1);
PRINT_INFO("(&a + 1) - &a = " << (char* )(&a + 1) - (char* )&a);
|
输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| [INFO]: a = 0x7fff7d937ba0 [INFO]: a + 1 = 0x7fff7d937bac [INFO]: a[0] = 0x7fff7d937ba0 [INFO]: a[1] = 0x7fff7d937bac [INFO]: a[0] + 1 = 0x7fff7d937ba4 [INFO]: a[1] + 1 = 0x7fff7d937bb0 [INFO]: &a[0] = 0x7fff7d937ba0 [INFO]: &a[1] = 0x7fff7d937bac [INFO]: &a[0] + 1 = 0x7fff7d937bac [INFO]: &a[1] + 1 = 0x7fff7d937bb8 [INFO]: &a[0][0] = 0x7fff7d937ba0 [INFO]: &a = 0x7fff7d937ba0 [INFO]: &a + 1 = 0x7fff7d937bb8 [INFO]: (&a + 1) - &a = 24
|
通过上面的程序,可以知道的是 a 代表了数组的首地址,代表了第一行的首地址。记住了它这里与 &a[0][0] 值相等但是并没有代表他的含义。我们可以把二维数组这么认为,把每一行当成一个整体作为一个元素,所以有咱们的 a[0], a[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
| int a[][3] = {{1, 2, 3}, {4, 5, 6}}; int* p[2] = {NULL};
p[0] = a[0]; p[1] = a[1];
for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i) { for (int j = 0; j < 3; ++j) { PRINT_INFO("a[" << i << "][" << j << "] = " << a[i][j]); PRINT_INFO("p[" << i << "][" << j << "] = " << p[i][j]); } }
PRINT_INFO("----------------------------");
for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i) { for (int j = 0; j < 3; ++j) { PRINT_INFO("*(p[" << i << "] + " << j << ") = " << *(p[i] + j) ); } }
PRINT_INFO("----------------------------");
for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i) { for (int j = 0; j < 3; ++j) { PRINT_INFO("*(*(p + " << i << ") + " << j << ") = " << *(*(p + i) + j) ); } }
|
输出:
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
| [INFO]: a[0][0] = 1 [INFO]: p[0][0] = 1 [INFO]: a[0][1] = 2 [INFO]: p[0][1] = 2 [INFO]: a[0][2] = 3 [INFO]: p[0][2] = 3 [INFO]: a[1][0] = 4 [INFO]: p[1][0] = 4 [INFO]: a[1][1] = 5 [INFO]: p[1][1] = 5 [INFO]: a[1][2] = 6 [INFO]: p[1][2] = 6 [INFO]: ---------------------------- [INFO]: *(p[0] + 0) = 1 [INFO]: *(p[0] + 1) = 2 [INFO]: *(p[0] + 2) = 3 [INFO]: *(p[1] + 0) = 4 [INFO]: *(p[1] + 1) = 5 [INFO]: *(p[1] + 2) = 6 [INFO]: ---------------------------- [INFO]: *(*(p + 0) + 0) = 1 [INFO]: *(*(p + 0) + 1) = 2 [INFO]: *(*(p + 0) + 2) = 3 [INFO]: *(*(p + 1) + 0) = 4 [INFO]: *(*(p + 1) + 1) = 5 [INFO]: *(*(p + 1) + 2) = 6
|
以上三种方式情况都能访问到我们的二维数组。
首先我们定义的指针数组,那么数组的元素只能是指针,同时我们上面进行了分析, 将二维数组的每行看成是一个一维数组,那么 a[0], a[1] 就是每行的首地址。那么我们初始化指针数组就顺理成章了。此时数组 a 里面就有两个元素 a[0] 和 a[1]。
p[0] == a[0] p[1] == a[1] ,知道每行的首地址移动 j 个元素,实际偏移的地址量 sizeof(类型) * j 个字节。那么知道了地址取出这个单元个的值,加 * 就 ok 了,我们知道带有中括号的表达式可以这么写 p[i] == *(p + i)。
数组指针
定语是指针,那么作为指针就应该有指向了,只不过它指向的是一个数组,一个什么样的数组呢,它指向一个包含 N 个元素的一维数组。原型如:int (*p) [N];
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
| int a[][3] = {{1, 2, 3}, {4, 5, 6}};
int (*p) [3] = NULL;
p = a;
for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i) { for (int j = 0; j < 3; ++j) { PRINT_INFO("*(p[" << i << "] + " << j << ") = " << *(p[i] + j) ); } }
for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i) { for (int j = 0; j < 3; ++j) { PRINT_INFO("*(*(p + " << i << ") + " << j << ") = " << *(*(p + i) + j) ); } }
|
输出:
1 2 3 4 5 6 7 8 9 10 11 12
| [INFO]: *(p[0] + 0) = 1 [INFO]: *(p[0] + 1) = 2 [INFO]: *(p[0] + 2) = 3 [INFO]: *(p[1] + 0) = 4 [INFO]: *(p[1] + 1) = 5 [INFO]: *(p[1] + 2) = 6 [INFO]: *(*(p + 0) + 0) = 1 [INFO]: *(*(p + 0) + 1) = 2 [INFO]: *(*(p + 0) + 2) = 3 [INFO]: *(*(p + 1) + 0) = 4 [INFO]: *(*(p + 1) + 1) = 5 [INFO]: *(*(p + 1) + 2) = 6
|
大家要注意的是类型的是为指针变量赋值的时候,类型要匹配。
二维数组 a 代表着数组名,同时也是第一行的首地址,我们说把每个一维数组当成一个整体,那么我们的二维数组就成了一个一维数组了,一维数组怎么取元素的呢? a[0], a[1] … a[i] 就是这个二维数组中每一个一维数组的值,但是切记它也只是一个地址。所以取整个数组的元素的值就有了上面的表述方式了。 *(a[i] + j) ,*(*(a + i) + j), i 表示行指针 a 移动的行数,取出它的值是一行的首地址, j 表示在此行的基础上移动的列数,最终得到的是这个数组第 i 行 j 列的地址了,取值的话就加上 * 就 ok 了。
数组指针,本质是一个指针,指向了一个数组,那么它里面存放的是一个地址。你可以把理解为一个二级指针。这样也是可以的。
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
| int a[][3] = {{1, 2, 3}, {4, 5, 6}};
int (*p) [3] = NULL;
p = &a[0];
for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i) { for (int j = 0; j < 3; ++j) { PRINT_INFO("*(p[" << i << "] + " << j << ") = " << *(p[i] + j) ); } }
for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i) { for (int j = 0; j < 3; ++j) { PRINT_INFO("*(*(p + " << i << ") + " << j << ") = " << *(*(p + i) + j) ); } }
|
数组指针数组
按照咱们的上面来分析,定语是数组,那么数组就有元素,修饰语就是数组指针,那么我们可以这么认为它的本质是一个数组,数组包含了若干个元素,每个元素都是一个数组指针,也就是每一个元素是一个指针,指向了一个数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| int a[][3] = {{1, 2, 3}, {4, 5, 6}}; int b[][3] = {{7, 8, 9}, {10, 11, 12}};
int (* p[]) [3] = {a, b};
for (int k = 0; k < sizeof(p) / sizeof(p[0]); ++k) { for (int i = 0; i < 2; ++i) { for (int j = 0; j < 3; ++j) { PRINT_INFO("*(*(p[" << k << "] + " << i << ") + " << j << ") = " << *(*(p[k] + i) + j) ); } } PRINT_INFO("------------------------"); }
|
输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| [INFO]: *(*(p[0] + 0) + 0) = 1 [INFO]: *(*(p[0] + 0) + 1) = 2 [INFO]: *(*(p[0] + 0) + 2) = 3 [INFO]: *(*(p[0] + 1) + 0) = 4 [INFO]: *(*(p[0] + 1) + 1) = 5 [INFO]: *(*(p[0] + 1) + 2) = 6 [INFO]: ------------------------ [INFO]: *(*(p[1] + 0) + 0) = 7 [INFO]: *(*(p[1] + 0) + 1) = 8 [INFO]: *(*(p[1] + 0) + 2) = 9 [INFO]: *(*(p[1] + 1) + 0) = 10 [INFO]: *(*(p[1] + 1) + 1) = 11 [INFO]: *(*(p[1] + 1) + 2) = 12 [INFO]: ------------------------
|