《C程序设计语言》读书笔记

第二章《类型,运算符与表达式》
1,变量名由字母,数字,下划线组成,数字不能开头。名字尽量表达变量意义。
2,int通常代表特定机器中整数的自然长度。
3,'/0'表示值为0的字符,也就是空字符null,其数字值为0.
4,字符串常量就是字符串数组,用'/0'结束,因此存储字符串的物理存储单元比双引号中字符数
多一个。
5,计算字符常量函数strlen的核心代码是while(s!='/0'){++i;}.所以strlen是依靠'/0'
计算字符串长度的。
6,默认情况下,外部变量,和静态变量将被初始化为0,未经显示初始化的自动变量的值为未定义
值。
7,const限定符指定的元素不能被更改,可理解为只读。对数组而言,const限定符指定数组所有元素的值不能被修改。如 int strlen(const char[])表明函数不能修改数组元素的值。
8,自增与自减运算符只能作用于变量,类似于表达式(i+j)++是非法的。
9,+= , *= 为赋值运算符。例如:x *= y + 1 的含义是x = x * (y + 1)而不是 x = x * y + 1。
10,条件表达式expr1 ? expr2 : expr3首先计算expr1,如果其值不等于0(为真),则计算
expr2的值,并以该值作为条件表达式的值。否则,计算expr3的值,并以该值为表达式的值。
11,理解记忆运算符优先级与求值顺序。

第三章《流控制》
1,if语句有嵌套的情况下应该使用括号。
2,switch语句中,case的作用只是一个标号,因此,某个分支中的代码执行完后,程序将进入下一个分支继续执行。除非在程序中使用break或return显式跳转。
3,break从循环语句中跳出,continue执行下一次循环。
4,goto语句一般做出错处理。


第四章 《函数与程序结构》
1,c语言一般有许多小的函数组成,而不是少量较大函数组成。一个程序可以保存在一个或多个源文件中,各个文件可以单独编译,并可以与库中已编译过的函数一起加载。
2,函数定义形式如下:
       返回值类型 函数名(函数声明表)
      {
           声明和语句
       }
  函数定义的各构成部分都可以省略。最简单函数 dummy(){},如果函数中省略了返回值类型,  则默认为int类型
