[C陷阱和缺陷] 第5章 库函数】的更多相关文章

  有关库函数的使用,我们能给出的最好建议是尽量使用系统头文件,当然也可以自己造轮子,随个人喜好.本章将探讨某些常用的库函数,以及编程者在使用它们的过程中可能出错之处.   5.1 返回整数的getchar函数   我们首先考虑下面的例子: #include<stdio.h> int main() { char c; while( ( (c = getchar()) != EOF ) ) putchar(c); return 0; }   上面代码在某些情况下可能出错,原因在于变量 c 被声明…
有感自己的C语言在有些地方存在误区,所以重新仔细把"C陷阱和缺陷"翻出来看看,并写下这篇博客,用于读书总结以及日后方便自身复习. 第1章 词法"陷阱" 1.1 =不同与==   = 是赋值操作符,而 == 是作为比较操作符,初学者容易将 == 错写为 = ,这种情况下编译器不会报错,这就有可能造成很严重的后果,还不容易发现.比如下面这个例子: while( c=' ' || c=='\t' || c=='\n' ) { ; }   即使c既不等于'\t',也不等于'…
第3章 语义"陷阱"     一个句子哪怕其中的每个单词都拼写正确,而且语法也无懈可击,仍然可能有歧义或者并非书写者希望表达的意思.程序也有可能表面上是一个意思,而实际上的意思却相去甚远,本章考查了若干种可能引起上述歧义的程序书写方式. 3.1 指针与数组     C语言中指针与数组这两个概念之间的联系是如此密不可分,以至于如果不能理解其中一个概念,就不可能理解另一个概念.而且,C语言对这些概念的处理, 在某些方面与其它任何为人熟知的程序语言都不同.   C语言的数组值得注意的地方有以…
  C语言在许多不同的系统平台上都有实现.的确,使用C语言编写程序的一个首要原因就是,C程序能够方便地在不同的编程环境中移植.   不同的系统有不同的需求,因此我们应该能够预料到,机器不同则其上的C语言实现也由细微差别.今天,一个C程序员如果希望自己写的程序在另一个编程环境也能够工作,他就必须掌握许多这类细小的差别.本章要讨论的是关于可移植性的几个最常见的错误来源,重点放在语言的属性上,而不是在函数库的属性上.   7.1 标识符名称的限制   某些C语言实现把一个标识符中出现的所有字符都作为有…
