娓娓道来c指针 (3)指针和数组「建议收藏」

娓娓道来c指针 (3)指针和数组

大家好,又见面了,我是全栈君。

                            (3)指针和数组

在c中指针和数组似乎有着千丝万缕的关系。事实上它们不是一回事:指针是指针,数组是数组。两者不同样。

说它们有关系,只是是由于常见这种代码:

int main()
{
	int array[] = {1,2,3,4,5};
	int n = sizeof(array) / sizeof(int);
	int *p = array;
	int i;
	for (i = 0; i < n; i++)
		printf("p[%d]...%d\n", i, p[i]);
	system("pause");
	return 0;
}

执行

娓娓道来c指针 (3)指针和数组「建议收藏」

在上面的代码中,指针和下标运算符的结合使用,给人一种指针和数组是一样的感觉。

本质是:数组名是一个指向数组起始元素的常量指针。这也是数组和指针的唯一联系!

之所以能够使用 p[i] 来訪问数组中的元素,是由于在编译器中 p[i] 被解释为 *(p+i),这仍然是指针的功能。

对编译器而言,用p[i]表达*(p+i)的含义是没有意义的。它仅仅是为了让人看着舒服。用着方便。这是语法糖

    p[i]是*(p+i)的简单写法,实际上。至少对于编译器来说,[]这种运算符全然能够不存在。

    但是对于人类来说。*(p+i)的写法在解读上比較困难,写起来也麻烦(键入量大)。因此,c语言引入[]运算符。

    就像这样。这些不过为了让人类easy理解而引入的功能,的确能够让我们感受到编程语言的甜蜜味道(easy着手),有时我们称这些功能为语法糖(syntax sugar 或者 syntactic sugar)。

以上摘自《征服c指针》。借此推荐这本书。书中一针见血地指出:仅仅有在声明语句中。[]才表达数组的含义。在表达式中,[]与数组无关!

总结起来就是。看似数组的使用方法:p[i],事实上是*(p+i)的语法糖。p仍然是指针,与数组并无关系。


指针和数组的不同之处,还能够从以下的样例看出

void fun(int array[5])
{
	printf("  sizeof(array)...%d\n", sizeof(array));
}
int main()
{
	int array[] = { 1, 2, 3, 4, 5 };
	printf("  sizeof(array)...%d\n", sizeof(array));
	fun(array);
	return 0;
}

执行

娓娓道来c指针 (3)指针和数组「建议收藏」

从执行结果看,函数形參尽管用数组的方式进行了声明,但仍然被当做指针。这揭示了c语言中传递数组时的规则:传递过去的是地址,是指向数组起始元素的地址。之所以这样,基于两点;

  1. 从效率上考虑。若是把整个数组赋值过去,太耗时,也耗空间。还不如传地址过去,使用同一份内容。
  2. 在c语言设计之初,赋值操作就仅限于基本类型(char、int、float……),而数组是聚合类型。
这给我们的编程启发是:传递数组时,不要忘了把数组大小也传递过去。否则,函数那边因为不知道数组大小,极易越界。

应这样设计函数 void fun(int *array, int n),n是数组大小。

另一点须要指出。即使函数被设计成void fun(int array[5], int n),array依旧被看成是指针。

也就是说即使数组带了长度。该长度也会被编译器忽略掉。一句话:形參中的数组统统看成指针。

既然如此,还不如直接写成void fun(int *array, int n)。指针的形式。更能表达本意。


再思考:假设p[i]是*(p+i)的意思。因为加法具有交换律:p+i=i+p,那么i[p]相同能够表达p[i]的意思,是这种吗?实验验证:
int main(){	int array[] = { 1, 2, 3, 4, 5 };	int n = sizeof(array) / sizeof(int);	int *p = array;	int i;	for (i = 0; i < n; i++)		printf("  %d[p]...%d\n", i, i[p]);	return 0;}

执行

娓娓道来c指针 (3)指针和数组「建议收藏」
实验证明,我们的猜想是正确的:p[i]确实是*(p+i)的语法糖。i[p]这种写法是否非常逆天呢!

总结:仅仅有在函数形參中,仅有这一种情况,声明的数组。如 int array[]会被看作是指针。其他情况下,指针与数组并无联系。

