学习
实践
活动
专区
工具
TVP
写文章

给K&R的C挑个“错”

Kernighan和Ritchie合写的《The C Programming Language, Second Edition》虽然是二三十年前的书了, 但仍被认为是有关C语言的经典之作。被人饱含深情的称之为“K&R”。

题目略有些标题党,但是在C范围内,称之为错,也勉强说得过去。

01

清晰的图和令人困惑表述

在K&R第二版第五章的9和10节中有这样两个图。

俗话所,一图胜千言。两个图对于理解name和argv是大有用处的:图1中是说name是一个数组,数组的每个元素是指向字符串的指针;图2是说argv是一个指针,它指向一个数组,这个被指向的数组的元素是指向字符串的指针。

单从这两个图上看,name和argv的类型是不同的,但从C/C++中带参数的main的参数列表写法:main(int argc, char *argv[])可以看到,name和argv的声明方式是一样的。从语法上讲,这样的声明方式是在告诉编译器,name和argv都是数组,就像图1那样。那么为什么K&R会说argv是一个指针呢?

在第10节中,K&R给出的第二版本的echo函数是这样写的:

如果argv是数组的话,那么在编译时应该会出错,但是实际上这种写法可以可以正常编译运行。

这是我称之为“错”的地方:为什么明明声明了一个数组,但是却能够当做指针来用呢?

02

K&R的解释没错

K&R说argv是指针是没有问题的,只是需要加一些注解。当然,要提前说明,这部分只是笔者的理解,可能是有瑕疵的,也可能是不靠谱的。

K&R第五章的标题是“指针和数组”,这章的开篇,K&R就写到“指针和数组是紧密相关的。”但紧密相关和完全一样毕竟是两码事儿。

比如, 可以用指针打印数组。

但是如果将12行中*pa++改成*a++,将会编译不通过:

原因就是指针是一个变量,而数组名却不是。

那么为什么K&R的第二个版本的echo在编译时不报错呢?

问题的关键在函数调用。

当数组名作为函数参数时,实际传递的这个数组第一个元素的地址,也就意味着实际传递的是指针。

这就是K&R说argv是指针的原因。将带参数的main写成main(int argc, char **argv)也许是一种更好的方式。

通过阅读编译器生成的汇编代码,那么函数调用的过程就可以看得更加清楚明白。

一言以蔽之,标题所说的“错” ,实际上并不是错,在理解了指针和数组的关系后,就能够理解为什么K&R和C++ Primer对于argv的表述虽不尽相同,但本质上一样的。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180609G0QPNY00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

关注

腾讯云开发者公众号
10元无门槛代金券
洞察腾讯核心技术
剖析业界实践案例
腾讯云开发者公众号二维码

扫码关注腾讯云开发者

领取腾讯云代金券