错题集
约 1315 个字 19 行代码 预计阅读时间 5 分钟
按照TonyCrane老师的分类整理一下,不知道来不来得及只有两个半小时了
一. 运算符优先级
优先级 | 运算符 | 结合律 |
---|---|---|
1 | 后缀运算符:[] () · -> | 从左到右 |
2 | 一元运算符:++ -- ! ~ +(正) -(负) * & sizeof 类型转换 | 从右到左 |
3 | 乘除法运算符:* / % | 从左到右 |
4 | 加减法运算符:+ - | 从左到右 |
5 | 移位运算符:<< >> | 从左到右 |
6 | 关系运算符:< <= > >= | 从左到右 |
7 | 相等运算符:== != | 从左到右 |
8 | 位运算符 AND:& | 从左到右 |
9 | 位运算符 XOR:^ | 从左到右 |
10 | 位运算符 OR:| | 从左到右 |
11 | 逻辑运算符 AND:&& | 从左到右 |
12 | 逻辑运算符 OR:|| | 从左到右 |
13 | 条件运算符:?: | 从右到左 |
14 | 赋值运算符:= += -= *= /= %= &= ^= \|= <<= >>= |
从右到左 |
15 | 逗号运算符:, | 从左到右 |
二. 标识符关键词
define
可以用作关键词,它只是预处理命令
三. 数据类型
- 整型:
- 十进制:
123
- 八进制:
0123
- 16进制:
0x123
- 十进制:
- 字符型:
- 八进制:
\101
,最多三个字符,8以上也不行 - 16进制:
x41
,无长度限制
- 八进制:
四. 指针相关
4.1. 多级指针
用递归来理解:
int var = 1;
int *p1=&var;
int **p=&p1;
(int **)p -> (int *)p1 -> (int) var
4.2. 区分指针数组和数组指针
char *p[10]
: 大小为10的数组,数据项是指针char (*p)[10]
:*p
是指针,指向大小为10的数组
4.3. 野指针问题
若指针声明未初始化,且未被赋值,则指向的内存无法确定,即野指针 不要尝试访问野指针即可
⚠注意定义的时候赋值和语句赋值的区别:比如下面这道题:
(C13A) In the following code fragments, item ___
is correct.
A. int *p; scanf("%d", &p);
B. int *p; scanf("%d", p);
C. int k, *p=&k; scanf("%d", p);
D. int k, *p; *p=&k; scanf("%d", p);
注意C和D的区别!C是定义了一个新的变量
k
,并且让p
指向它,是合法的。 D中*p=&k
是不合法的(相当于将k
的地址写入p
指向的空间,还是进行了访问)
假设 scanf
语句执行时输入 ABCDE<回车>
,能使 puts(s)
语句正确输出 ABCDE
的程序段是 _____
A. char s[5] = {"ABCDE"}; puts(s);
B. char s[5] = {'A', 'B', 'C', 'D', 'E'}; puts(s);
C. char *s; scanf("%s", s); puts(s);
D. char *s; s="ABCDE"; puts(s);
答案是D,剩下都涉及野指针的访问。D的操作:1)声明指针 2)让指针指向一个字符串 3)输出,完全正确
4.4. 隐式转换问题
4.4.1 函数指针
原理:
任何函数指代器表达式,在用于异于下列语境时
- 作为取址运算符的操作数
- 作为
sizeof
的操作数
会经历到指向表达式所指代函数的指针的转换。
function(20);
(function)(20);
(*&function)(20);
(&function)(20);
(*function)(20);
(***********function)(20); // 不用数了,11 个
No.4: C语言允许通过函数指针来调用函数 √
No.5: function
作为取址运算符的操作数自动转化为function
指针,即&function
,这样再解引用,即function
本身,√
4.5 指针杂项:
int a[10]
之后a++
是错误的:数组名不可被赋值- (C15A/C16A) For the declarations:
char *s, str[10];
, statement ____ is completely correct. A. strcpy(s, "hello"); B. str="hello"+1 C. s=*&(str+1) D. s=str+1
A. 将 "hello" 拷贝到 s 指向的空间。但是 s 指向什么呢?你并不清楚,也就是说 s 是一个野指针,你不清楚它指向哪里,也就自然不能向它指向的空间中写入数据 B. str 是一个数组,数组名不能被赋值,所以是错的 C. str+1 不能被取地址,因为这是计算过程中的一个数,而不是实际存在内存中的数,所以是错的 D. str+1 表示的就是 str 数组中第二个元素的地址,将其赋值给 s,是正确的
- 定义了
char *a = "hello"
之后,表示a
作为字符指针指向了"hello"的开头,但是是只读的,是不可修改的
五. 奇怪表达式
以下代码语法正确的是_____
.
A. for ( ); B. do { } while ( ); C. while ( ) ; D. for ( ; ; ) ;
注意这道题考的是空表达式而不是循环语句。while 后的括号中必须有条件表达式,所以 BC 错误;for 后面的括号中必须有两个分号分割的三个语句,所以 A 错误。 D 是正确的,for( ; ; ) 就表示死循环,而后面的 ; 表示循环体为空,语法完全正确,是一个彻底的死循环。
六. 文件相关
记住相关函数!
-
打开文件:
if((fp = fopen("48","rb"))==NULL){ printf("Error!"); exit(0); }
-
关上文件:
考点:失败是if(fclose(fp)) { printf("Cannot close\n"); exit(0); }
1
,成功是0
,(C14) -
读取文件:
- 字符方式:
ch=fgetc(fp)
fputc(ch,fp)
- 格式化方式:
fscanf(文件指针,格式字符串,输入表)
fprintf(文件指针,格式字符串,输出表)
- 数据流
fread(数据所在的指针,sizeof(数据块),数据块数,文件指针fp)
- 字符方式:
七. 杂项
1. 设int i=0, j=9; char s[ ] = "happy new year!", *sp=s,*sq=s+9;
执行下列哪一条语句所得到的结果和其他三项不同_______
.
A.while ( i <= j ) s[i++]=s[j--]; |
B.for ( ; i<=j; ++i, --j ) s[i]=s[j]; |
---|---|
C.for ( ; sp++ <= sq--; ) *sp = *sq ; |
D.do { *sp=*sq; } while( sp++ < sq-- ); |
do-while
循环会执行一次,然后检查条件 sp < sq
。由于 sp
和 sq
初始时相等(都指向 s[0]
和 s[9]
),条件为 false
,循环不会执行任何操作,s
保持原样 "happy new year!"
。
- 函数可以嵌套调用但不能嵌套定义