3,只要保证每一个函数不被分离到多个文件中,源程序就可以分成多个文件。
4,外部变量的利弊,外部变量可以在全局访问,如果函数之间共享大量的变量,使用外部变量比使用很长的参数表更方便,有效。但可能对结构产生不良影响。
5,自动变量只能在函数内部使用,从其所在的函数被调用时变量开始存在,在函数退出时变量将消失。而外部变量是永久存在的,它们的值在一次函数调用到下一次函数调用之间保持不变。
6,外部变量或函数的作用域从声明它的地方开始,到其所在的(待编译的)文件的末尾结束。
7,函数外部的static修饰变量或函数,则该变量或函数只对该文件可见,其他文件无法访问。static类型的内部变量是一种只能在某个特定函数中使用但一直占据存储空间的变量。
8,(#define 名字 替换文本) 后续所有出现名字记号的地方都将被替换为替换文本。


第五章《指针与数组》
1,指针是一种保持变量地址的变量。ANSI C使用类型void *(指向void的指针)代替char *作为通用指针的类型。
2,一元运算符&可用于取一个对象的地址。如 p = &c; 地址运算符&只能应用于内存中的对象,
即变量和数组元素。它不能作用于表达式,常量或register类型的变量。
3,每个指针必须指向某种特定的数据结构(一个例外情况是指向void类型的指针可以存放指向任
何类型的指针,但它不能间接引用其自身)。
4,根据定义,数组类型的变量或表达式的值是该数组第0个元素的地址。因此pa = &a[0]可以写
成 pa = a;
5,计算数组元素a的值时,c语言实际上先将其转换为*(a + i)的形式,然后再进行求职。
6,数组名和指针之间有一个不同之处,指针是一个变量,因此,pa = a和pa++都是合法的。当数
组名不是变量,因此,类似于 a = pa和a++形式的语句是非法的。
7,当把数组名传递给一个函数时,实际传递的是该数组第一个元素的地址。因此,数组名参数必
须是一个指针,也就是一个存储地址值的变量。函数定义中,形式参数 char s[] 和 char *s是等价的。
8,指针初始化只能是0或者是表示地址的表达式,对后者来说,表达式所代表的地址必须是在此前
已定义的具有合适数据类型的地址。
9,指针和整数之间不能相互转换,但0是唯一的例外,常数0可以赋值给指针,指针也可以和常数0
进行比较。程序中经常用符号常量NULL代替常量0,这样便于更清晰地说明常量0是指针的一个特殊值。
10,指针可以和整数进行相加或相减运算。例如p + n,在计算p + n时,n将根据p指向的对象的
长度按比例缩放,而p指向的对象取决于p的声明。例如,如果int类型占4个字节的存储空间,那么int类型的计算中,对应的n将按4的倍数来计算。
11,指向相同数组中元素的俩个指针可进行减法或比较运算。
12,不经强制类型转换而直接将指向一种类型对象的指针赋值给另一个类型对象的指针运算是非法
的。(俩个指针之一是void *类型的情况除外)
13, char amessage[] = "nw is the time"; /* 定义一个数组 */
        char *pmessage = "now is the time"; /* 定义一个指针 */
     上述声明中,amessage是一个仅仅足以存放初始化字符串及空字符'/0'的一维数组。数组中
单个字符可以进行修改,但amessage始终指向同一个存储位置。另一方面,pmessage是一个指针,其初值指向一个字符串常量,之后它可以被修改以指向其他地址,当如果试图修改字符串的内容,结果是没有定义的。
14,字符串复制函数,漂亮的strcpy写法。
void strcpy(char *s,char *t)
{
  while(*s++ = *t++)
  ;
}
15,指针数组,由于指针本身也是变量,所以它们也可以像其它变量一样存储在数组中。如:char *lineptr[MAXLINES]表示lineptr是一个具有MAXLINES个元素的一维数组,其中数组的每个元素是一个指向字符类型对象的指针。
16,多维数组做函数参数传递时,除数组的第一维下标可以不指定大小外,其余各维都必须明确指定大小。
17,指针与多维数组
  int a[10][20]
  int *b[10]
a是一个真正的二维数组,它分配了200个int类型长度的存储空间。对b来说,该定义仅仅分配了10个指针,并且没有对它们初始化,它们的初始化必须以显示的方式进行。
18,在支持c语言的环境中,可以在程序开始执行时将命令行参数传递给程序。调用主函数main时,它带有俩个参数。第一个参数(习惯上称为argc,用于参数计数)的值表示运行程序时命令行中参数的数目;第二个参数(称为argv,用于参数向量)是一个指向字符串数组的指针,其中每个字符串对应一个参数。如: echo hello world ,argc的值为3,argv[0],argv[1],argv[2]的值分别为“echo”,“hello”,“world”。注意:argv[0]的值是启动该程序的程序名。而argv[argc]为0.
19,在c语言中,函数本身不是变量,当可以定义指向函数的指针。这种类型的指针可以被赋值,存放在数组中,传递给函数以及作为函数的返回值等等。如:int (*comp)(void *,void *)中的comp是一个指向函数的指针。在tvsample中的vopot对应程序中,使用了函数指针数组完成了编号对应函数的功能,算是本部分知识在工作中应用的一个体现,有兴趣的同事可以参考。


第六章《结构》
1,结构是一个或多个变量的集合,这些变量可能为不同的类型,为了处理的方便而将这些变量组织在一个名字之下。由于结构将一组相关的变量看做一个单元而不是各自独立的实体,因此结构有助于组织复杂的数据,特别是在大型的程序中。
2,struct point{
      int x;
      int y;
};
关键字struct引入结构声明。结构声明由包含在花括号内的一系列声明组成。关键字struct后面的名字是可选的,称为结构标记(这里是point)。结构标记用于为结构命名,在定义之后,结构标记就代表花括号内的声明,可以用它作为该声明的简写形式。
3,定义结构体。方法一:struct {……}x,y,z;方法二:struct point x,y,z;
4,c语言提供了一个编译时(compile-time)一元运算符sizeof,它可用来计算任一对像的长度。表达式 sizeof 对象 以及 sizeof(类型名)将返回一个整形值,它等于指定对象或类型占用的存储空间字节数。
5,条件编译语句#if中不能使用sizeof,因为预处理器不对类型名进行分析。但预处理器并不计算#define语句中的表达式,因此,在#define中使用sizeof是合法的。
6,不要认为结构的长度等于各成员长度的和。因为不同的对象有不同的对齐要求,所以,结构中可能会出现未命名的“空穴”(hole0).例如,假设char类型占用一个字节,int 类型占用4个字节,则下列结构:
   struct{
      char c;
      int i;
   }
可能需要8个字节的存储空间,而不是5个字节。使用sizeof运算符可以返回正确的对象长度。
7,在c语言中,将malloc的返回值声明为一个指向void类型的指针,然后再显式地将该指针强制转换为所需类型。如:(int *)malloc(sizeof(int));
8,c语言提供了一个称为typedef的功能,它用来建立新的数据类型名,例如,声明 typedef int
Length;将Length定义为与int具有同等意义的名字。类型Length可用于类型声明,类型转换等,它和类型int完全相同。又如:typedef char* String。
9,从任何意义上讲,typedef声明并没有创建一个新类型,它只是为某个已存在的类型增加一个新的名称而已。typedef声明也没有增加任何新的语义:通过这种方式声明的变量与通过普通声明方式声明的变量具有完全相同的属性。
10,实际上,typedef类似于#define语句,但由于typedef是由编译器解释的,因此它的文本替换功能要超过预处理器的能力。例如:typedef int (*PEI)(char *,char *);该语句定义了类型PEI是“一个指向函数的指针,该函数具有俩个char *类型的参数,返回值类型为int”
11.实际上,联合(union)就是一个结构,它的所有成员相对于基地址的偏移量都为0。


第七章《输入与输出》
1,输入/输出功能并不是c语言本身的组成部分,标准库提供了输入/输出函数,字符串处理函数,存储管理函数与数学函数,以及其它一些c语言程序的功能。
2,getchar函数在每次被调用时返回下一个输入字符。在许多环境中,可以使用符号 < 来实现输入重定向,它将把键盘输入替换为文件输入:如果程序prog中使用了函数getchar,则命令行
prog < infile 将使用程序prog从输入文件infile(而不是键盘)中读取字符。
3,如果输入通过管道机制来自于另一个程序,那么这种输入切换也是不可见的。比如,在某些系统中,下列命令行: otherprog | prog 将运行来个程序otherprog 和 prog,并将程序otherprog的标准输出通过管道重定向到程序prog的标准输入上。同理可以理解标准库函数putchar。
4,使用输入/输出库函数的每个源程序文件必须在引用这些函数之前包含下列语句:#include<stdio.h>当文件名用一对尖括号<和>括起来时,预处理器将在由具体实现定义的有关位置中查找指定的文件(例如,在UNIX系统中,文件一般放在目录/usr/include中)。
5,输出函数printf将内部数值转换为字符的形式。int printf(char *format,arg1,arg2,……);函数printf在输出格式format的控制下,将其参数进行转换与格式化,并在标准输出设备上打印出来。它的返回值为打印的字符数。每个转换说明由一个百分号字符(即%)开始,并以一个转换字符结束。同理理解标准库函数scanf。
6,在读写一个文件之前,必须通过库函数fopen打开该文件。fopen用类似于x.c或y.c这样的外部名与操作系统进行某些必要的连接和通信,并返回一个随后可以用于文件读写操作的指针。该指针称为文件指针,它指向一个包含文件信息的结构,这些信息包括:缓冲区的位置,缓冲区中当前字符的位置,文件的读或写状态,是否出错或是否已经到达文件结尾等。
7,在<stdio.h>中定义了包含相关信息的结构FILE:如:
   FILE *fp;
   FILE *fopen(char *name,char *mode);
   fp是一个指向结构FILE的指针,fopen函数返回一个指向结构FILE的指针。FILE像int一样是一个类型名,而不是结构标记。它是通过typedef定义的。fopen的第一个参数是一个字符串,它包含文件名。第二个参数是访问模式,用于指定文件的使用方式。容许的模式包括:读(“r”),写(“w”)及追加(“a”)。某些系统还区分文本文件和二进制文件,对后者的访问需要在模式字符串中增加“b”。
8,getc函数从文件中返回一个字符,int getc(FILE *fp)如到达文件尾或出现错误,该函数返回EOF(EOF是一个标识符,通常值为-1)。putc是一个输出函数,int putc(int c,FILE *fp)该函数将字符c写入到fp指向的文件中,并返回写入的字符,如发生错误,则返回EOF。
9,getchar和putchar函数可以通过getc,putc,stdin,stdout定义如下:
   #define getchar() getc(stdin)
   #define putchar() putc((c),stdout)
   stdin与stdout都是FILE *类型的对象。但它们是常量,而非变量。因此不能对它们赋值。
10,int fclose(FILE *fp)负责断开由fopen函数建立的文件指针和外部名之间的连接,并释放文件指针。对输出文件执行fclose,它将把缓存区中由putc函数正在收集的输出写到文件中。
11,stdrr标准错误,即使对标准输出进行了重定向,写到stderr中的输出通常也会显示在屏幕上。
12,行输入 char *fgets(char *line,int maxline,FILE *fp) 读入一行写入字符串数组line把‘/n’替换为‘/0’。如发生错误,返回NULL。  行输出 int fputs(char *line,FILE *fp)将一个字符串(不需要包含换行符)写入到一个文件中。如发生错误,返回EOF。
13,了解一些其他的标准库函数。字符操作函数(strcat,strcpy,strcmp,strchar,strlen);字符类别测试和转换函数(isalpha,isupper,islower,isdigit,isalnum,isspace,toupper,tolower);命令执行函数system(char *s) 如:unix系统中的小例子system(”data“);存储管理函数void *malloc(size_t n),void *calloc(size_t n,size_t size),free();及一些常用的数学函数。

第八章《UNIX系统接口》
1,UNIX操作系统通过一系列的程序调用提供服务,这些系统调用实际上是操作系统内的函数,它们可以被用户程序调用。ANSI C 标准函数库是以UNIX系统为基础建立起来的,学习本章有助于更好地理解标准库。
2,在UNIX操作系统中,所有的外围设备(包括键盘和显示器)都被看作是文件系统中的文件,因此,所有的输入/输出都要通过读文件或写文件完成。也就是说,通过一个单一的接口就可以处理外围设备和程序之间的所有通信。
3,在读写文件之前,将这个意图通知系统,该过程称为打开文件。系统检查你的权利(该文件是否存在?是否有访问它的权限?),如一切正常,操作系统将向程序返回一个小的非负整数,该整数称为文件描述符。任何时候对文件的输入/输出都是通过文件描述符标识文件,而不是通过文件名标识文件。(文件描述符类似于标准库中的文件指针或MS-DOS中的文件句柄。)系统负责维护已打开文件的所有信息,用户程序只能通过文件描述符引用文件。
4,因为大多数的输入/输出是通过键盘和显示器来实现的,为了方便起见,UNIX对此做了特别的安排。当命令解释程序(即”shell“)运行一个程序的时候,它将打开3个文件,对应的文件描述符分别为0,1,2,依次表示标准输入,标准输出和标准错误。如果程序从文件0中读,对1和2进行写,就可以进行输入/输出而不必关心打开文件的问题。
5,程序的使用者可通过<和>重定向程序的I/O:prog < 输入文件名 > 输出文件名,这种情况下,shell把文件描述符0和1的默认赋值改变为指定的文件。通常,文件描述符2仍与显示器相关联,这样,出错信息会输出到显示器上。与管道相关的输入/输出也有类似的特性。在任何情况下,文件赋值的改变都不是由程序完成的,而是由shell完成的。只要程序使用文件0作为输入,文件1和2作为输出和,它就不知道程序的输入从哪里来,并输出到哪里去。
6,输入和输出通过read和write系统调用实现的。在这俩个函数中,第一个参数是文件描述符,第二个参数是程序中存放读或写的数据的字符数组,第三个参数是要传输的字节数。
   int n_read = read(int fd, char *buf, int n);
   int n_written = write(int fd, char *buf, int n);
   每个调用返回实际传输的字节数。在读文件时,函数的返回值可能会小于请求的字节数。如果返回值为0,则表示已到达文件的结尾;如果返回值为-1,则表示发生了某种错误。在写文件时,返回值是实际写入的字节数。如果返回值与请求写入的字节数不相等,则说明发生了错误。在一次调用中,读出或写入的数据的字节数可以为任意大小。用更大的值调用该函数可以获得更高的效率,因为系统调用的次数减少了。
7,用read系统调用实现getchar函数
#include<syscalls.h>
int getchar(void)
{
   char c;
   return (read(0,&c,1) == 1) ? (unsigned char) c : EOF;
}
8,除了默认的标准输入,标准输出和标准错误文件外,其它文件必须在读或写之前显示的打开。系统调用open和creat用于实现该功能。open与第七章讨论的fopen相似,不同的是,前者返回一个文件描述符,它仅仅是一个int类型的数字。而后者返回一个文件指针。如发生错误,open将返回-1.
  int fd;
  int open(char *name, int flags, int perms)
  与fopen一样,参数name是一个包含文件名的字符串。第二个参数flags是一个int类型的值,它说明以何种方式打开文件。(O_RDONLY(只读),O_WRONLY(只写),O_RDWR(读写))
9,在unix文件系统中,每个文件对应一个9比特的权限信息,它们分别控制文件的所有者,所有者组合其它成员对文件的读,写和执行访问。创建文件 int creat(char *name, int perms);perms代表权限,如:可用0755代表所有者可以读写执行,而所有者组合其它成员只能进行读和执行操作。
10,输入/输出通常是顺序进行的:每次调用read和write进行读写的位置紧跟在前一次操作的位置之后。lseek可以在文件中任意移动位置而不实际读写任何数据:long lseek(int fd,long offset,int origin);将文件描述符为fd的文件的当前位置设置为offset,其中,offset是相对于orgin指定的位置而言的。随后进行的读写操作将从此位置开始,origin的值可以为0,1,2,分别用于自动offset从文件开始,从当前位置或从文件结束处开始算起。lseek系统调用返回一个long类型的值,此值表示文件的新位置,若发生错误,则返回-1。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值