副标题: -
作者: Brian W. Kernighan / Dennis M. Ritchie
译者: - / -
出版社: Prentice Hall
出版年: 1989-03-01
页数: 274
定价: $48.67
装帧: Paperback
ISBN: 9780131103627
作者: Brian W. Kernighan / Dennis M. Ritchie
译者: - / -
出版社: Prentice Hall
出版年: 1989-03-01
页数: 274
定价: $48.67
装帧: Paperback
ISBN: 9780131103627
内容简介 · · · · · ·
-
作者简介 · · · · · ·
-
豆瓣成员常用的标签(共130个) · · · · · ·
喜欢读"C Programming Language"的人也喜欢 · · · · · ·
按有用程度 按页码先后 最新笔记
-
1-6
faithprice (必须强人所难)
C语言是所有语言的基础。我就从这里开始吧。 Chapter 1 最简单的C程序就是打印"Hello World!".文件头引用程序中要使用的printf函数所在的库文件stdio.h: #include <stdio.h>.每个C程序都要有个主干,用main开头,后面的()大概是用于括返回值,{}中间写程序语句。printf输出字符串要用""括起来。C源码写完存好,在字符界面cc之,如果程序没错,gcc会生成一个a.out,执行a.out,就可以看到结果。逗号在p... (更多)C语言是所有语言的基础。我就从这里开始吧。Chapter 1最简单的C程序就是打印"Hello World!".文件头引用程序中要使用的printf函数所在的库文件stdio.h: #include <stdio.h>.每个C程序都要有个主干,用main开头,后面的()大概是用于括返回值,{}中间写程序语句。printf输出字符串要用""括起来。C源码写完存好,在字符界面cc之,如果程序没错,gcc会生成一个a.out,执行a.out,就可以看到结果。逗号在printf输出的字符串里可以直接写,但是换行符需用\n表示,类似的\t表示制表符,\b表示backspace,\"表示",\\表示\。C的数据类型包括int short long,分别表示整型,短整型,长整型。变量声明的格式是int counter; 声明用分号;结尾,事实上所有语句都用分号结尾。while的格式:while后跟一对括号,括号里包含一个逻辑表达式,逻辑表达式的值为真则执行while所管的语句,执行一遍后再来检查此表达式,若为真则再执行,否则结束while语句,执行下一条。另一种结束while语句的方法是写break; while的特点是至少执行一次,另一个循环语句for可能一次都不执行。char float也是数据类型。char用于单个字符,float用于浮点数,即非整数。加减乘除分别是+-*/,需要注意的是/。若a,b都是整数类型,则a/b的结果是整数除法的结果,砍掉了余数,所以如要获得浮点数结果,则须强制类型转换。继续说printf:有时需要输出的不只是一个字符串,还需要把变量的值打印出来,这时就需要通配符。类似于printf("%d",counter);就会打印出counter这个整型变量的值,若有多个通配符,则后面以逗号分隔开的变量挨个对号入座。还可以规定输出变量值所占的位置,比如%6d就是占6个字符位置,%f用于float变量,%6.2f指用6格打印此变量,2格的小数位。%s是字符串。for的用法:for(expr1;expr2;expr3) expr1通常用于给控制循环的变量赋初值,expr2通常是个逻辑表达式,用于设定循环结束的边界条件,expr3通常用于改变控制变量的值。这三个expr都可以为空,只是要保证循环有限步后会结束。逻辑表达式的值为布尔型,只有0,1两个值。0代表假,1代表真。所有非零的数作为逻辑表达式值都是1.因此逻辑表达式可以是一个数值表达式,不一定是个逻辑判断。这提供了相当的灵活性。注意赋值和逻辑判断的区别:=用于赋值,==用于逻辑判断。后面将学到的字符的位操作也有类似的混淆可能,&是位的与操作,&&是两个逻辑表达式的并运算。为了调试和扩展的需要,也为了程序的易读性,通常不在程序里直接使用常数值,而是在程序头做常量声明,格式是:#define SUP 255 注意没有分号结尾。注释的用法:C语言中用/*和*/把注释括起来,也是为了易读性(readability)。Bear in mind,程序是拿来给人读的。大小关系判断符号:大于>,小于<,不大于<=,不小于>=,等于==,不等于!=。逻辑关系判断符号:并且&&,或者||,计算时从左至右,且得值即止。getchar()和putchar(),是读入和输出函数。假设c是一个char变量。c=getchar();把读入的字符赋给c,putchar(c);把c打印出来。EOF是一个特殊的char值,为-1,用于标记文件尾。char的取值范围是0-255,一个byte的范围。运算的优先级:赋值运算的优先级高于比较运算,因此c=getchar()!=EOF的意思是读入一个字符赋给c然后c跟EOF比较。++,--,+=,-=,*=,/=这些运算符。a++是先取a的值再加1,++a是先给a加1再取a的值。a+=1等价于a=a+1,这种运算比较紧凑,且易读性强。条件语句:C语言没有if then else,直接是 if expression statement1; else statement2;。expression的值为真则执行statement1,否则执行statement2. eles语句可无。if else可以嵌套,配对原则是else跟最近的if配,为免混淆和易读性,做好缩进和{}。字符用''括起来,不要跟字符串搞混了。'a'和"a"是不同的。函数:构成函数的要件是输入和输出,输入和输出都要声明数据类型,用return语句在函数体内给出输出。函数头的例子 int power(int base, int n)。其中的base和int不是必须的,只是为了易读性。完全可以写成int power(int,int)。不需要返回值的函数声明为void,例如 void copy(char to[],char from[])。int是default return type,可以省略。In C, we call by value. 意思是我们对call过来的是个local copy,不改变原值。这样的设置减少了很多出错的可能性,也可使程序更简洁。这是对变量,对数组就不是这样了。字符串的结尾隐藏着一个\0,作为“字符串在这里结束”的信号。缺省地,每个变量都local于声明它的函数,它的值不会保留,函数被call,then exit后它就被释放了,所以每次用它必须先初始化,否则它的值就是乱的。想使用一直存在的变量可以采用外部变量(external variable),外部变量必须在所有函数(包括main)的外面声明一次,若要在函数内部使用此外部变量,则必须在函数里前面加个extern声明之。除非绝对必要,不要使用外部变量,因为我不知道什么时候它就变化了,且使用外部变量不利于程序的万用性。Chapter 2变量的命名规则:变量名的首位可以用字母或下划线,但不推荐用下划线,因为库函数的名字常以下划线开头。变量名内部可以用字母,下划线和数字。变量名是大小写敏感的。有些词C语言已经占用了,不可以用于做变量名,例如if,else,int,float。应尽可能给变量起与它的作用相关的名,局部变量起短名,外部变量起长名。unsigned和signed,若char为8 bits,则unsigned char的取值范围是0到255,signed char的取值范围是-128到127。double是float的扩展数据类型,比float精度更高。float,double,long double三者的关系类似于short int,int,long int的关系。<limit.h>和<float.h>包含着数据类型的界数据。如何得知这些数据类型的范围?先定义一个unsigned int整数,赋值为0,然后减去1,由所得可知其范围,也可知其范围大小,由此可算出signed int的范围,其它数据类型的值域可用同样的方法求得。常数:以l或L结尾的整数为长整型,无符号数以u或U结尾,无符号长整型以ul或UL结尾,浮点数以f或F结尾,双精度浮点数以l或L结尾。八进制整数以0开头,16进制整数以0x或0X开头,非十进制整数也可加后缀L或U。字母字符和有些非字母字符可以直接括在''里表示,有些叫escape sequence的则不能。他们包括:\a alert, \\ 右斜杠, \b 退格, \? 问号,\f formfeed, \' 单引号, \n 换行, \" 双引号,\r carriage return, \ooo 八进制数, \xhh 十六进制数, \v 垂直tab, \t 水平tab. '\0'代表以0为值的字符。注意,一般地,'\x'代表以x为值的字符。任意字符串必须以不可见的'\0'结尾。标准库函数strlen(s)返回字符串s的长度(不包括尾部那个'\0')。strlen和其它字符串函数在<string.h>中。另一种表示常量的方式是枚举,例子:enum family {father=1,mother,son,daughter}; 其中mother会被自动赋值为2,son被赋值为3,注意枚举语句不像#define,它需要以分号结尾。枚举列表中的名字必须两两不同,但值不必。所有的变量必须在使用前声明。对于不想被改变的变量可在声明时前面加const后面赋值。例如: const double e=2.7182845905;&&和||第一章提过了,这里再强调一下它们的得值即止功能。他们是从左往右计算的,一旦算到足够决定他们值的地方,就不接着往右算了,这可以用于更灵活地写代码。不同数据类型的变量若在一个表达式里,会自动将数据范围小者转换为数据范围大者再进行运算。例如:int转为long, float转为double。C语言还提供了强制转换,只要在需转换的变量前写(类型名)即可。若将数值范围大的量赋给数值范围小的类型量,则会丢失数据。自加和自减运算符:只能用于变量,不可用于表达式,即a++可以,(a+b)++不可以。用此运算符常可简化程序。位运算:& 按位与, | 按位或,^按位异或,<<左移,>>右移,~按位补。&可以用mask数取截出一段。左右移空出来的位用0补(对于unsinged)。注意位运算与逻辑运算的区别。赋值运算符:expr1 op=expr2等价于expr1=expr1 op expr2。<ctype.h>提供了一族无关于字符集的测试和转化函数。例如isdigit()。<math.h>提供了一些常见数学函数。例如sqrt()。条件表达式:expr1 ? expr2 : expr3.其意义是若expr1为真,则执行expr2,否则执行expr3。用它可使程序更紧凑。运算优先度列表,用tab分组:() [] ->! ~ ++ -- + - *(type) sizeof* / %+ -<< >>< <= > >=== !=&^ |&&||?:= += -= *= /= &= ^= |= <<= >>=, 一元运算符& + - * 比同个模样的二元运算符优先级高。Chapter 3本章的名字叫control flow,应是详解各语句的用法。一般的语句以分号结尾。{}可以当作一个语句看,不需要再加分号做结尾。switch (expr) {case const-expr: statementscase const-expr: statementsdefault: statements} 这是switch语句的格式。特别注意不同case可以共用statements,只要冒号后面继续跟case就可以。运算符逗号,常见于for的()里,被逗号分隔开的两个表达式从左往右计算,计算结果的类型和数值是最右边的那个表达式的类型和数值。逗号运算符不要多用,若非逻辑上紧密相连的表达式,不要往一起连。do-while: dostatementwhile(expression);即statement至少执行一次。想速度从循环中跳出时用break,注意一个break能且只能跳出一层循环。这与return不同,return直接终止函数体的运行。continue:只用于for,while中,效果是这次循环到此结束,直接执行下一次循环。goto的用法: go label;......label:除非绝对必要,别用goto。Chapter 4本章的标题是:函数和程序结构。我们大概都听说过。好的程序结构是自顶向下的。一个由多个独立的小结构组合成的大结构更稳定,更容易维护,其中的小结构也容易用在别处。在函数声明和定义处言明所用参数的类型是个好习惯,call此函数时可自动做强制类型转换以避免出错。若函数预料之外地无返回值,很可能什么地方搞砸了,去看看。函数声明时的返回值和call它时期待的返回值必须统一,否则会出错。C语言中不允许在函数内定义函数。cc命令可以同时编译数个C语言源文件(*.c),若某个源文件编译出错,修改后可再将此源文件(*.c)与其它已编译通过的对象文件(*.o)一起编译。所有的函数和函数参数若在遇到定义前就遇到引用,默认其返回值和参数均为int类型。如果函数有参数,声明它们的类型,如果没有,用void。automatic variables是生活在函数内部的,call结束即释放,不保留值。external variables可以在函数之间传递参数,但也有可能造成意料之外的改动。编程作为工程的精神是:尽量让每一部分都只知道(可access)它必须知道的部分,其它的互相之间都隐藏起来。scope:即一个对象的有效范围。automatic variables的scope是定义它的函数内。external variable和函数的scope是从声明它开始到所编译的文件结束。如果一个external variable在定义之前就被引用,或它在一个不同于定义它的文件中被使用,则必须用extern来定义它。习惯上把所有函数和外部变量一起在头文件(header file)里声明了,起名*.h。static variables: 一个变量既需要在某些函数间使用,又不希望别的函数知道它,可以把前者那些函数写在一个文件里,在此变量声明前加static和external即可。函数也可声明为static,这样函数所在文件之外就不能call它了。static也可用在内部变量上,它也像automatic variables只存在于特定函数内,但不同的是它保有storage,函数call完值还在。寄存器变量(register variables):只能将automatic variables和函数的形式参数声明为寄存器变量,可能可以加快程序运行速度。块结构(block structure):函数不能在块结构中嵌套,但变量可以在块结构中声明,且scope限于那个块。一对{}(compound statement)即可构成一个块。若在块中有与external variable同名的变量则其类型以块中的为准,但通常不建议使用重名变量。初始化:如无显明初始化,external和static变量自动获得0初值,automatic和register变量自动获得垃圾初值。若赋初值,则external和static的必须是常数形式的初值,automatic和register的可以是由其它变量算出来的数值赋给它,甚或是函数返回值。数组的初始化:可以把{}中用逗号隔开的数依序赋给数组元素。若数组大小未指定,则编译器会自动按所赋值个数确定,若所赋值个数大于指定大小则报错,若小于则剩下的初始化为0.字符数组可以{}地赋值,也可以直接把字符串"***"赋给它,{'a','\0'}等价于"a"。C中的函数可以迭代使用。允许迭代可以使函数比较容易写和看懂。但是定要小心处理迭代到trivial时的状态。C的预处理:#include"" 和#include<>都可以使编译时直接把别的文件的内容拿过来代替这一行。被include的文件若修改了,所有include它的文件都要重新编译。宏的格式:#define name replacement text。其作用方法是:编译时所有name都被换成replacement text,其scope为从出现到编译的文件结束。定义中可以用到之前的定义。编译中的替换不替换被双引号引起来的字符串,也不替换包含这个name的tokens的一部分。replacement text的选择是任意的。宏可以用参数,例如#define max(A,B) ((A)>(B)?A:B) 须注意A和B的括号,因为替换是literally的,如果不加括号会出问题。例如#define square(x) x*x,计算square(z+1)恐怕就不是你想要的结果。#undef可以取消定义。定义中#的用法:#define dprint(expr) printf(#expr " = %g\n", expr)。带了#的expr会给它加上""当作一个字符串处理。定义中##的用法:#define paste(front,back) front ## back的结果是paste(name,sir)是namesir。##吸收掉两边的空格把两边的参数连起来。条件包含(conditional inclusion):以#if或#ifdef或#ifndef开始,以#endif结束。例子:#ifndef HDR \n #define HDR \n #endif。条件测试可以用来保证header只被include一次,也可以用来针对不同系统include进不同的header。Chapter 5类型名 *name; 声明了一个指向某类型的指针。void *name;声明的指针可以用于值向任何类型的量,但不能从中取出它所指量的值。例如: int x *ip; ip=&x;把x的地址赋给指针ip。*ip在声明行的意思是“我这儿声明指针呢”,在statement里意思是指针所指地址的值。为什么指针还要声明类型?不声明类型就不能取所指地址的值?因为存一个值可能不止需要一个字节,不声明类型就不知道要往后读几个字节和以什么方式计算其值。*用作指针取值(dereference)时优先级仅次于括号那级,但它是从右往左算的,所以(*p)++中的括号是必要的。指针是变量,因此一个指针的值可以赋给另一个指针。函数不能直接改变call它的变量的值,但它可以改变作为它的arguments的指针。比如交换两数a,b的值可以写个交换两指针的函数swap(int *px,*py),然后用swap(&a,&b)貌似交换二者之值。数组元素的值是连续存储的,声明一个数组也就是给了一个指向数组0号元素的指针,char s[];和char *s;等价。事实上:若 int a[10],*pa; pa=&a[0];则a和pa是一个东西,a[i]和*(a+i)是一个东西,pa[i]和*(pa+i)是一个东西。须注意的是pa是变量,a不是。因此写pa++是合法的,a++则不合法。若p是指向某数组middle某元素,且p[-1]存在,则p[-1]这种写法合法。指针算术的加减不是地址的加减,而是一个元素一个元素的挪动,具体地址的操作埋在底下了。地址算术:指针所代表的地址在两指针所指元素属于同一个数组时可以减。指针之间不能加。指针可以自加和自减。指针可以被赋0值,其更多地被用NULL代替。NULL在<stdio.h>中被定义,0是唯一可与指针比较的数值。指向同一个数组的指针可以做大小比较,等或不等比较。若写char *p; p="hello";则p被赋予指向字符串"hello"第一个字符的指针值。而char q[]; q="hello";后q是一个数组。指针可以改为指向别的地址。数组元素可以变化但存储位置不变。指针数组的例子:int *girls[];指针的指针的例子:int *(*girls[]);多维数组声明时只有第一个[]可以是空的,其它的必须在声明时指明。多维数组更准确的说法是数组的数组,因为girls[i][j]是合法的,girls[i,j]则不合法。下面要说的比较tricky:int (*girls)[29];是一个指向包含29个元素的数组的指针,而int *girls[29];则是一个由29个指针为元素的数组。为啥?[]的优先级高于*。int *girl_phone(unsigned int number[]) 是一个参数为整数,返回值为指针的函数。也就是说:函数的返回值可以是指针。二维数组和指针数组的区别:声明一个指明长度的二维数组时就已经虚位以待了,而声明一个指明长度的指针数组不过是准备了几个位置做指针,还没说它们要指向哪。它们完全可以指向不同数组的子数组,且子数组的大小不必相同,这给了它灵活性。命令行参数:在命令行环境下call函数会自动地有两个arguments,一个是argc即argument的个数,函数名默认是第一个argument,所以argc至少为1;一个是argv,一个指针数组,指向一行命令的作为string的每个argument。指针也可以指向函数,例如(*girls)(int,int);意思是girls是一个指向有两个int arguments的函数的指针。也有返回值为指针的函数。嵌套几层容易晕。复杂声明这一节看得我头大,这东西有意义嘛?等发现有意义再回来看。Chapter 6本章描述一些用于存储数据的结构。用来定义结构的命令是struct。例子:struct point {int x;int y;};这定义了一个类型,大括号里面的是它的members。指明members用.MemberName。结构定义可以嵌套。取member的.运算符是从左往右计算的。函数定义的名字那一行,名字前面的用于指明返回值的类型,后面小括号里的指明arguments是什么。函数返回值可以属于struct定义出来的某个类型。如果一个大的结构要传给一个函数,一般传指针比传整个结构的copy要高效。指向结构的指针很常用,所以有一个特别的写法。例如p是一个指向结构的指针。p->member-of-structure就代表那个member,这比(*p).member要易写。指针的声明和赋值有个易混淆的地方,比如:struct point origin,*pp;pp=&origin;和struct point origin, *pp=&origin;是等价的。声明行里的*是用于告诉编译器“我这儿要声明一个指针”。指针的名字并不包括那个*,而在声明行之外用那个指针,前面还有个*的话,是取地址上存储的值的意思。 (收起)2012-01-07 17:06:44 回应
-
第1页
竹林 (给生活加点糖~~)
这是一本学习C语言的必读书籍,堪称经典。 我读的是电子版,chm格式的,所以没有页码,本文的页码指的是chapter。 第一章是概念性的介绍,从最经典的“Hello Word!”开始,到变量与算术表达式,数据类型,表达式,符号常量,字符的输入和输出,数组,函数,参数传递(值传递),字符数组,外部变量和作用域,并且包含了很多的练习题。 通过这些基础知识,作者把C语言的功能娓娓道来,深入浅出。本人学习C语言也有很长一段... (更多)这是一本学习C语言的必读书籍,堪称经典。我读的是电子版,chm格式的,所以没有页码,本文的页码指的是chapter。第一章是概念性的介绍,从最经典的“Hello Word!”开始,到变量与算术表达式,数据类型,表达式,符号常量,字符的输入和输出,数组,函数,参数传递(值传递),字符数组,外部变量和作用域,并且包含了很多的练习题。通过这些基础知识,作者把C语言的功能娓娓道来,深入浅出。本人学习C语言也有很长一段时间了,也写过一些代码,但是对一些细节问题还是有些模棱两可,而对C语言的掌握是需要很细致的,否则在调试一些代码或者BUG的时候是很痛苦的。为此,我在读这本书的同时,也同步做了一些练习,有些是书上的,有些是自己觉得很重要的,这些代码都放在了google code上,欢迎大家访问指正。代码地址:http://code.google.com/p/tcpl/ (收起)2011-04-14 22:54:19 回应
-
第1页
竹林 (给生活加点糖~~)
这是一本学习C语言的必读书籍,堪称经典。 我读的是电子版,chm格式的,所以没有页码,本文的页码指的是chapter。 第一章是概念性的介绍,从最经典的“Hello Word!”开始,到变量与算术表达式,数据类型,表达式,符号常量,字符的输入和输出,数组,函数,参数传递(值传递),字符数组,外部变量和作用域,并且包含了很多的练习题。 通过这些基础知识,作者把C语言的功能娓娓道来,深入浅出。本人学习C语言也有很长一段... (更多)这是一本学习C语言的必读书籍,堪称经典。我读的是电子版,chm格式的,所以没有页码,本文的页码指的是chapter。第一章是概念性的介绍,从最经典的“Hello Word!”开始,到变量与算术表达式,数据类型,表达式,符号常量,字符的输入和输出,数组,函数,参数传递(值传递),字符数组,外部变量和作用域,并且包含了很多的练习题。通过这些基础知识,作者把C语言的功能娓娓道来,深入浅出。本人学习C语言也有很长一段时间了,也写过一些代码,但是对一些细节问题还是有些模棱两可,而对C语言的掌握是需要很细致的,否则在调试一些代码或者BUG的时候是很痛苦的。为此,我在读这本书的同时,也同步做了一些练习,有些是书上的,有些是自己觉得很重要的,这些代码都放在了google code上,欢迎大家访问指正。代码地址:http://code.google.com/p/tcpl/ (收起)2011-04-14 22:54:19 回应
-
1-6
faithprice (必须强人所难)
C语言是所有语言的基础。我就从这里开始吧。 Chapter 1 最简单的C程序就是打印"Hello World!".文件头引用程序中要使用的printf函数所在的库文件stdio.h: #include <stdio.h>.每个C程序都要有个主干,用main开头,后面的()大概是用于括返回值,{}中间写程序语句。printf输出字符串要用""括起来。C源码写完存好,在字符界面cc之,如果程序没错,gcc会生成一个a.out,执行a.out,就可以看到结果。逗号在p... (更多)C语言是所有语言的基础。我就从这里开始吧。Chapter 1最简单的C程序就是打印"Hello World!".文件头引用程序中要使用的printf函数所在的库文件stdio.h: #include <stdio.h>.每个C程序都要有个主干,用main开头,后面的()大概是用于括返回值,{}中间写程序语句。printf输出字符串要用""括起来。C源码写完存好,在字符界面cc之,如果程序没错,gcc会生成一个a.out,执行a.out,就可以看到结果。逗号在printf输出的字符串里可以直接写,但是换行符需用\n表示,类似的\t表示制表符,\b表示backspace,\"表示",\\表示\。C的数据类型包括int short long,分别表示整型,短整型,长整型。变量声明的格式是int counter; 声明用分号;结尾,事实上所有语句都用分号结尾。while的格式:while后跟一对括号,括号里包含一个逻辑表达式,逻辑表达式的值为真则执行while所管的语句,执行一遍后再来检查此表达式,若为真则再执行,否则结束while语句,执行下一条。另一种结束while语句的方法是写break; while的特点是至少执行一次,另一个循环语句for可能一次都不执行。char float也是数据类型。char用于单个字符,float用于浮点数,即非整数。加减乘除分别是+-*/,需要注意的是/。若a,b都是整数类型,则a/b的结果是整数除法的结果,砍掉了余数,所以如要获得浮点数结果,则须强制类型转换。继续说printf:有时需要输出的不只是一个字符串,还需要把变量的值打印出来,这时就需要通配符。类似于printf("%d",counter);就会打印出counter这个整型变量的值,若有多个通配符,则后面以逗号分隔开的变量挨个对号入座。还可以规定输出变量值所占的位置,比如%6d就是占6个字符位置,%f用于float变量,%6.2f指用6格打印此变量,2格的小数位。%s是字符串。for的用法:for(expr1;expr2;expr3) expr1通常用于给控制循环的变量赋初值,expr2通常是个逻辑表达式,用于设定循环结束的边界条件,expr3通常用于改变控制变量的值。这三个expr都可以为空,只是要保证循环有限步后会结束。逻辑表达式的值为布尔型,只有0,1两个值。0代表假,1代表真。所有非零的数作为逻辑表达式值都是1.因此逻辑表达式可以是一个数值表达式,不一定是个逻辑判断。这提供了相当的灵活性。注意赋值和逻辑判断的区别:=用于赋值,==用于逻辑判断。后面将学到的字符的位操作也有类似的混淆可能,&是位的与操作,&&是两个逻辑表达式的并运算。为了调试和扩展的需要,也为了程序的易读性,通常不在程序里直接使用常数值,而是在程序头做常量声明,格式是:#define SUP 255 注意没有分号结尾。注释的用法:C语言中用/*和*/把注释括起来,也是为了易读性(readability)。Bear in mind,程序是拿来给人读的。大小关系判断符号:大于>,小于<,不大于<=,不小于>=,等于==,不等于!=。逻辑关系判断符号:并且&&,或者||,计算时从左至右,且得值即止。getchar()和putchar(),是读入和输出函数。假设c是一个char变量。c=getchar();把读入的字符赋给c,putchar(c);把c打印出来。EOF是一个特殊的char值,为-1,用于标记文件尾。char的取值范围是0-255,一个byte的范围。运算的优先级:赋值运算的优先级高于比较运算,因此c=getchar()!=EOF的意思是读入一个字符赋给c然后c跟EOF比较。++,--,+=,-=,*=,/=这些运算符。a++是先取a的值再加1,++a是先给a加1再取a的值。a+=1等价于a=a+1,这种运算比较紧凑,且易读性强。条件语句:C语言没有if then else,直接是 if expression statement1; else statement2;。expression的值为真则执行statement1,否则执行statement2. eles语句可无。if else可以嵌套,配对原则是else跟最近的if配,为免混淆和易读性,做好缩进和{}。字符用''括起来,不要跟字符串搞混了。'a'和"a"是不同的。函数:构成函数的要件是输入和输出,输入和输出都要声明数据类型,用return语句在函数体内给出输出。函数头的例子 int power(int base, int n)。其中的base和int不是必须的,只是为了易读性。完全可以写成int power(int,int)。不需要返回值的函数声明为void,例如 void copy(char to[],char from[])。int是default return type,可以省略。In C, we call by value. 意思是我们对call过来的是个local copy,不改变原值。这样的设置减少了很多出错的可能性,也可使程序更简洁。这是对变量,对数组就不是这样了。字符串的结尾隐藏着一个\0,作为“字符串在这里结束”的信号。缺省地,每个变量都local于声明它的函数,它的值不会保留,函数被call,then exit后它就被释放了,所以每次用它必须先初始化,否则它的值就是乱的。想使用一直存在的变量可以采用外部变量(external variable),外部变量必须在所有函数(包括main)的外面声明一次,若要在函数内部使用此外部变量,则必须在函数里前面加个extern声明之。除非绝对必要,不要使用外部变量,因为我不知道什么时候它就变化了,且使用外部变量不利于程序的万用性。Chapter 2变量的命名规则:变量名的首位可以用字母或下划线,但不推荐用下划线,因为库函数的名字常以下划线开头。变量名内部可以用字母,下划线和数字。变量名是大小写敏感的。有些词C语言已经占用了,不可以用于做变量名,例如if,else,int,float。应尽可能给变量起与它的作用相关的名,局部变量起短名,外部变量起长名。unsigned和signed,若char为8 bits,则unsigned char的取值范围是0到255,signed char的取值范围是-128到127。double是float的扩展数据类型,比float精度更高。float,double,long double三者的关系类似于short int,int,long int的关系。<limit.h>和<float.h>包含着数据类型的界数据。如何得知这些数据类型的范围?先定义一个unsigned int整数,赋值为0,然后减去1,由所得可知其范围,也可知其范围大小,由此可算出signed int的范围,其它数据类型的值域可用同样的方法求得。常数:以l或L结尾的整数为长整型,无符号数以u或U结尾,无符号长整型以ul或UL结尾,浮点数以f或F结尾,双精度浮点数以l或L结尾。八进制整数以0开头,16进制整数以0x或0X开头,非十进制整数也可加后缀L或U。字母字符和有些非字母字符可以直接括在''里表示,有些叫escape sequence的则不能。他们包括:\a alert, \\ 右斜杠, \b 退格, \? 问号,\f formfeed, \' 单引号, \n 换行, \" 双引号,\r carriage return, \ooo 八进制数, \xhh 十六进制数, \v 垂直tab, \t 水平tab. '\0'代表以0为值的字符。注意,一般地,'\x'代表以x为值的字符。任意字符串必须以不可见的'\0'结尾。标准库函数strlen(s)返回字符串s的长度(不包括尾部那个'\0')。strlen和其它字符串函数在<string.h>中。另一种表示常量的方式是枚举,例子:enum family {father=1,mother,son,daughter}; 其中mother会被自动赋值为2,son被赋值为3,注意枚举语句不像#define,它需要以分号结尾。枚举列表中的名字必须两两不同,但值不必。所有的变量必须在使用前声明。对于不想被改变的变量可在声明时前面加const后面赋值。例如: const double e=2.7182845905;&&和||第一章提过了,这里再强调一下它们的得值即止功能。他们是从左往右计算的,一旦算到足够决定他们值的地方,就不接着往右算了,这可以用于更灵活地写代码。不同数据类型的变量若在一个表达式里,会自动将数据范围小者转换为数据范围大者再进行运算。例如:int转为long, float转为double。C语言还提供了强制转换,只要在需转换的变量前写(类型名)即可。若将数值范围大的量赋给数值范围小的类型量,则会丢失数据。自加和自减运算符:只能用于变量,不可用于表达式,即a++可以,(a+b)++不可以。用此运算符常可简化程序。位运算:& 按位与, | 按位或,^按位异或,<<左移,>>右移,~按位补。&可以用mask数取截出一段。左右移空出来的位用0补(对于unsinged)。注意位运算与逻辑运算的区别。赋值运算符:expr1 op=expr2等价于expr1=expr1 op expr2。<ctype.h>提供了一族无关于字符集的测试和转化函数。例如isdigit()。<math.h>提供了一些常见数学函数。例如sqrt()。条件表达式:expr1 ? expr2 : expr3.其意义是若expr1为真,则执行expr2,否则执行expr3。用它可使程序更紧凑。运算优先度列表,用tab分组:() [] ->! ~ ++ -- + - *(type) sizeof* / %+ -<< >>< <= > >=== !=&^ |&&||?:= += -= *= /= &= ^= |= <<= >>=, 一元运算符& + - * 比同个模样的二元运算符优先级高。Chapter 3本章的名字叫control flow,应是详解各语句的用法。一般的语句以分号结尾。{}可以当作一个语句看,不需要再加分号做结尾。switch (expr) {case const-expr: statementscase const-expr: statementsdefault: statements} 这是switch语句的格式。特别注意不同case可以共用statements,只要冒号后面继续跟case就可以。运算符逗号,常见于for的()里,被逗号分隔开的两个表达式从左往右计算,计算结果的类型和数值是最右边的那个表达式的类型和数值。逗号运算符不要多用,若非逻辑上紧密相连的表达式,不要往一起连。do-while: dostatementwhile(expression);即statement至少执行一次。想速度从循环中跳出时用break,注意一个break能且只能跳出一层循环。这与return不同,return直接终止函数体的运行。continue:只用于for,while中,效果是这次循环到此结束,直接执行下一次循环。goto的用法: go label;......label:除非绝对必要,别用goto。Chapter 4本章的标题是:函数和程序结构。我们大概都听说过。好的程序结构是自顶向下的。一个由多个独立的小结构组合成的大结构更稳定,更容易维护,其中的小结构也容易用在别处。在函数声明和定义处言明所用参数的类型是个好习惯,call此函数时可自动做强制类型转换以避免出错。若函数预料之外地无返回值,很可能什么地方搞砸了,去看看。函数声明时的返回值和call它时期待的返回值必须统一,否则会出错。C语言中不允许在函数内定义函数。cc命令可以同时编译数个C语言源文件(*.c),若某个源文件编译出错,修改后可再将此源文件(*.c)与其它已编译通过的对象文件(*.o)一起编译。所有的函数和函数参数若在遇到定义前就遇到引用,默认其返回值和参数均为int类型。如果函数有参数,声明它们的类型,如果没有,用void。automatic variables是生活在函数内部的,call结束即释放,不保留值。external variables可以在函数之间传递参数,但也有可能造成意料之外的改动。编程作为工程的精神是:尽量让每一部分都只知道(可access)它必须知道的部分,其它的互相之间都隐藏起来。scope:即一个对象的有效范围。automatic variables的scope是定义它的函数内。external variable和函数的scope是从声明它开始到所编译的文件结束。如果一个external variable在定义之前就被引用,或它在一个不同于定义它的文件中被使用,则必须用extern来定义它。习惯上把所有函数和外部变量一起在头文件(header file)里声明了,起名*.h。static variables: 一个变量既需要在某些函数间使用,又不希望别的函数知道它,可以把前者那些函数写在一个文件里,在此变量声明前加static和external即可。函数也可声明为static,这样函数所在文件之外就不能call它了。static也可用在内部变量上,它也像automatic variables只存在于特定函数内,但不同的是它保有storage,函数call完值还在。寄存器变量(register variables):只能将automatic variables和函数的形式参数声明为寄存器变量,可能可以加快程序运行速度。块结构(block structure):函数不能在块结构中嵌套,但变量可以在块结构中声明,且scope限于那个块。一对{}(compound statement)即可构成一个块。若在块中有与external variable同名的变量则其类型以块中的为准,但通常不建议使用重名变量。初始化:如无显明初始化,external和static变量自动获得0初值,automatic和register变量自动获得垃圾初值。若赋初值,则external和static的必须是常数形式的初值,automatic和register的可以是由其它变量算出来的数值赋给它,甚或是函数返回值。数组的初始化:可以把{}中用逗号隔开的数依序赋给数组元素。若数组大小未指定,则编译器会自动按所赋值个数确定,若所赋值个数大于指定大小则报错,若小于则剩下的初始化为0.字符数组可以{}地赋值,也可以直接把字符串"***"赋给它,{'a','\0'}等价于"a"。C中的函数可以迭代使用。允许迭代可以使函数比较容易写和看懂。但是定要小心处理迭代到trivial时的状态。C的预处理:#include"" 和#include<>都可以使编译时直接把别的文件的内容拿过来代替这一行。被include的文件若修改了,所有include它的文件都要重新编译。宏的格式:#define name replacement text。其作用方法是:编译时所有name都被换成replacement text,其scope为从出现到编译的文件结束。定义中可以用到之前的定义。编译中的替换不替换被双引号引起来的字符串,也不替换包含这个name的tokens的一部分。replacement text的选择是任意的。宏可以用参数,例如#define max(A,B) ((A)>(B)?A:B) 须注意A和B的括号,因为替换是literally的,如果不加括号会出问题。例如#define square(x) x*x,计算square(z+1)恐怕就不是你想要的结果。#undef可以取消定义。定义中#的用法:#define dprint(expr) printf(#expr " = %g\n", expr)。带了#的expr会给它加上""当作一个字符串处理。定义中##的用法:#define paste(front,back) front ## back的结果是paste(name,sir)是namesir。##吸收掉两边的空格把两边的参数连起来。条件包含(conditional inclusion):以#if或#ifdef或#ifndef开始,以#endif结束。例子:#ifndef HDR \n #define HDR \n #endif。条件测试可以用来保证header只被include一次,也可以用来针对不同系统include进不同的header。Chapter 5类型名 *name; 声明了一个指向某类型的指针。void *name;声明的指针可以用于值向任何类型的量,但不能从中取出它所指量的值。例如: int x *ip; ip=&x;把x的地址赋给指针ip。*ip在声明行的意思是“我这儿声明指针呢”,在statement里意思是指针所指地址的值。为什么指针还要声明类型?不声明类型就不能取所指地址的值?因为存一个值可能不止需要一个字节,不声明类型就不知道要往后读几个字节和以什么方式计算其值。*用作指针取值(dereference)时优先级仅次于括号那级,但它是从右往左算的,所以(*p)++中的括号是必要的。指针是变量,因此一个指针的值可以赋给另一个指针。函数不能直接改变call它的变量的值,但它可以改变作为它的arguments的指针。比如交换两数a,b的值可以写个交换两指针的函数swap(int *px,*py),然后用swap(&a,&b)貌似交换二者之值。数组元素的值是连续存储的,声明一个数组也就是给了一个指向数组0号元素的指针,char s[];和char *s;等价。事实上:若 int a[10],*pa; pa=&a[0];则a和pa是一个东西,a[i]和*(a+i)是一个东西,pa[i]和*(pa+i)是一个东西。须注意的是pa是变量,a不是。因此写pa++是合法的,a++则不合法。若p是指向某数组middle某元素,且p[-1]存在,则p[-1]这种写法合法。指针算术的加减不是地址的加减,而是一个元素一个元素的挪动,具体地址的操作埋在底下了。地址算术:指针所代表的地址在两指针所指元素属于同一个数组时可以减。指针之间不能加。指针可以自加和自减。指针可以被赋0值,其更多地被用NULL代替。NULL在<stdio.h>中被定义,0是唯一可与指针比较的数值。指向同一个数组的指针可以做大小比较,等或不等比较。若写char *p; p="hello";则p被赋予指向字符串"hello"第一个字符的指针值。而char q[]; q="hello";后q是一个数组。指针可以改为指向别的地址。数组元素可以变化但存储位置不变。指针数组的例子:int *girls[];指针的指针的例子:int *(*girls[]);多维数组声明时只有第一个[]可以是空的,其它的必须在声明时指明。多维数组更准确的说法是数组的数组,因为girls[i][j]是合法的,girls[i,j]则不合法。下面要说的比较tricky:int (*girls)[29];是一个指向包含29个元素的数组的指针,而int *girls[29];则是一个由29个指针为元素的数组。为啥?[]的优先级高于*。int *girl_phone(unsigned int number[]) 是一个参数为整数,返回值为指针的函数。也就是说:函数的返回值可以是指针。二维数组和指针数组的区别:声明一个指明长度的二维数组时就已经虚位以待了,而声明一个指明长度的指针数组不过是准备了几个位置做指针,还没说它们要指向哪。它们完全可以指向不同数组的子数组,且子数组的大小不必相同,这给了它灵活性。命令行参数:在命令行环境下call函数会自动地有两个arguments,一个是argc即argument的个数,函数名默认是第一个argument,所以argc至少为1;一个是argv,一个指针数组,指向一行命令的作为string的每个argument。指针也可以指向函数,例如(*girls)(int,int);意思是girls是一个指向有两个int arguments的函数的指针。也有返回值为指针的函数。嵌套几层容易晕。复杂声明这一节看得我头大,这东西有意义嘛?等发现有意义再回来看。Chapter 6本章描述一些用于存储数据的结构。用来定义结构的命令是struct。例子:struct point {int x;int y;};这定义了一个类型,大括号里面的是它的members。指明members用.MemberName。结构定义可以嵌套。取member的.运算符是从左往右计算的。函数定义的名字那一行,名字前面的用于指明返回值的类型,后面小括号里的指明arguments是什么。函数返回值可以属于struct定义出来的某个类型。如果一个大的结构要传给一个函数,一般传指针比传整个结构的copy要高效。指向结构的指针很常用,所以有一个特别的写法。例如p是一个指向结构的指针。p->member-of-structure就代表那个member,这比(*p).member要易写。指针的声明和赋值有个易混淆的地方,比如:struct point origin,*pp;pp=&origin;和struct point origin, *pp=&origin;是等价的。声明行里的*是用于告诉编译器“我这儿要声明一个指针”。指针的名字并不包括那个*,而在声明行之外用那个指针,前面还有个*的话,是取地址上存储的值的意思。 (收起)2012-01-07 17:06:44 回应
-
1-6
faithprice (必须强人所难)
C语言是所有语言的基础。我就从这里开始吧。 Chapter 1 最简单的C程序就是打印"Hello World!".文件头引用程序中要使用的printf函数所在的库文件stdio.h: #include <stdio.h>.每个C程序都要有个主干,用main开头,后面的()大概是用于括返回值,{}中间写程序语句。printf输出字符串要用""括起来。C源码写完存好,在字符界面cc之,如果程序没错,gcc会生成一个a.out,执行a.out,就可以看到结果。逗号在p... (更多)C语言是所有语言的基础。我就从这里开始吧。Chapter 1最简单的C程序就是打印"Hello World!".文件头引用程序中要使用的printf函数所在的库文件stdio.h: #include <stdio.h>.每个C程序都要有个主干,用main开头,后面的()大概是用于括返回值,{}中间写程序语句。printf输出字符串要用""括起来。C源码写完存好,在字符界面cc之,如果程序没错,gcc会生成一个a.out,执行a.out,就可以看到结果。逗号在printf输出的字符串里可以直接写,但是换行符需用\n表示,类似的\t表示制表符,\b表示backspace,\"表示",\\表示\。C的数据类型包括int short long,分别表示整型,短整型,长整型。变量声明的格式是int counter; 声明用分号;结尾,事实上所有语句都用分号结尾。while的格式:while后跟一对括号,括号里包含一个逻辑表达式,逻辑表达式的值为真则执行while所管的语句,执行一遍后再来检查此表达式,若为真则再执行,否则结束while语句,执行下一条。另一种结束while语句的方法是写break; while的特点是至少执行一次,另一个循环语句for可能一次都不执行。char float也是数据类型。char用于单个字符,float用于浮点数,即非整数。加减乘除分别是+-*/,需要注意的是/。若a,b都是整数类型,则a/b的结果是整数除法的结果,砍掉了余数,所以如要获得浮点数结果,则须强制类型转换。继续说printf:有时需要输出的不只是一个字符串,还需要把变量的值打印出来,这时就需要通配符。类似于printf("%d",counter);就会打印出counter这个整型变量的值,若有多个通配符,则后面以逗号分隔开的变量挨个对号入座。还可以规定输出变量值所占的位置,比如%6d就是占6个字符位置,%f用于float变量,%6.2f指用6格打印此变量,2格的小数位。%s是字符串。for的用法:for(expr1;expr2;expr3) expr1通常用于给控制循环的变量赋初值,expr2通常是个逻辑表达式,用于设定循环结束的边界条件,expr3通常用于改变控制变量的值。这三个expr都可以为空,只是要保证循环有限步后会结束。逻辑表达式的值为布尔型,只有0,1两个值。0代表假,1代表真。所有非零的数作为逻辑表达式值都是1.因此逻辑表达式可以是一个数值表达式,不一定是个逻辑判断。这提供了相当的灵活性。注意赋值和逻辑判断的区别:=用于赋值,==用于逻辑判断。后面将学到的字符的位操作也有类似的混淆可能,&是位的与操作,&&是两个逻辑表达式的并运算。为了调试和扩展的需要,也为了程序的易读性,通常不在程序里直接使用常数值,而是在程序头做常量声明,格式是:#define SUP 255 注意没有分号结尾。注释的用法:C语言中用/*和*/把注释括起来,也是为了易读性(readability)。Bear in mind,程序是拿来给人读的。大小关系判断符号:大于>,小于<,不大于<=,不小于>=,等于==,不等于!=。逻辑关系判断符号:并且&&,或者||,计算时从左至右,且得值即止。getchar()和putchar(),是读入和输出函数。假设c是一个char变量。c=getchar();把读入的字符赋给c,putchar(c);把c打印出来。EOF是一个特殊的char值,为-1,用于标记文件尾。char的取值范围是0-255,一个byte的范围。运算的优先级:赋值运算的优先级高于比较运算,因此c=getchar()!=EOF的意思是读入一个字符赋给c然后c跟EOF比较。++,--,+=,-=,*=,/=这些运算符。a++是先取a的值再加1,++a是先给a加1再取a的值。a+=1等价于a=a+1,这种运算比较紧凑,且易读性强。条件语句:C语言没有if then else,直接是 if expression statement1; else statement2;。expression的值为真则执行statement1,否则执行statement2. eles语句可无。if else可以嵌套,配对原则是else跟最近的if配,为免混淆和易读性,做好缩进和{}。字符用''括起来,不要跟字符串搞混了。'a'和"a"是不同的。函数:构成函数的要件是输入和输出,输入和输出都要声明数据类型,用return语句在函数体内给出输出。函数头的例子 int power(int base, int n)。其中的base和int不是必须的,只是为了易读性。完全可以写成int power(int,int)。不需要返回值的函数声明为void,例如 void copy(char to[],char from[])。int是default return type,可以省略。In C, we call by value. 意思是我们对call过来的是个local copy,不改变原值。这样的设置减少了很多出错的可能性,也可使程序更简洁。这是对变量,对数组就不是这样了。字符串的结尾隐藏着一个\0,作为“字符串在这里结束”的信号。缺省地,每个变量都local于声明它的函数,它的值不会保留,函数被call,then exit后它就被释放了,所以每次用它必须先初始化,否则它的值就是乱的。想使用一直存在的变量可以采用外部变量(external variable),外部变量必须在所有函数(包括main)的外面声明一次,若要在函数内部使用此外部变量,则必须在函数里前面加个extern声明之。除非绝对必要,不要使用外部变量,因为我不知道什么时候它就变化了,且使用外部变量不利于程序的万用性。Chapter 2变量的命名规则:变量名的首位可以用字母或下划线,但不推荐用下划线,因为库函数的名字常以下划线开头。变量名内部可以用字母,下划线和数字。变量名是大小写敏感的。有些词C语言已经占用了,不可以用于做变量名,例如if,else,int,float。应尽可能给变量起与它的作用相关的名,局部变量起短名,外部变量起长名。unsigned和signed,若char为8 bits,则unsigned char的取值范围是0到255,signed char的取值范围是-128到127。double是float的扩展数据类型,比float精度更高。float,double,long double三者的关系类似于short int,int,long int的关系。<limit.h>和<float.h>包含着数据类型的界数据。如何得知这些数据类型的范围?先定义一个unsigned int整数,赋值为0,然后减去1,由所得可知其范围,也可知其范围大小,由此可算出signed int的范围,其它数据类型的值域可用同样的方法求得。常数:以l或L结尾的整数为长整型,无符号数以u或U结尾,无符号长整型以ul或UL结尾,浮点数以f或F结尾,双精度浮点数以l或L结尾。八进制整数以0开头,16进制整数以0x或0X开头,非十进制整数也可加后缀L或U。字母字符和有些非字母字符可以直接括在''里表示,有些叫escape sequence的则不能。他们包括:\a alert, \\ 右斜杠, \b 退格, \? 问号,\f formfeed, \' 单引号, \n 换行, \" 双引号,\r carriage return, \ooo 八进制数, \xhh 十六进制数, \v 垂直tab, \t 水平tab. '\0'代表以0为值的字符。注意,一般地,'\x'代表以x为值的字符。任意字符串必须以不可见的'\0'结尾。标准库函数strlen(s)返回字符串s的长度(不包括尾部那个'\0')。strlen和其它字符串函数在<string.h>中。另一种表示常量的方式是枚举,例子:enum family {father=1,mother,son,daughter}; 其中mother会被自动赋值为2,son被赋值为3,注意枚举语句不像#define,它需要以分号结尾。枚举列表中的名字必须两两不同,但值不必。所有的变量必须在使用前声明。对于不想被改变的变量可在声明时前面加const后面赋值。例如: const double e=2.7182845905;&&和||第一章提过了,这里再强调一下它们的得值即止功能。他们是从左往右计算的,一旦算到足够决定他们值的地方,就不接着往右算了,这可以用于更灵活地写代码。不同数据类型的变量若在一个表达式里,会自动将数据范围小者转换为数据范围大者再进行运算。例如:int转为long, float转为double。C语言还提供了强制转换,只要在需转换的变量前写(类型名)即可。若将数值范围大的量赋给数值范围小的类型量,则会丢失数据。自加和自减运算符:只能用于变量,不可用于表达式,即a++可以,(a+b)++不可以。用此运算符常可简化程序。位运算:& 按位与, | 按位或,^按位异或,<<左移,>>右移,~按位补。&可以用mask数取截出一段。左右移空出来的位用0补(对于unsinged)。注意位运算与逻辑运算的区别。赋值运算符:expr1 op=expr2等价于expr1=expr1 op expr2。<ctype.h>提供了一族无关于字符集的测试和转化函数。例如isdigit()。<math.h>提供了一些常见数学函数。例如sqrt()。条件表达式:expr1 ? expr2 : expr3.其意义是若expr1为真,则执行expr2,否则执行expr3。用它可使程序更紧凑。运算优先度列表,用tab分组:() [] ->! ~ ++ -- + - *(type) sizeof* / %+ -<< >>< <= > >=== !=&^ |&&||?:= += -= *= /= &= ^= |= <<= >>=, 一元运算符& + - * 比同个模样的二元运算符优先级高。Chapter 3本章的名字叫control flow,应是详解各语句的用法。一般的语句以分号结尾。{}可以当作一个语句看,不需要再加分号做结尾。switch (expr) {case const-expr: statementscase const-expr: statementsdefault: statements} 这是switch语句的格式。特别注意不同case可以共用statements,只要冒号后面继续跟case就可以。运算符逗号,常见于for的()里,被逗号分隔开的两个表达式从左往右计算,计算结果的类型和数值是最右边的那个表达式的类型和数值。逗号运算符不要多用,若非逻辑上紧密相连的表达式,不要往一起连。do-while: dostatementwhile(expression);即statement至少执行一次。想速度从循环中跳出时用break,注意一个break能且只能跳出一层循环。这与return不同,return直接终止函数体的运行。continue:只用于for,while中,效果是这次循环到此结束,直接执行下一次循环。goto的用法: go label;......label:除非绝对必要,别用goto。Chapter 4本章的标题是:函数和程序结构。我们大概都听说过。好的程序结构是自顶向下的。一个由多个独立的小结构组合成的大结构更稳定,更容易维护,其中的小结构也容易用在别处。在函数声明和定义处言明所用参数的类型是个好习惯,call此函数时可自动做强制类型转换以避免出错。若函数预料之外地无返回值,很可能什么地方搞砸了,去看看。函数声明时的返回值和call它时期待的返回值必须统一,否则会出错。C语言中不允许在函数内定义函数。cc命令可以同时编译数个C语言源文件(*.c),若某个源文件编译出错,修改后可再将此源文件(*.c)与其它已编译通过的对象文件(*.o)一起编译。所有的函数和函数参数若在遇到定义前就遇到引用,默认其返回值和参数均为int类型。如果函数有参数,声明它们的类型,如果没有,用void。automatic variables是生活在函数内部的,call结束即释放,不保留值。external variables可以在函数之间传递参数,但也有可能造成意料之外的改动。编程作为工程的精神是:尽量让每一部分都只知道(可access)它必须知道的部分,其它的互相之间都隐藏起来。scope:即一个对象的有效范围。automatic variables的scope是定义它的函数内。external variable和函数的scope是从声明它开始到所编译的文件结束。如果一个external variable在定义之前就被引用,或它在一个不同于定义它的文件中被使用,则必须用extern来定义它。习惯上把所有函数和外部变量一起在头文件(header file)里声明了,起名*.h。static variables: 一个变量既需要在某些函数间使用,又不希望别的函数知道它,可以把前者那些函数写在一个文件里,在此变量声明前加static和external即可。函数也可声明为static,这样函数所在文件之外就不能call它了。static也可用在内部变量上,它也像automatic variables只存在于特定函数内,但不同的是它保有storage,函数call完值还在。寄存器变量(register variables):只能将automatic variables和函数的形式参数声明为寄存器变量,可能可以加快程序运行速度。块结构(block structure):函数不能在块结构中嵌套,但变量可以在块结构中声明,且scope限于那个块。一对{}(compound statement)即可构成一个块。若在块中有与external variable同名的变量则其类型以块中的为准,但通常不建议使用重名变量。初始化:如无显明初始化,external和static变量自动获得0初值,automatic和register变量自动获得垃圾初值。若赋初值,则external和static的必须是常数形式的初值,automatic和register的可以是由其它变量算出来的数值赋给它,甚或是函数返回值。数组的初始化:可以把{}中用逗号隔开的数依序赋给数组元素。若数组大小未指定,则编译器会自动按所赋值个数确定,若所赋值个数大于指定大小则报错,若小于则剩下的初始化为0.字符数组可以{}地赋值,也可以直接把字符串"***"赋给它,{'a','\0'}等价于"a"。C中的函数可以迭代使用。允许迭代可以使函数比较容易写和看懂。但是定要小心处理迭代到trivial时的状态。C的预处理:#include"" 和#include<>都可以使编译时直接把别的文件的内容拿过来代替这一行。被include的文件若修改了,所有include它的文件都要重新编译。宏的格式:#define name replacement text。其作用方法是:编译时所有name都被换成replacement text,其scope为从出现到编译的文件结束。定义中可以用到之前的定义。编译中的替换不替换被双引号引起来的字符串,也不替换包含这个name的tokens的一部分。replacement text的选择是任意的。宏可以用参数,例如#define max(A,B) ((A)>(B)?A:B) 须注意A和B的括号,因为替换是literally的,如果不加括号会出问题。例如#define square(x) x*x,计算square(z+1)恐怕就不是你想要的结果。#undef可以取消定义。定义中#的用法:#define dprint(expr) printf(#expr " = %g\n", expr)。带了#的expr会给它加上""当作一个字符串处理。定义中##的用法:#define paste(front,back) front ## back的结果是paste(name,sir)是namesir。##吸收掉两边的空格把两边的参数连起来。条件包含(conditional inclusion):以#if或#ifdef或#ifndef开始,以#endif结束。例子:#ifndef HDR \n #define HDR \n #endif。条件测试可以用来保证header只被include一次,也可以用来针对不同系统include进不同的header。Chapter 5类型名 *name; 声明了一个指向某类型的指针。void *name;声明的指针可以用于值向任何类型的量,但不能从中取出它所指量的值。例如: int x *ip; ip=&x;把x的地址赋给指针ip。*ip在声明行的意思是“我这儿声明指针呢”,在statement里意思是指针所指地址的值。为什么指针还要声明类型?不声明类型就不能取所指地址的值?因为存一个值可能不止需要一个字节,不声明类型就不知道要往后读几个字节和以什么方式计算其值。*用作指针取值(dereference)时优先级仅次于括号那级,但它是从右往左算的,所以(*p)++中的括号是必要的。指针是变量,因此一个指针的值可以赋给另一个指针。函数不能直接改变call它的变量的值,但它可以改变作为它的arguments的指针。比如交换两数a,b的值可以写个交换两指针的函数swap(int *px,*py),然后用swap(&a,&b)貌似交换二者之值。数组元素的值是连续存储的,声明一个数组也就是给了一个指向数组0号元素的指针,char s[];和char *s;等价。事实上:若 int a[10],*pa; pa=&a[0];则a和pa是一个东西,a[i]和*(a+i)是一个东西,pa[i]和*(pa+i)是一个东西。须注意的是pa是变量,a不是。因此写pa++是合法的,a++则不合法。若p是指向某数组middle某元素,且p[-1]存在,则p[-1]这种写法合法。指针算术的加减不是地址的加减,而是一个元素一个元素的挪动,具体地址的操作埋在底下了。地址算术:指针所代表的地址在两指针所指元素属于同一个数组时可以减。指针之间不能加。指针可以自加和自减。指针可以被赋0值,其更多地被用NULL代替。NULL在<stdio.h>中被定义,0是唯一可与指针比较的数值。指向同一个数组的指针可以做大小比较,等或不等比较。若写char *p; p="hello";则p被赋予指向字符串"hello"第一个字符的指针值。而char q[]; q="hello";后q是一个数组。指针可以改为指向别的地址。数组元素可以变化但存储位置不变。指针数组的例子:int *girls[];指针的指针的例子:int *(*girls[]);多维数组声明时只有第一个[]可以是空的,其它的必须在声明时指明。多维数组更准确的说法是数组的数组,因为girls[i][j]是合法的,girls[i,j]则不合法。下面要说的比较tricky:int (*girls)[29];是一个指向包含29个元素的数组的指针,而int *girls[29];则是一个由29个指针为元素的数组。为啥?[]的优先级高于*。int *girl_phone(unsigned int number[]) 是一个参数为整数,返回值为指针的函数。也就是说:函数的返回值可以是指针。二维数组和指针数组的区别:声明一个指明长度的二维数组时就已经虚位以待了,而声明一个指明长度的指针数组不过是准备了几个位置做指针,还没说它们要指向哪。它们完全可以指向不同数组的子数组,且子数组的大小不必相同,这给了它灵活性。命令行参数:在命令行环境下call函数会自动地有两个arguments,一个是argc即argument的个数,函数名默认是第一个argument,所以argc至少为1;一个是argv,一个指针数组,指向一行命令的作为string的每个argument。指针也可以指向函数,例如(*girls)(int,int);意思是girls是一个指向有两个int arguments的函数的指针。也有返回值为指针的函数。嵌套几层容易晕。复杂声明这一节看得我头大,这东西有意义嘛?等发现有意义再回来看。Chapter 6本章描述一些用于存储数据的结构。用来定义结构的命令是struct。例子:struct point {int x;int y;};这定义了一个类型,大括号里面的是它的members。指明members用.MemberName。结构定义可以嵌套。取member的.运算符是从左往右计算的。函数定义的名字那一行,名字前面的用于指明返回值的类型,后面小括号里的指明arguments是什么。函数返回值可以属于struct定义出来的某个类型。如果一个大的结构要传给一个函数,一般传指针比传整个结构的copy要高效。指向结构的指针很常用,所以有一个特别的写法。例如p是一个指向结构的指针。p->member-of-structure就代表那个member,这比(*p).member要易写。指针的声明和赋值有个易混淆的地方,比如:struct point origin,*pp;pp=&origin;和struct point origin, *pp=&origin;是等价的。声明行里的*是用于告诉编译器“我这儿要声明一个指针”。指针的名字并不包括那个*,而在声明行之外用那个指针,前面还有个*的话,是取地址上存储的值的意思。 (收起)2012-01-07 17:06:44 回应
-
第1页
竹林 (给生活加点糖~~)
这是一本学习C语言的必读书籍,堪称经典。 我读的是电子版,chm格式的,所以没有页码,本文的页码指的是chapter。 第一章是概念性的介绍,从最经典的“Hello Word!”开始,到变量与算术表达式,数据类型,表达式,符号常量,字符的输入和输出,数组,函数,参数传递(值传递),字符数组,外部变量和作用域,并且包含了很多的练习题。 通过这些基础知识,作者把C语言的功能娓娓道来,深入浅出。本人学习C语言也有很长一段... (更多)这是一本学习C语言的必读书籍,堪称经典。我读的是电子版,chm格式的,所以没有页码,本文的页码指的是chapter。第一章是概念性的介绍,从最经典的“Hello Word!”开始,到变量与算术表达式,数据类型,表达式,符号常量,字符的输入和输出,数组,函数,参数传递(值传递),字符数组,外部变量和作用域,并且包含了很多的练习题。通过这些基础知识,作者把C语言的功能娓娓道来,深入浅出。本人学习C语言也有很长一段时间了,也写过一些代码,但是对一些细节问题还是有些模棱两可,而对C语言的掌握是需要很细致的,否则在调试一些代码或者BUG的时候是很痛苦的。为此,我在读这本书的同时,也同步做了一些练习,有些是书上的,有些是自己觉得很重要的,这些代码都放在了google code上,欢迎大家访问指正。代码地址:http://code.google.com/p/tcpl/ (收起)2011-04-14 22:54:19 回应
书评 · · · · · · (共50条) 我来评论这本书
热门评论 最新评论
K&R
-
- shuaiye 把谭老师的书丢到废纸篓里是唯一正确的选择。 科尼汉的书简洁明晰到了极致。我买了能买到的科尼汉所有的书, 从《unix编程环境》到《程序设计实践》,没有一本让我失望。 伟大的作者,简洁风格的代表,永远的K&R. ...... (46回应)2005-09-26 49/54有用来自 机械工业出版社2004版
请看C语言圣经!--- 浅谈我个人的阅读体会
-
- 一笑 如果你是一个完完全全的编程新手,本书不适合于你---- 你应该先看一本国内的C语言教材,他们虽然泛泛而谈,但至少可以让你了解具备一点最基本的C语言知识,而且不会让你感到太困难---比如潭老师的书(虽然被很多人唾弃)---何况国内的作者最适合写计算机方面泛泛而谈的书籍..呵呵。 如果你已经看过1到2本最基础...... (11回应)2006-04-16 47/49有用来自 机械工业出版社2004版
配套此书的习题集一起看,可功力大增.
-
- compactset 其实第一本c语言书是不是它要看各人功力.要是不会吸星大法, 纵然有高手注入n股纯阳真气, 也练不出九阳神功. 第一遍读此书, 悟性如我这样的, 觉得没有什么收获, 因为自己体质太弱, 突然进补此等无色无臭的高级鸡汤, 实在吸收不了其中的高级营养, 只能喝点米汤,于是我读"C语言的科学和艺术". 后来,慢...... (6回应)2008-07-18 22/22有用来自 机械工业出版社2004版
C语言的圣经
-
- hcwang 拿到这本薄薄的书,很多人开始怀疑,C语言是这么几百页能讲清楚的么。看完这本书,我想答案已经很明了,却真的让人感到震憾。什么是好书?无法删减的书才是真正的好书。K&R的书一如C语言的设计理念:简单而高效 里面的习题建议都认真做一遍,而且是在linux下用vi来做,用makefile来编译,用shell脚本来进行测试,本...... (7回应)2007-12-05 26/27有用来自 机械工业出版社2004版
书写出来的只是冰山一角
-
- nokivan 1年前翻过的书,当时感觉就是一本讲的不够详细的一本书,还有题目很难。曾经甚至幼稚的以为看懂了这本书。随着对C和CS的逐渐了解,期间总是想再把它拿过来认认真真的看一遍。他比任何其他任何语言类书籍能让你感觉”踏实“,或许这就是作者功力和经验的体现。现在再翻翻不得不说作者”在下一盘很大的棋“。书写出来的只是冰山一角,能不能看......2012-02-11 1/1有用来自 机械工业出版社2004版
推荐一个C语言教程(小学生坐在马桶上都可以读懂的...
-
- 啊哈C语言 推荐一个C语言教程………… 萌爆了……………… 小学生坐在马桶上都可以读懂的“C语言编程”入门书 下载地址:下载地址http://www.docin.com/p-332091647.html......2012-02-04 来自 机械工业出版社2004版
这本书还行
-
- start 书还行。不过光看书自学觉得挺累的,有些操作,好多遍都搞不明白。我找了一个猎豹网校,上面都是这类IT课程,看着视频,有老师教,学起来更容易些。不懂还可以随时请教的,觉得还不错。 ......2012-02-01 来自 机械工业出版社2004版
推荐一下
-
- cordial "终于拿到书了!翻了几下挺高兴的。我是初学者,在读职校,学校有开一点计算机课程,不过讲得比较简单。我自己喜欢学编程,就买来C语言想好好再学下。说实话,书是随便买的,因为那么多也一下子看不出哪本好哪本不太好。才看前两章还行,再往后翻就觉得吃力了。还好在网上找到一个专门教编程课程的猎豹网校,在那里试听了一下,觉得有老师教和......2011-12-06 来自 机械工业出版社2004版
一本程序员案头必备的书籍
-
- 恋雨晴结 看这本书已经很长一点时间了,当时学习C语言的时候用的谭浩强的书,后来想深入的学习C语言,就买了这本书,本书的作者就是C语言的发明者,本书只有薄薄的两百来页,但是却字字珠玑,深刻透彻,可以说是C语言方面最经典的书,不仅值得阅读,还值得收藏。......2011-12-02 来自 机械工业出版社2004版
不错的一本书!
-
- summary 有人说C语言超简单啊,可也有人说C语言太难了,自学没法看的!我自己买来书一看,嘿,真不幸,我归后面那一堆儿的!我就在网上到处找怎么学,在猎豹网校上看到,那么多编程课程,一大堆IT课程,就有这个C语言!一看视频,觉得老师讲得挺清楚啊,跟着听,好像也不怎么难啊。我一琢磨,是自己没那个耐心,一行一行去对着书啃那么多代码,搞清......2011-11-21 来自 清华大学出版社2000版
"C Programming Language"的论坛 · · · · · ·
| 有下载的地方吗? | 来自索析(Soothe) | 2 回应 | 2012-01-16 |
| 经典的不用多说 | 来自低调的华丽 | 2009-05-29 | |
| 淘到了原版的 | 来自lala | 11 回应 | 2009-12-04 |
| 感觉像C语言圣经一样的书 | 来自melody | 2010-08-08 | |
| 感觉像C语言圣经一样的书 | 来自melody | 2010-08-08 |
> 浏览更多话题
在哪儿买这本书? · · · · · ·
- 亚马逊 (RMB 841.50)
- 查看1家网店价格 (841.50元起)
- 加入购书单 多本比价 批量购买 已在购书单
这本书的其他版本 · · · · · · ( 全部7 )
以下豆列推荐 · · · · · · (全部)
- 程序员最应该读的图书(原版) (hongqn)
- 【C/C++学习指南】 (小李飞刀)
- 拓展编程视界系列 (AlbertLee)
- 【计算机科学课程设置】 (小李飞刀)
- 程序员必读经典书籍 (Felven)
谁读这本书?
喜欢这本书的人常去的小组 · · · · · ·

- Vim (6200)

- LISP (2012)

- Linux (6609)

- Haskell (889)

- O'Reilly爱好者 (2803)

- Python编程 (19004)

- Emacs (2343)

- TAOCP (614)
喜欢这本书的人关注的活动 · · · · · ·
订阅关于C Programming Language的评论:
feed: rss 2.0