&array的含义
另一点,对于 int array[5];array表示指向数组起始元素的指针,那么&array又是什么呢?实验下:
int main(){	int array[] = { 1, 2};	printf("   array...%p\n", array);	printf("  &array...%p\n", &array);	printf("&array+1...%p\n", &array+1);	return 0;}

执行

娓娓道来c指针 (3)指针和数组「建议收藏」
分析实验结果:0031FCEC与0031FCE4相差8。而sizeof(array)就是8。
结论就是:array和&array都是指针。但类型不同。array的类型是int*。而&array的类型是int(*)[2]。

array是指向普通int类型的指针;&array是数组指针,该数组元素是int类型的,且数组大小是2。

至于array和&array两者的值是一样的,应该非常好理解。

补充
标量(scalar):简单讲,标量就是指char、int、double和枚举类型等数值类型,再加上指针。

至于数组、结构体和共用体这样将多个标量进行组合的类型,我们称之为聚合类型(aggregate)。

那么为什么int(*)[2]表示的是数组指针呢?这须要透彻理解c的声明语法。又比方。二维数组(更甚者,多维数组)的数组名又是什么类型的指针呢?这须要了解c中数组的实际含义,后序解说。

很多其它指针和数组的内容见(5)c数组本质


专栏文件夹:


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/115590.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 2193. 分配问题(最小费用最大流解决最佳二分图问题)

    2193. 分配问题(最小费用最大流解决最佳二分图问题)有 n 件工作要分配给 n 个人做。第 i 个人做第 j 件工作产生的效益为 cij。试设计一个将 n 件工作分配给 n 个人做的分配方案。对于给定的 n 件工作和 n 个人,计算最优分配方案和最差分配方案。输入格式第 1 行有 1 个正整数 n,表示有 n 件工作要分配给 n 个人做。接下来的 n 行中,每行有 n 个整数 cij,表示第 i 个人做第 j 件工作产生的效益为 cij。输出格式第一行输出最差分配方案下的最小总效益。第二行输出最优分配方案下的最大总效益。数据范围1≤n≤

    2022年8月9日
    3
  • mysql utf8占几个字节_utf-8的中文是一个字符占几个字节

    mysql utf8占几个字节_utf-8的中文是一个字符占几个字节英文字母和中文汉字在不同字符集编码下的字节数英文字母:·字节数:1;编码:GB2312字节数:1;编码:GBK字节数:1;编码:GB18030字节数:1;编码:ISO-8859-1字节数:1;编码:UTF-8字节数:4;编码:UTF-16字节数:2;编码:UTF-16BE字节数:2;编码:UTF-16LE中文汉字:字节数:2;编码:GB2312字节数:2;编…

    2022年6月26日
    28
  • XRDP与VNC的关系

    XRDP与VNC的关系

    2022年2月3日
    112
  • mysql resulttype_MyBatis-resultType 与 resultMap 中的几种返回类型「建议收藏」

    一、返回集合1.返回JavaBean集合publicListselectMyUserByNameLike(Stringname);select*frommyuserwherenamelike#{name}测试方法publicstaticvoidmain(String[]args){SqlSessionsession=null;try{InputStreaminpu…

    2022年4月12日
    185
  • 修改Docker中nginx容器默认的端口号配置[通俗易懂]

    修改Docker中nginx容器默认的端口号配置[通俗易懂]修改nginx的默认端口号一般来说,nginx默认使用的是80端口号,但是狗血的是服务器上80端口号被占用了

    2025年8月30日
    5
  • 信道和带宽_信道带宽怎么计算

    信道和带宽_信道带宽怎么计算信道和带宽在用cmw500测试不同band下的throughput时,发现module在某几个band注册不上小区。后来经过同事顺滑的演示,得知是因为不同band支持不同的带宽,而我一直设置cmw500的Cellbandwidth=20MHZ,对于那些最大只支持10MHZ的band自然注册不上。关于不同Band支持的带宽可以参考下表(3GPPTS36.101V17.2.0(2021-06))Table5.6.1-1:E-UTRAchannelbandwidth结尾处分享一

    2022年10月7日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号