第2章 语法陷阱 2.1 理解函数声明   当计算机启动时,硬件将调用首地址为0位置的子例程,为了模拟开机时的情形,必须设计出一个C语言,以显示调用该子例程,经过一段时间的思考,得出语句如下: ( *(void(*) () )0 ) ();   像这样的表达式看起来很难理解,但只要将其一层一层地剥离,还是能够理解的.下面我将用几个例子来帮助大家逐渐理解这个表达式. void *a(); void (*b) ();   因为()的优先级高于,所以a()为(a()),a是一个函数,该函数的返回类型为…
  在严格意义上的编译过程开始之前,C语言预处理器首先对程序代码作了必要的转换处理.因此,我们运行的程序实际上并不是我们所写的程序.预处理器使得编程者可以简化某些工作,它的重要性可以由两个主要的原因说明:   第一个原因是,我们也许会遇到这样的情况,需要将多个在程序中出现的所有实例统统加以修改.我们希望在程序中只改动一处数值,然后重新编译就可以实现.预处理器要做到这一点可以说是轻而易举(使用宏定义即可: #define N 1024).而且,预处理器还能够很容易地把所有常量定义都集中在一起,这样…
一个C程序可能是由多个分别编译的部分组成,这些不同部分通过连接器合并成一个整体.在本章中,我们将考查一个典型的连接器,注意它是如何对C程序进行处理的,从而归纳出一些由于连接器的特点而可能导致的错误. 4.1 什么是连接器     在C语言中,一个重要的思想就是分别编译,即若干个源程序可以在不同的时候单独进行编译,然后通过连接器整合到一起.但是连接器一般是与C编译器分离的,连接器如何做到把若干个C源程序合并成一个整体呢? 尽管连接器并不理解C语言,但它理解机器语言和内存布局.只要编译器将C源程序"…
第七章 1.null指针并不指向任何对象,所以只用于赋值和比较运算,其他使用目的都是非法的. 误用null指针的后果是未定义的,根据编译器各异. 有的编译器对内存位置0只读,有的可读写. 书中给出了一种判断编译器如何处理内存0的代码: #include <stdio.h> int main() { char *p; p=NULL; printf("location 0 contains: %d\n", *p); ; } 在禁止读内存0的机器上,程序会执行失败.有的机器上,却…
第一章 词法“陷阱” 1. =不同于== if(x = y) break; 实际上是将y赋给x,再检查x是否为0. 如果真的是这样预期,那么应该改为: if((x = y) != 0) break; 2. &和| 不同于 && 和 ||   3.词法分析中的“贪心法” 编译器将程序分解成符号的方法是:从左到有一个一个字符的读入,如果该字符可能组成一个符号,那么再读入下一个字符,判断已经读入的两个字符组成的字符床是否可能是一个符号的组成部分:如果可能,继续读入下一个字符,重复上述判断…
版权声明:本文为Focustc原创文章.转载请注明作者及出处. https://blog.csdn.net/caozhankui/article/details/35925939 看完<C陷阱与缺陷>,忍不住要又一次翻一下,记录一下与自己的惯性思维不符合的地方. 记录的是知识的增量.是这几天的流量,而不是存量. 这本书是在ASCI C/C89订制之前写的.有些地方有疏漏. 第一章 词法陷阱 1.3 C语言中解析符号时使用贪心策略,如x+++++y将被解析为x++ ++ +y.并编译出错. 1.…
下载地址:点我 凯尼格 (作者), 高巍 (译者) <C和C++经典著作:C陷阱与缺陷>适合有一定经验的C程序员阅读学习,即便你是C编程高手,<C和C++经典著作:C陷阱与缺陷>也应该成为你的案头必 备书籍.作者以自己1985年在Bell实验室时发表的一篇论文为基础,结合自己的工作经验扩展成为这本对C程序员具有珍贵价值的经典著作.写作<C和C++经典著作:C陷阱与缺陷>的出发点不是要批判C语言,而是要帮助C程序员绕过编程过程中的陷阱和障碍.<C和C++经典著作:C…
要参与C语言项目,于是作者只好重拾C语言(之前都是C++,还是C++方便). 看到大家都推荐看看  C陷阱与缺陷(C traps and pitfalls),于是好奇的开始了这本书的读书之旅. 决定将书中重要的知识点和易错点记录下来方便自己复习和他人学习~~不多说了,下面开始. 第一章:词法陷阱 在C语言中,符号(程序文字)之间的空白(包括空格符.制表符.换行符)将被忽略.书中举了一例: if (x > big) big = x; 可以写成: if ( x > big ) big = x ;…
这段时间把<C陷阱和缺陷>看了,没时间自己写总结.就转一下别人的学习笔记吧http://bbs.chinaunix.net/thread-749888-1-1.html Chapter 1 词法陷阱 程序中的单个字符孤立起来看并没有什么意义,只有结合上下文才有意义,如p->s = "->";两处的-意义是不同的. 程序的基本单元是token ,相当于自然语言中的单词. 一个token的意义是不会变的. 而组成token 的字符序列则随上下文的不同而改变. tok…
作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz 编译器中负责将程序分解为一个一个符号的部分,称为“词法分析器”.下面看一个例子: if(x > big) big = x; 这个语句的第一个符号是C语言的关键字if,紧接着下一个符号是左括号,再下一个符号是标识符x,再下一个是大于号,再下一个是标识符big,依次类推.在C语言中,符号之间的空白符将被忽略. 本章将探讨符号和组成符号的字符间的关系,以及有关符号含义的一些常见误解. 陷阱1 “=”不同于“==” 将相…
作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz 陷阱1 理解函数声明 作者提出一个问题:有一个首地址为0的函数,该函数返回值类型为void,没有参数.怎样用C语言的语句调用这个函数? 答案是(*(void  (*)())0)(); 要理解这个调用形式,要清楚如下两个问题: 一是函数指针. 假设fp是一个函数指针,则调用fp所指向的函数的方法是 (*fp)(); 因为fp是一个函数指针,所以*fp是该指针所指向的函数,所以(*fp)()就是调用该函数的方式.AN…
有关运算符优先级   1. "<<" 和 "+" data8 = data4H << 4 +data4L; 这里本意是让高四位的数据,左移四位,然后和低四位相加,但是因为 “+”的运算符优先级 高于 "<<",所以会导致如下的情况: data8 = data4H << (4 +data4L);                    int data8 = 0;                  in…
1. 使用 e1=e2的赋值方式 作为 条件语句内部的判断,请使用显示的判断 不使用: if( x =y ) foo(); 而使用: ) foo(); 2. 注意编码规范,一定要在赋值号 “=”两边,写上空格,以避免如下的 无意识错误. 本来想写成: a = -; 但是没有加空格: a=-; 这会被编译器翻译成:(这里猜测应该是很老的编译器才有这种解释,现在都是用 “+=”和“-=”运算符) a = a - ; 3.进制的表示 int a ; a = ; /*十进制*/ printf("a:%d…
1.= 与==的区别 赋值运算符= 的优先级要小于逻辑运算符== 也就是说,会进行先逻辑上的比较,然后再把比较结果进行赋值,很合理. getc库是什么??? 1.C语言中有单字符 = 也有多字符单元如:== C语言对这一问题的解决方案为:每个符号应该包含尽可能多的字符.即贪心法的处理策略 所以例如: a---b 与a --  -b 相同 与a- --b 不同 1.如果一个整型常量的第一个字符是数字0,那么该常量会被视作八进制数 如: 10与 010 的含义是不同的 0195的含义是 1* 8^2…
笔记: 第一章:词法陷阱 提倡显示比较if((x = y) != 0) foo(); 第二章:语法陷阱 已知一个类型的声明 该类型的类型转换:吧声明中的变量名和声明末尾的分号去掉,再将剩余的部分用括号整个“封装”起来即可 (*(void(*)())0); (void(*)()) 这是一个返回值为void的函数指针类型 typedef void (*funcptr)() 中 funcptr 等价于 (void(*)()) typedef void (*funcptr)(); //funcptr表示…
1. 词法“陷阱” = 不同于 == , 可以通过if( 1 == a )来避免 & | 不同于 && || 词法分析中的“贪心法” 编译器将程序分解成符号的方法是,从左到右一个字符一个字符地读入,如果该字符可能组成一个符号,那么再读入下一个字符,判断已经读入的两个字符组成的字符串是否可能是一个符号的组成部分:如果可能,继续读入下一个字符,重复上述判断,直到读入的字符组成的字符串已不再可能组成一个有意义的符号.这个处理策略被称为“贪心法”,也称为“大嘴法”.举例:a---b 等价于…
第三章 语义陷阱 3.1 指针与数组 C语言中只有一维数组,而且数组的大小必须字编译期就作为一个常数确定下来.数组中的元素可以是另外一个数组.任何一个数组下标运算都等同于一个对应的指针运算.int a[3];除了a被用作运算符sizeof的参数这一情形,在其它所有情形中数组名a都代表指向数组a中下标为0的元素的指针,sizeof(a)是整个数组a的大小.*a是数组a中下标为0的元素的引用,*(a+1)是数组中下标为1的元素的引用. 3.2 非数组的指针 在C语言中,字符串常量代表了一块包括字符串…
本文转自 https://www.xuebuyuan.com/1951579.html 自己找工作过程中复习过的书包括<C traps and Pitfalls>,<编程珠玑>,<编程之美>,<算法导论>,<Effective c++>,<c++ 沉思录>,另外的就是Linux我平时经常看的一些书了.所以这些书都是在我的书桌上,从来没有丢过.当然还有一本你永远都不可能撤下去的书叫做<深入理解计算机系统>,这个自然是不用提的…
第一章 词法"陷阱" 1.4整型常量 如果一个整型常量的第一个字符是数字0,那么该常量将被视作八进制数.因此,10与010的含义截然不同.需要注意这种情况,有时候在上下文为了格式>对齐的需要,可能无意中将十进制数写成了八进制数,例如: struct{ int part_number; char *description; }parttab[] = { 046, "left-handen widget" , 047, "right-handed wid…
第二章 语法陷阱 2.1 理解函数声明 (*(void(*)())0)();任何C变量的声明都由两部分组成:类型以及一组类似表达式的声明符.一旦我们知道了如何声明一个给定类型的变量,那么该类型的类型转换符只需要添加一个括号即可的到.例如 float (*h)();表示h是一个指向返回值为浮点类型的函数的指针.因此(float (*h)())表示一个"指向返回值为浮点类型的函数的指针"的类型转换符. 第一步假设fp是一个函数指针,那么通过(*fp)()调用fp所指向的函数,可以简写问fp…
第一章 词法陷阱 术语“符号”指的是程序的一个基本组成单元,其作用相当于一个句子中的单词.编译器中负责将程序分解为一个一个符号的部分,一般称为“词法分析器”. 1.1 =不同于== 一般容易将比较运算误写成赋值运算的情形,另一方面,如果把赋值运算误写成比较运算,同样会造成混淆:if((filedesc==open(argv[i],0))<0)error(); 在本例中,如果函数open执行成功,则返回0或者正数:而如果函数open执行失败,将返回-1.上面这段代码的本意是将函数open的返回值存…
本文关注的主要是python陷阱,具体而言,是指CPython,而且除非特别说明,所有代码示例都是在python2.7运行的. 我个人对陷阱的定义是这样的:代码看起来可以工作,但不是以你“想当然“”的方式.如果一段代码直接出错,抛出了异常,我不认为这是陷阱.比如,Python程序员应该都遇到过的“UnboundLocalError", 示例: >>> a=1 >>> def func(): ...     a+=1 ...     print a ... &g…
2.1理解函数声明 这一章仔细分析了(*(void(*)())0)();这条语句的含义,并且提到了typedef的一种函数指针类型定义的用法. 我们经常用到的typedef用法是用于指定结构体的类型,比如单链表的结点经常这么定义 typedef struct { int data; struct node *next; } Node; 实质上是给struct给了一个别名叫做Node,之后在使用时就只需要用Node这个类型名即可,与int.float等内置类型名用法完全一致. 但在函数指针这里用法…
前言和导读 "得心应手的工具在初学时的困难程度往往超过那些easy上手的工具."比較认同这句话. 我至今认为自己事实上还是个刚入了门的刚開始学习的人. 第一章 "词法"陷阱 因为之前学过编译原理,对编译器词法分析(主要是符号识别过程)比較了解,理解起来不困难. 在讲到"="和"=="."|"和"||"."&"和"&&"时,联…
导读 程序是由符号(token)序列所组成的,将程序分解成符号的过程,成为"词法分析". 符号构成更大的单元--语句和声明,语法细节最终决定了语义. 词法陷阱 符号(token)指的是程序的一个基本组成单元,其作用相当于一个句子中的单词. 编译器中负责将程序分解为一个一个符号的部分,称作"词法分析器". 在C语言中,符号之间的空白(/b /t /n...)将被忽略. #include <stdio.h> int main() { if ( 1 ) pri…
词法分析: 编译器将程序分解成符号的方法是 从左到右一个一个字符的读入,如果该字符可能组成一个符号,再读入下一个字符 而c语言里的符号 / * =只有一个字符长, 是单字符的, /* == 一些事双字符符号. 故因此有以下陷阱 a---b     等价     a-- -b y= x/*p      /*被编译器理解成一段注释的开始 因此应该写成y = x / *p 或者 y = x/(*p) 整型常量 : 如果一个整形常量的第一个字符是数字0 那么该常量将被视作八进制,有时候在上下文中为了格式…