今天分析了C语言二维数组和指针的基本理解,感觉有点懵。。。代码记录一下,如果有大神临幸发现哪里有误,欢迎指正~~~
#include <stdio.h> #include <stdlib.h> #include <string.h> //void func(int p[][]) //这样写等同于void func(int **p) p++移动了四个字节,(*p)++移动了四个字节,不符合二维数组规律 //{ //} //列优先输出的函数(即竖着输出) void func(int p[][4], int a, int b) //这样写是正确的,这样写等同于void func(int (*p)[4]) p++移动16个字节,(*p)++移动了4个字节,a和b是为了保持维度,a表示列,b表示行 { for (int i = 0; i < a; i++) { for (int j = 0; j < b; j++) { printf("%d\n", *(*(p + j) + i)); } } } int main() { int array[3][4] = { { 0, 1, 2, 3 }, { 4, 5, 6, 7 }, { 8, 9, 10, 11 } }; //printf("%d\n", sizeof(array[0])); // 结果为16,妈的,array[0]竟然不是指针,而是一个数组的名称, //printf("%d\n", sizeof(array)); //结果48 func(array,
sizeof(array[0]) / sizeof(int), sizeof(array) / sizeof(array[0]));//
第二个参数是列数,第三个参数为行数 //array[0]并不是一个变量,是二维数组中第0行的首地址
//和下面的: *(p + 0) + 1; 代表int *向后位移了一个位置 道理上应该是相同的。 //在二维数组中*array代表的也是数组的首地址,而一维数组中*array代表的是第一个元素的值 //printf("%d %d %d %d\n", array, *array, &array, &array[0][0], array[0]); //
printf("%d\n", array + 1); //
printf("%d\n", array[0] + 1); //结果为array + 1 移动了16个字节 // array[0] + 1 移动了4个字节 //可以这样理解,array + 1看成连长,array[0] + 1看成排长,连长每次走一行(即走4个数,14个字节),排长每次走一列(即走一个数,4个字节) //int *p = array; //指向一维数组的指针
//int (*p)[4];
是一个变相的二级指针 //p = array; //*(p + 0) + 1; 代表int *向后位移了一个位置 //for (int i = 0; i < 4; i++) //{ // for (int j = 0; j < 3; j++) // { // printf("%d\n", *(*(p + j) + i)); // } //} //*(p + 0) 代表的是指向第一行的指针。所以*(p + 0) + 1 是指向第一行第二个元素的位置 //printf("---------------\n"); //----------- //p + 1; //代表的是排长,每次走一行 //p[0][0] = *(*(p + 0) + 0); //代表的是连长,每次走一个数 //printf("%d\n", *(*(p+1))); //第一行第0个元素 system("pause"); return 0; }
分析如下:
黄色代码部分:输出的地址完全相同,所以二维数组和一维数组的一点区别是: 在二维数组中*array代表的也是数组的首地址,而一维数组中*array代表的是第一个元素的值
红色代码部分: 相对于黄色代码部分,红色代码结果为: array + 1 移动了16个字节 , array[0] + 1 移动了4个字节;
因为array是数组的首地址,而且是一个二维数组,所以array+1 应该是移动一行,即4个数字,array[0]是二维数组的“第一行数组”的首地址,所以+1应该是在第一行数组里面移动指针;
( 如果 int *p = &i; 那么p+1的结果就会移动4个字节,如果 char *p = &i; 那么p+1的结果就会移动1个字节, 这里其实也是相同的道理,只是不好理解。。。)
也可以使用排长和连长的例子来理解,把array看成连长,把array[0]看成排长,连长每次审阅,会一行一行的走,排长审阅,则会一排一排的走,所以array(连长)每次走16个字节,array[0]每次走4个字节。
橘黄色代码部分: 定义二级指针的时候,一般会这样定义,int (*p)[4];
这里有一个“指针数组”和“数组指针”的概念,图示和代码如下:
指针数组: 数组指针
int *p[5]; int (*P)[10];
#include <stdio.h> #include <stdlib.h> int main() { //指针数组 char *s[10]; //是一个数组,该数组中有10个char *指针,每个指针指向一个字符 printf( "%d\n" ,sizeof (s[0])); //4 //数组指针 char (*s1)[10]; //是一个指针变量,该指针变量指向一个char[10];不能指向其他任何char[n]数组 printf( "%d\n" , sizeof (s1)); //4 system( "pause" ); return 0; }
所以:int (*p)[4]; 是一个数组指针,指向一个4个元素的数组,
p = array; 也就是把二维数组的首地址赋给p,array也是一个地址(相当于一个指针,但如果我们用sizeof(array)会发现其实不是一个指针),所以p其实是一个变相的二级指针(你不信的话可以利用**p测试看是否能够取到数组的第一个元素)
所以 *(p + 0) + 1; 代表int *向后位移了一个位置 也就不难理解了, p是一个二级指针, p+0代表的其实就是第一行数组的首地址。*(p+0) 还是一个指针, 也就是一个int * 类型的变量(指针也是一个变量),*(p + 0) + 1;代表的就是int *向后位置了一个位置
*(p + 0) 代表的是指向第一行的指针。所以*(p + 0) + 1 是指向第一行第二个元素的位置的指针,*(*(p + 0) + 1 ) 就是第一行第二个元素的值;
灰色颜色代码的部分: 这样写的原因就是直接把二维数组的维度发过去,因为在接收端函数方是不知道二维数组的维度的,而且这样写以后更改数组的维度的时候,不用更改其他代码。