文章目录
- 数组地址的移位
- C 源程序和函数的关系
- 二维数组值的表示方式
- (n & (n-1)) == 0
- 容易出错的 ++
- 位运算
- fseek 可以实现的操作
数组地址的移位
个人理解:
这题的 A C 选项的差别应该在优先级上(下文有 C 语言运算符优先级表),取地址 和 ++ 属于同一类(单目运算符),所有单目运算符的优先级都是 2,而且和其他运算符不同的是,其他运算符与同等级运算符同时存在时,是从左往右结合,但单目运算符是从右往左。那这样是不是说 C 选项没问题呢?
C 还是有问题的,错就错在 ++ 在 a[0] 右边,我们都知道累加运算符是先取值再加 1,所以 &a[0]++ 还是会先取 a[0] 的地址,然后再加 1,但是,这里又有问题了,这时的加 1 会作用在 a[0] 上还是 &a[0] 上呢?。。。
网上解答(来源不详)
&a[0]++;是错误语句,编译都不会过。因为++是后++,在执行该语句时是不计算的,所以a[0]++是个表达式而不是值,显然用&取一个表达式的地址是非法操作!而如果是&++a[0];则是正确的,因为前++在执行&时已经计算过了:就是先给a[0]+1,然后再取a[0]的地址。
这样才能解释通了,& 不能操作一个表达式,但 &++a[0] 却是没问题的。
下面是 C 语言运算符的优先级表(图片来自网络)
另外,如果题目中的数组的数据类型为 char,那么答案会是怎样的呢?答案依然是相同的,除非选项中出现了 &a + 1(原因见下文,但貌似不改题目,&a + 1 也是错的)。
题目的讨论区里还有下面这样一句话(貌似作者写错了):
要区分A中的&a[0]+1和&a+1。虽然a作为数组名可以认为是指向数组第一个元素的指针,但是其本质上不是指针,而是编译器隐式来处理成指针。在sizeof和&时例外,所以这里如果是&a+1的话,+1的偏移量取决于数组大小;而a[0]是数组元素,所以+1的偏移量是数组元素的大小。
这句话有点问题,把 &a + 1 改成 a + 1 才对。&a[0] + 1 的偏移量单位为数组类型的字节大小,但 &a + 1 的偏移量单位是数组总大小。
这里简单讨论一下 &a ,a,和 &a[0] 三者的关系,&a[0] 很好理解,就是取数组第一个元素的地址,& 和 [] 抵消,所以 &a[0] 等价于 a + 0(即 a),都表示数组第一个元素的首地址;而 &a 是整个数组的首地址,它的值和 a 是相同的,但意义显然不同,a + 1 是数组第二个元素的地址,而 &a + 1 就直接跳到数组外面去了。
这里可以联想到多维数组,假如有数组 b[2][3],&b[0] 表示第一个元素的地址,&b[0] + 1 等价于 b + 1 和 b[1],b[0] 和 b[1] 两个地址的差值就是 3 个数组元素的大小,也就是第二维数组的大小,而假设 b[0] 就是 a,那么 a 这个数组的大小就是 3 个元素的大小,&a + 1 偏移的大小就是 a 数组的总大小。
C 源程序和函数的关系
1、一个C语言源程序可以由一个或多个源文件组成。
2、每个源文件可由一个或多个函数组成。
3、一个源程序不论由多少个文件组成,都有一个且只能有一个main函数,即主函数。
4、源程序中可以有预处理命令(include 命令仅为其中的一种),预处理命令通常应放在源文件或源程序的最前面。
5、每一个说明,每一个语句都必须以分号结尾。但预处理命令,函数头和花括号“}”之后不能加分号。
6、标识符,关键字之间必须至少加一个空格以示间隔。若已有明显的间隔符,也可不再加空格来间隔。
7、C语言中,有一组相关的控制语句,用以实现选择结构与循环结构:选择控制语句:if; switch、case。循环控制语句:for、while、do…while。转移控制语句:break、continue、goto。——https://www.php.cn/faq/447392.html
感觉 B 选项是对的呀。
二维数组值的表示方式
把数组第二维的大小看成 3 了。。。 1 * 4 + 3 = 7, B 是对的。
(n & (n-1)) == 0
n & n - 1 可以把 n 的二进制的最后一个 1 变为 0,如果 n & (n - 1) == 0,说明 n 的二进制中只有一位是 1,即为 2的幂。2 的幂并不全是偶数,20=1 就是一个奇数,所以该判断是错误的。前面也提到了,这个式子的含义是判断 n 是否为 2 的幂。
容易出错的 ++
这题出错是因为粗心,不过还是简单梳理一下:
p 是一个 struct student 类型指针,指向 stu[3] 这个数组,A 选项,p->num 等价于 p[0].num 即 6001,A 选项结果为 6002;B 选项,p++ 这个括号是多余的,最后结果就是 p->num ,即 6001;C 选项,结果是 6001;D 选项,p 先偏移一位,然后取值,即 p[1],p[1].num = 6003,选 D。
位运算
程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算就是直接对整数在内存中的二进制位进行操作。
C 语言基本类型包括:整型数据类型、字符数据类型和浮点型数据类型。字符数据都有对应的数字编号,所以也可以参与位运算(相当于整数的位运算)。浮点数有三部分组成:符号位,指数位,数值位。移位操作会使指数位与数值位之间移动,产生的结果没有什么意义。
左移一位才是原操作数的两倍。。。
负数右移高位补 1。
fseek 可以实现的操作
没注意是多选题。。。