C语言的4个冷知识



By
jonson
17 2 月 24
0
comment

01 数组的下标可以是负数

C语言中使用数组,一般来说都是这样的:

int ary[5] = {1, 2, 3, 4, 5};ary[0] = 10;

语法规定,数组的长度必须是个常量,保证数组所占的内存大小不变。

数组下标从 0 开始,依次往后递增。

于是大部分同学都把它当作了默认的规则。

其实,数组的长度可以是0,叫做柔性数组,目的是让结构体变成可变长度,不过也是使用 malloc 进行空间的申请。

另外,数组的下标也可以是负数,正数表示向后访问,负数表示向前访问。

比如:

int ary[5] = {1, 2, 3, 4, 5};int *p = &ary[2];p[-2] = 0;

如果不太明白,可以看下下面的内存示意图:

对于二维数组,同样可以使用负数的下标来访问元素。

int ary[3][3] = {{1, 2, 3}, {2, 3, 4}, {3, 4, 5}};int (*p)[3] = ary + 2;printf(" %dn ", p[-1][-1]);

指针p指向数组的第三行,p[-1]表示第二行的首元素地址,p[-1][-1]表示第二行首元素的前面一个元素,即第一行最后一个元素

注意:二维数组在内存中也是连续的。

使用负数作为下标来访问数组,切记内存不要越界,访问的内存一定是存在的,否则肯定有可能导致程序崩溃聪明的同学应该也能发现,这个所谓的负数其实只是指针的加减运算而已,坦白说并没有什么用。

02 数组名可以放在括号中

在 C语言中,数组和指针在使用上是等价的,数组可以使用指针来表示,指针也可以通过下标来访问,这在上一个讨论中已经看到,如:

ary[i] =  0x55;*(ary + i) = 0x55;*(i + ary) = 0x55;

以上三行代码的效果是一样的, 冷知识在于,编译器也支持这样的用法:

i[ary] = 100;  // 提醒一下,数组名称放到了[]里面

在 MDK 中验证一下,如下,编译通过,0 error  ,0 waring。

这种用法放到到二维数组中也是一样的道理,例子如下:

int ary[3][3] = {{1, 2, 3}, {2, 3, 4}, {3, 4, 5}};printf("%dn",2[array][2]);

当然我们一点也不推荐这种写法,这样的冷知识,我们了解一下,以备和面试官侃天说地时用。

03. sizeof是一个运算符

在初学C语言的时候,我们刚刚接触到整型,浮点型数据,总是用 sizeof 来判断数据类型占用的内存空间,比如,我们常常会这样写:

float sum;int bytes = sizeof(sum);

这样来使用sizeof,就会使我们误以为,sizeof是一个函数。但是实际上,你像下面这样写,也是没有问题的:

int bytes = sizeof sum; //

从上面可以观察到,sizeof 绝对不是一个函数,因为没有括号一样可以运行,所以他本质上是一个 C语言的关键字或者看做运算也可以,如同 +, – , * , / 一样,而不是sqrt()这种函数。但是要注意,如果是求整型关键字就必须要加括号,比如:

int bytes = sizeof (float); //

这地方用运算来看待 sizeof 也是可以理解的,因为 float 是一个关键字,他前面只能加 unsinged,或者 const 这些关键字。 这里你可以假想是我们将 0 进行强制类型转换为 float,然后去计算这个变量占用空间的大小,如:

int bytes = sizeof (float) 0; // 这里可以假想是 0 被省略了

04. 空格不都是没用的

一般情况下,学校老师会告诉我们,大部分情况下,空格在C语言程序中是无关紧要的,或者说除了预处理器那部分代码,空格无关紧要。但是,可以尝试思考一下下面这两条语句:

printf("Hello World");printf("Hello  World");

看出这两行代码的区别了吗?其实下面那条是不合法的,就是因为转义字符后面多加了一个空格。当然,这个例子是特意为了说明这个问题举得,这么短的代码实在也没有必要换行。

发表回复