再谈数组与指针
来源:互联网 发布:编程语言薪资排行榜 编辑:程序博客网 时间:2024/05/21 03:56
在以前的一遍博文中,有谈到数组与指针,经过了一段时间,我对数组与指针的认识又更深入了一些………
(一)、数组是什么?
其实数组也是一种数组类型,对于元素是 int 类型的数组的类型就是 int []。
我们在进行函数声明的时候有时候会省略形参的标识符,只写上形参的类型,对于数组类型的形参我们就是写成这样 int []。
例如: int funtion(int [], int , int );(尽管在函数体内部会退化成指针。)
还有我可以对一个类型进行 sizeof 运算 sizeof(int) ,我们也可以对数组类型进行sizeof 运算,例如: sizeof(int [10]) (数组类型有多少元素要指出)。
用typedef 可以对数组类型取一个别名:
typedef int vegtable[10];
vegtable arr; <=====> int arr[10];
(二)、指针是什么?
指针是C/C++的最特别的地方,也是最难学好的地方!
但指针也没有那么晦涩难懂。
指针的本质是 变量和其他的变量一样,能被运算,真正区别于其他变量的是,指针存储的内容是地址。
那变量总有个数据类型的,指针的类型: 其实也就是地址的类型,而地址的类型取决于地址里存放的数据的类型!
指针的偏移步长,是指针指向地址的里数据类型进行 sizeof 运算的大小。
int *p; 指针p的步长就是 sizeof(int);
int (*p)[10]; 指针p的步长就是 sizeof(int [10]);
int (*p)[10][10]; 指针p的步长就是 sizeof(int [10][10]);
有时我们对指针进行强制类型转换,转换的本质是使指针指向的地址里的数据类型改变,这样指针的步长也会发生变化。
int (*p)[10]; 步长是 sizeof(int) 对指针p进行强制类型转换 int *pp = (int *)p; 现在pp的步长就是 sizeof(int)。
如何定义一个指向某个数据类型的指针(看一个指针指向什么数据类型)?
1)、是指针; (*p)
2)、指向什么类型数据; 例如: 指向整型 int (*p) ; 指向数组类型(元素是int,有10个元素) int (*p)[10];
指向函数(返回值是int,两个形参是int) int (*p)(int ,int);
3)、再给指针赋值。
(看一个指针指向什么数据类型 也类似上面的分析方法)
(三)、数组与指针什么时候通用,什么时候不通用?
数组与指针在一些地方是通用的,也有一些地方是不能互换的。
数组与指针在通用的时候,数组是退化成指针,我们对数组的操作就可以转化成对指针的操作。
例如对数组里元素的访问就 a[i] 实际上编译会之后会变成 *(a+i), 即使通过指针来访问元素的;数组作为形参传递给函数……
那数组在哪些情况不会退化指针呢?有三种情况下数组不会退化成指针的:
1)、sizeof 对数组进行 sizeof 运算的时候,数组不会退化成指针;
2)、& 对数组进行 & 运算时
3)、(自己暂时还未理解,理解就马上添加上)
除上面的三种情况外,数组都会退化成指针的。
(四)、数组指针与指针数组
我觉得中文有些饶人,不算是问题,如果你看英语对这俩概念的描述,或许你会很直观的区分它们:
数组指针: A pointer to an array int (*p)[10];
指针数组: An array of poiners to integers int *p[10];
我们看看对数组名进行 & 运算:
int a[10];
int *p = a; 是把 &a[0] 赋给 p,p+1 的偏移是sizeof(int) p指向数组的第一个元素
int (*p)[10] = &a; 是把 &a 赋给 p,p+1 的偏移是sizeof(int [10]) p指向整个数组 这就是一个数组指针
(五)、数组作为参数传递给函数
数组除上面讲的三种情况除外,数组都会退化成指针。
所以数组作为函数的参数时,数组会退化指针。
一维数组作参数的写法:
int fun(int a[10]);
int fun(int a[]);
int fun(int *a);
一维数组:上面这些都是传递首个元素的地址 &a[0],指针在函数体内的步长是 sizeof(int) 。
二维数组作参数的写法:
int fun(int a[10][10]);
int fun(int a[][10]);
int fun(int (*p)[10]);
二维数组:上面这些都是传递首行的地址 &a[0],也就是传递的是行地址,指针在函数体内的步长是 sizeof(int [10])。
现在来分析下 二维数组的 int fun(int a[][10]); 为什么是这种, 而像 int fun(int a[10][]); int fun(int a[][]);的传递方式不可以呢?
int a[10][10];
看二维数组前中括号里的数字(以下简称前数字)和后中括号里的数字(以下简称后数字)所代表的意义。
前数字 是数组的行数, 后数字 是代表的数字的每行的列数。
上面这句或许你认为我说了跟没说似的,但你看二位数组传入给函数的是首行的地址,在函数体内会对指针操作进行偏移,这时候就要步长了,而步长就是每行的列数,所以说必须传入每行的列数,即后数字,这样函数体内就知道二维数组传入的地址指针的偏移步长。
也需你会问,那行数为什么不用传入呢?
我们来对比一维数组,int fun(int a[]);一维数组没有传入的是元素的个数,在函数体内部,对于传入的指针来说是没有传入对指针操作的边界,这样就好理解了二维数组为什么没有传入行数,行数即是二维数组的行指针的操作边界。
我们会经常看见,一维数组作为函数参数时,还另外再传入一个参数(数组的元素的个数),这样就告诉函数对指针的操作边界。
所以在二维数组作为函数参数是,我们也可以再传入一个参数(数组的行数)告诉函数对指针的操作边界。
这样我们就可以类比多维数组作函数参数怎么传递了, 一定要传入对指针操作的步长。
例如: int fun(int a[][10][10]) 步长是 sizeof(int [10][10])。
另:二维数组的作函数参数还有两种非常危险的写法 int fun(int **a); int fun(int *a[10]);(多维数组类似,至于为什么你自己可以分析到的)。
以上都是我个人对与数组与指针的理解,若有什么不对或不足,欢迎指出,我会及时更正!转载请说明出处!
- 再谈数组与指针
- 指针:指针与数组
- 指针与指针数组
- 再论数组与指针
- 指针数组与数组指针
- 指针数组与数组指针
- 指针数组与数组指针
- 指针数组与数组指针
- 指针数组与数组指针
- 指针数组与数组指针
- 指针数组与数组指针
- 数组指针与指针数组
- 指针数组与数组指针
- 指针数组与数组指针
- 指针数组与数组指针
- 指针数组 与数组指针
- 指针数组与数组指针
- 数组指针与指针数组
- 浮点数在计算机中如何存储
- 浮点数在计算机中如何存储
- js判断复选框checkbox数组是否被选中
- 连接access数据库语句
- 邮箱和手机号码正则表达式验证(手机号码支持188)-HTML-XHTML-CSS
- 再谈数组与指针
- 各种实现下C++的扩展名。
- 计算机专业英语词汇
- Poppin 技术点
- 线程池
- DX步步为营(零)——入门篇
- 通过俄罗斯方块浅谈游戏中的AI(一)我眼中的小游戏AI
- 反射的基本用法简例!
- Map 遍历里面的元素