C语言易错点总结

  1. 所有的注释都会被预处理器用空格进行替换,因此注释可以出现在任何空格可以出现的地方。
  2. 除了数组名被用作运算符sizeof的参数这一情况,其他所有情形代表指向数组中下标为0的元素的指针。
  3. C语言使用=作为赋值运算符,==作为比较运算符的原因是赋值在代码中更常见,这样可以减少代码长度
  4. C编译器将程序分解成符号的方法是贪心法
  5. 除了字符串和字符常量,符号的中间不能嵌有空白(空格符,制表符和换行符)
  6. 用单引号括起一个字符代表一个整数,用双引号括起一个字符代表一个指向无名数组起始字符的指针
  7. ‘abc’在vs中保存的最后一个字符,前面的被覆盖
  8. (a++)++表达式报错,自增和自减操作符的操作数必须是一个“左值”,而a++的结果是“右值”。
  9. 只有4种操作符的结果是“左值”,分别是[], ., ->, *
  10. 运算符的优先级:[],(),->,.最高,其次是单目运算符,接着是算术>移位>关系>逻辑>赋值>条件(?:),最后是逗号,只有单目、三目和赋值运算符是自右向左结合的
  11. 注意悬挂else
  12. 如果f是一个函数名,则f;语句计算函数f的地址,却不调用
  13. 在java和Python中,一个语句要么按照我们的预期正确执行,要么立即抛出异常,但在C++中还有一种情况是逻辑上出错了,C++标准却没有规定怎么处理。
  14. C语言中只有四个运算符(&&、||、?:和,)存在规定的求值顺序,其他所有运算符对其操作数求值的顺序是未定义的。逗号运算符先对左侧操作数求值,“丢弃”后再对右侧操作数求值。
  15. 分隔函数参数的逗号并非逗号运算符,所以在f(x,y)中的x,y的求值顺序是未定义的,而在g((x,y))中则是先对x求值,在对y求值,函数g只有一个参数
  16. 按位运算符(&、|、~)和逻辑运算符(&&、||、!)某些时候可以互换,不过只是因为巧合
  17. 函数main的返回值告知操作系统该函数的执行是成功还是失败,典型的处理方案是返回值为0表示执行成功,非0为失败
  18. 当两个操作数都是有符号整数时,“溢出”就可能发生,“溢出”的结果是未定义的。正确做法是强制转换为无符号整数或者将加法转换为减法
  19. 如果p是一个空指针,则printf(“%s”,p);的行为是未定义的。
  20. 数组下标从0开始和不对称边界是对程序设计的简化
  21. 一个返回值为整型的函数如果返回失败,实际上是隐含地返回了某个“垃圾”整数,只要该值不被用到,就无关紧要
  22. 如果一个未声明的标识符后跟一个开括号,那么它将被视为一个返回整型的函数
  23. 每个外部对象都必须在程序某个地方进行定义。如果一个程序中包括了语句extern int a;那么这个程序必须在别的某个地方包括int a;这个两个语句既可以位于同一个源文件中,也可以位于不同源文件中
  24. 如果一个程序对同一个外部变量的定义不止一次,结果是未定义的。例如:int a=1;出现在一个文件中,而int a=2;出现在另一个文件中,结果与系统有关。如果一个外部变量在多个源文件中定义却并没有指定初始值,那么某些系统会接受,另一些系统则不会接受。唯一的解决办法就是每个外部变量只定义一次。
  25. 如果在一个文件中定义char filename[] = “hello”,而在另一个文件中声明extern char* filename;在打印filename时,程序将不能正常工作
  26. 为了避免可能出现的命名冲突,如果一个函数仅仅被同一个源文件中的其他函数调用,则应该用static声明该函数
  27. getchar()返回类型为int(因为EOF是int类型),如果定义一个char类型变量接收,则程序可能不能正常工作
  28. 为了保持与过去不能同时进行文件读写操作的程序的向下兼容性,一个输入操作不能随后紧跟一个输出操作,反之亦然。如果要同时操作的话,必须在中间插入fseek函数的调用,其作用是改变文件状态
  29. C语言中仅有4种基本数据类型——整型、浮点型、指针和聚合类型(数组和结构等)
  30. 整型家族包括字符、短整型、整型和长整型,分为有符号和无符号两种。长整型至少应该和整型一样长,而整型至少应该和短整型一样长。
  31. Literal有时译为字面值,有时译为常量,它们含义相同,只是表达习惯不一。其中,string literal和char literal分别译为字符串常量和字符常量,其他的literal一般译为字面值
  32. 对于使用不同字符集的系统,使用字符常量可以提高程序的可移植性
  33. 枚举类型就是指它的值为符号常量而不是字面值的类型,其变量用整型存储
  34. 所有字符和NUL终止符都存储于内存的某个位置,具有相同的值的不同字符串在内存中是分开存储的。ANSIC声明如果对一个字符串常量进行修改,结果是未定义的
  35. 链接属性一共有3种——external(外部),internal(内部)和none(无),没有链接属性的标识符(none)总是被当做单独的个体,也就是说该标识符的多个声明被当做独立不同的实体
  36. 如果extern用于同一标识符的第2次或以后的声明时,不会更改由第一次声明所指定的链接属性
  37. 函数的形式参数不能声明为静态,因为实参总是在堆栈中传递给函数,用于支持递归
  38. 由于寄存器值的保存和恢复,某个特定的寄存器在不同的时刻所保存的值不一定相同,所以机器不提供寄存器变量的地址
  39. 由于显示的初始化将在代码块的起始处插入一条隐式的赋值语句,因此在声明变量的同时进行初始化和先声明后赋值只有风格只差,并无效率之别
  40. C语言不存在专门的“赋值语句”,赋值是一种操作,在表达式内进行
  41. 一个程序如果使用了有符号数的右移位操作,则不可移植
  42. 自增和自减操作符要求操作数必须是一个“左值”,因为操作符的结果是变量值的拷贝
  43. 逗号表达式自左至右逐个进行求值,整个表达式的值就是最后那个表达式的值
  44. 间接访问和下标引用的结果是个左值,其余操作符的结果则是右值
  45. 整型算术运算总是至少以缺省整型类型的精度来进行的,所以字符型和短整型操作数在使用之前被转换为普通整型,这种转换称为整型提升
  46. 把函数调用以操作符的方式实现意味着“表达式”可以代替“常量”作为函数名
  47. 变量名与内存位置之间的关联并不是硬件提供的,而是编译器实现的,变量名使得我们更方便记住地址,然而硬件仍然通过地址访问内存位置
  48. 不能简单地通过检查一个值的位来判断它的类型,必须观察程序中这个值的使用方式,值的类型并非值本身所固有的一种特性,而是取决于它的使用方式
  49. 机器内部NULL指针的实际值不一定是零值,编译器负责零值和内部值之间的翻译转换
  50. 对一个NULL指针进行间接访问,结果是未定义的
  51. 在表达式两端加上括号总是合法的
  52. 当程序调用一个无法见到原型的函数时,编译器认为该函数返回一个整型值
  53. 一个没有参数的函数的原型应该声明为“int *func(void);”而不是“int *func();”,后者表示只给出func函数的返回类型,目的是为了保持与ANSI标准之前的程序的兼容性
  54. 阅读递归函数最容易的方法不是纠缠于它的执行过程,而是相信递归函数会顺利完成它的任务。如果你的每个步骤正确无误,你的限制条件设置正确,并且每次调用之后更接近限制条件,递归函数总是能够正确地完成任务。
  55. Strcmp函数的返回值不应当作布尔值测试,也不应与1和-1进行比较
  56. 具有相同成员列表的结构声明产生不同类型的变量
  57. union变量可以被初始化,但初始值必须是union第一个成员的类型,而且它必须位于一对花括号里面
  58. 在许多机器中,可以把函数参数声明为寄存器变量,进一步提高指针传递的效率
  59. 常见的动态内存错误:对NULL指针进行解引用操作、对分配的内存进行操作时越过边界、释放非动态分配的内存、试图释放一块动态分配的内存的一部分以及一块动态内存被释放之后继续使用
  60. 不要仅仅根据代码的大小评估它的质量
  61. #progma是不可移植的,预处理器忽略它不认识的#progma指令,两个不同的编译器可能以两种不同的方式解释同一条#progma指令
  62. 不要在一个宏定义的末尾加上分号,使其成为一条完整的语句
  63. 标准输入是缺省的输入设置,标准输出是缺省的输出设置,具体的缺省值因编译器而异。标准错误就是错误信息写入的地方,为错误信息准备一个不同的流意味着,即使标准输出重定向到其他地方,错误信息仍将出现在屏幕或其他缺省的输出设备上
  64. 对于输出流,fclose函数在文件关闭之前刷新缓冲区
  65. 环境就是一个由编译器定义的名字/值对的列表,由操作系统维护
  66. 当exit函数被调用时,所有被atexit函数注册为退出函数的函数将按照它们注册的顺序被反序依次调用
  67. System函数把它的字符串参数传递给宿主操作系统,作为一条命令,由系统的命令处理器执行
  68. 使用断言检查内存是否分配成功是危险的
  69. 使用断言来防止非法操作,可以简化程序的调试
  70. Assert是一个宏,只适用于验证必须为真的表达式
  71. 迭代比尾部递归效率更高
  72. 局部变量声明和函数原型并不会产生任何汇编代码,但如果局部变量在声明时进行了初始化,就会出现指令用于执行赋值操作
  73. 是链接器而不是编译器决定外部标识符的最大长度
  74. 无法链接由不同编译器产生的程序
  75. 对信号进行处理将导致程序的可移植性变差
  76. 函数longjmp不能返回到一个已经不再处于活动状态的函数
  77. 函数clock可能只产生处理器时间的近似值
  78. 从异步信号的处理函数中调用exit或abort函数是不安全的
  79. 当每次信号发生时,必须重新设置信号处理函数
  80. 避免exit函数的多重调用
  81. 打印长整数时,使用l修饰符可以提高可移植性
  82. 不要忘了在一条调试用的printf语句后面跟一个fflush调用
  83. 改变文件的位置将丢弃任何被退回到流的字符
  84. 如果流当前处于文件尾,feof函数返回真。这个状态可以通过对流执行fseek、rewind或fsetpos函数来清除
  85. 在宿主式运行时环境中,操作系统可能执行自己的缓冲方式,不依赖于流
  86. 以#符号开头,后面不跟任何内容的一行,这条指令是无效指令,被预处理器简单地删除
  87. “xyz”+1表达式的结果是指针,指向字符串中的第2个字符:y
  88. *”xyz”表达式的结果是x,”xyz”[2]的结果是z
  89. cdecl程序可以帮助你分析复杂的声明

 

 

 

 

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值