万千只cnm 发表于 2021-8-6 20:28:48

c陷阱与易错点(持续更新

本帖最后由 万千只cnm 于 2021-8-6 20:28 编辑

                本帖主要收集/记录一些c语言编程过程当中         容易疏忽出错的地方 ,以及一些特性{:9_228:}

               欢迎大家捧场

万千只cnm 发表于 2021-8-6 20:28:49

本帖最后由 万千只cnm 于 2021-9-7 11:28 编辑

1.c语言中,符号之间的空白(空格符,制表,换行符)将被忽略

2.= 不同于 ==
      判断时可能无意写成赋值运算符:
if(a = b)      // 错误

3.应该进行显示的比较:更能表示意图
if(x = y)
    ...

改为
if( (x=y) != 0 )
...
4 词法分析当中的“贪心法则”:
       每一个符号应当尽可能包含更多的符号,直到非法为止

a---b 监测到两个 -- 后 ---非法-->相当于 (a--)- b

5. 整型常量的第一个数字如果是数字0 ,会被认为是八进制数

6.单个字符是整型
int *p = '\' ;   错p是指针变量,而右边是整型

7. 复合赋值只运算一次

mango +=y ;
等价于:
mango= mango +y;
I++;
而不是:
mango= mango +y;

8. 有符号数 不等价于 具有负号
无符号数的本质特性是 永远不会是负的
有符号数的本质特征是 对最左边的一个位进行取补会改变它的符号

9.scanf函数参数列表都应该是个指针(地址)

如整型就应该取地址&

10.声明符 转化为表达式,对其求值应该返回一个声明中给定类型的结果
如:
float f,g;
那么
g;
f;
表达式的值就是一个浮点数

11.声明--> 强制转换
   a.把声明中变量名和分号去掉
   b.对剩下部分整体加一个括号
如:
float(*h)();// 声明一个函数指针
12. “bool”操作符 优先级大于 逻辑(与/或..) 大于赋值 运算符如:
if (ch = getchar() =='a' )       //错 原意是先赋值给ch 然后就行比较
...

应改成:
if ( (ch = getchar() ) =='a' )
13. 函数若如无原型或定义 ,函数默认返回整型 14. switch若无break 会自然而然的顺序执行下去    switch语句只会从第一个case处进入,不能在其内部定义语句等;
15. 函数调用时,即使函数不带参数,也应该包括参数列表()

fun(); //对
fun; // 只计算函数fun的地址然后丢弃,并无调用
16. else 始终与同一对括号内最近的未匹配的if结合

17. 不要在一行代码里实现太多功能:       这种做法并不能使编译器产生的代码更有效率,而且会使你丧失调试代码的机会

18. c语言中数组可以看成一维数组,只不过数组内元素可以是任何类型对象
19.对于一个数组,我们只能做两件事:
      a. 确定数组的大小
      b. 获得指向该数组下标为0元素的指针

20. 当数组作为参数传递时,会被转化为指向元素类型的指针

21.不能对 NULL指针解引用 ,误用NULL指针效果都是未定义的

22. 边界对称 (下标)
      for(I = 0; I<10;i++)         0是入界点,在下标范围之内 ; 10是出界点,但不在范围之内;不对称
for(I = 0; I<=9; i++)对称

23. 关于循环次数问题:
       a. 可以用特例外推法 和 仔细检查边界
如:
for( k =10; --k>= 0 ;)
...假设 k等于0 --k 不符合 --》 k=1循环一次 --〉外推
一共循环十次

24. 运算符 && 和 || 首先对左侧的操作数求值,需要时再执行右操作数 (会断路)

25. 当一个运算的结果发生“溢出”时, 做出任何假设都是不安全的

26. extern关键字 :应保证一个特定名称的所有外部定义在每个目标模块中都有相同的类型
       a. 显示的说明了储存空间是在程序的其他地方分配的
       b. 是一个对外部变量的引用,而不是对其的定义

如把 数组 extern成指针,就很危险

27. 每个外部变量(全局变量) 只能定义一次

28.static不仅适用于变量 ,也适用于函数

29. 库函数里有的函数,不去使用它们就愚不可及(别自己写
      
30.getchar接受字符时, 应将 char 声明为 int

char c ;

while ( (c = getchar() ) !=EOF )
... 如果定义为char,可能无法容下EOF导致提前截断 或 永远停止不了
31. 一个输入操作不能随后直接紧跟一个输出操作,反之依然 。必须在其中加入fseek函数的调用

32. 当发生信号中断时,调用任何系统函数行为都是未定义的

33. 宏定义时应该都加上括号 ,防止展开时发生错误

34. 替代类型时 最好用typedef “封装” 而不是用#define   

35. ANSI C标准中 c实现必须能区分出前6个字符不同的外部名称,而且这个定义中并没有区分大小写

36. 有符号数整数的向右移位运算也并不等同于除以2的某次幂

37. 负数除法运算时取模可能有不同的结果

38. 单纯将负数变正可能会溢出
如: 负能表示- 2的k次方 而正只能表示2的k次方-1

39. 不要觉得程序能运行就万事大吉,这种工作方式最后往往会导致灾难

40. 可以预防性编写代码
如:
while('\t' == c || ' ' == c )
...讲变量写在比较右边, 当 == 误写为 = 时能立马发现错误,而不是巧合运行

41.
常量指针(const pointer) : 指针本身不可以修改(指向
指向常量的指针( pointer to const) : 指向的对象不可以修改

42. typedef 封装时 :

   typedef char *pstring;

const pstring str = NULL ;


const 限定的是封装的类型 即 指针
而不是像展开一样 : const char * str = NULL;

--》str是常量指针 属于顶层对象,自身不能改变

43.声明时 * 只从属于某个标识符(变量名)而非基本数据类型的一部分
       限定符 const等 属于基本数据类型的一部分,而不是只属于某个标识符

44. 避免在 case语句后声明变量





Max472 发表于 2021-8-6 23:11:45

万千只cnm 发表于 2021-8-6 20:28
1.c语言中,符号之间的空白(空格符,制表,换行符)将被忽略

2.= 不同于 ==


最后一个不应该是字符型 char 吗?
你咋说整型?

人造人 发表于 2021-8-6 23:25:08

Max472 发表于 2021-8-6 23:11
最后一个不应该是字符型 char 吗?
你咋说整型?

单个字符就是一个整数
int a = '0';
int a = 0x30;
int a = 48;
这 3 个是一回事

参考 https://fishc.com.cn/thread-67427-1-1.html

Max472 发表于 2021-8-6 23:29:54

人造人 发表于 2021-8-6 23:25
单个字符就是一个整数
int a = '0';
int a = 0x30;



int a = '0'

这不是强制类型转换吗

人造人 发表于 2021-8-6 23:31:25

Max472 发表于 2021-8-6 23:29
int a = '0'

这不是强制类型转换吗

不是
这样才是强制类型转换
int a = (int)'0';

人造人 发表于 2021-8-6 23:32:28

Max472 发表于 2021-8-6 23:29
int a = '0'

这不是强制类型转换吗

#include <stdio.h>

int main(void) {
    printf("%d\n", '0');
    return 0;
}

Max472 发表于 2021-8-7 08:54:18

人造人 发表于 2021-8-6 23:31
不是
这样才是强制类型转换
int a = (int)'0';

int a = '0';    隐式强制转换
int a = (int)'0';   显式强制转换

万千只cnm 发表于 2021-8-7 13:27:01

本帖最后由 万千只cnm 于 2021-8-7 13:33 编辑

有人吗{:5_101:}

jhq999 发表于 2021-8-13 06:45:26

本帖最后由 jhq999 于 2021-8-13 06:50 编辑

关于2.“==”要养成数值在前变量在后的习惯,比如i=0,1==i没毛病,而1=i会报错

万千只cnm 发表于 2021-8-13 18:38:46

jhq999 发表于 2021-8-13 06:45
关于2.“==”要养成数值在前变量在后的习惯,比如i=0,1==i没毛病,而1=i会报错

对的
页: [1]
查看完整版本: c陷阱与易错点(持续更新