您的位置:首页 > 其它

C Primer Plus 笔记(不断更新)

2015-07-03 15:05 204 查看
第七章: 分支控制

1.while((c=getchar()) != '' && c!= '\n'): 循环读入字符,直到出现第一个空格或者换行符 while(getchar()!='\n') continue 跳过输入行的剩余部分。

2.逻辑表达式是从左到右求值的,一旦发现有使表达式为假的因素,立即停止求值(这点和java是不同的)。比如,if(number !=0 && 12/number ==2),c语言可以保证右边不会出现除0错误。

3.&&和||运算符是序列的分界点。比如while(x++<10 && x+y<20), 在对右边表达式求值之前,先把x的值增加1.

4.用&&来测试范围,比如 if(range>=90 && range <=100), 不要用if(90 <= range <= 100),这种写法没有语法错误,但是有语义错误,因为编译器会解释为(90 <= range) <= 100, 所以最终值总是为真。

5.控制合法输入,读入一个数据,while(scanf("%d",&d)==1),判断两个输入:while(scanf("%f","%f",&length,&width) == 2)

6.break 语句其实是switch语句的附属物

第八章:字符输入输出

1.缓冲分为两类:

完全缓冲:缓冲区满时被清空,通常用于文件传输中,缓冲区块的大小取决于系统

行缓冲: 遇到一个换行字符时将清空缓冲区。键盘输入是标准的行缓冲,因此按下回车键将清空缓冲区。

2.现在的某些文件可能还会以 “Ctrl+z”来标记文件结束,也可能没有(^z)。第二种方式是存储文件的大小信息。

3.在大多数的Unix系统中,在一行的开始键入Ctrl+D会导致传送文件尾信号,可以用如下的方式:#include<stdio.h> while((ch=gechar()) != EOF)

4.令程序与文件一同工作有两种方式:一:明确的使用打开文件等专门的函数 二:重定向:将stdin流(通常是从键盘输入)重新分配至文件。输入重定向能使用文件代替键盘作为输入,输出重定向可以使程序用文件代替屏幕作为输出。

5. < 是Unix,Linux和Dos的重定向运算符。如 a.out < words, 该运算符把words文件与stdin流关联起来,将该文件的内容引导至a.out程序,由于C 将文件和I/O设备至于相同的地位,所以这个文件现在就是I/O设备。

6.使用重定向运算符>和<时,输入不能来自一个以上的文件,输出也不能定向至一个以上的文件

7.其它的运算符: (>>) 使得可以向一个文件的末尾追加数据;管道运算符 (|)可以将第一个程序的输出与第二个程序的输入连接起来

8.getchar()读取每个字符,包括空格,制表符和换行符,scanf()再读取数字式则跳过空格,制表符和换行符。putchar()

9.如果混合使用scanf()和getchar()函数,那么当调用getchar()之前scanf()恰好再输入缓冲中留下一个换行符,因此会产生问题,但是当我们知道了这个问题,可以通过编程手段来避免。

第九章:函数

1.一个函数通常包括三部分:函数原型,告知编译器函数的类型,函数调用,导致函数的执行,函数定义,确切的制定了函数的具体功能

2.在程序中可以把函数原型放在main()之前,也可以放到main()之中,可以放到变量声明的任何位置,这两种方法都是正确的。

3.在函数原型中可以根据您自己的喜好省略变量名,如 void show(char, int)

4.被调用函数使用的值是从调用函数中复制而来的,所以不管在被调用函数中对复制数值进行什么操作,调用函数中的原数值不会收到任何影响。

第十章:数组和指针

1.有关数组初始化:int no_data[size]: 如果不进行数组初始化,则和未初始化的普通变量一样,其中存储的是无用的数值;int some_date[4]={1492,1066},如果部分初始化,则编译器做的很好,多余的数组元素被初始化为0. int some_data[4]={1,2,3,4,5,6},这种初始化列表中项目的个数大于数组的大小,编译器会毫不留情的认为这是一个错误,但是可以用省略括号中的数字的方式来让编译器自动匹配数组大小。int some_data[]={1,2,3,4,5,6}。C99加入了一个新的特性:int days[MONTHS]={32,28,[4]=31,30,31,[1]=29}.有两点需要说明:1.[4]=31,30,31表明不仅days[4]=31,而且days[5]=30,days[6]=31. 2.后面的指定会覆盖前面的指定。

2.为什么C不检查数组边界? 在程序运行前,索引的值可能尚未确定下来,所以编译器此时不能找出所有的索引错误。为保证程序的正确性,编译器必须在运行时添加检查每个索引是否合法的代码,这回导致程序的运行速度减慢。

3.对于二维数组的初始化,也可以省略内部的花括号,只保留最外面的一对花括号,在初始化时,按照先后顺序来逐行赋值,因此前面的元素首先得到赋值,直到没有数值为止。

4.为什么在声明指针的时候必须指明指针指向的数据类型?在C中,对一个指针加1的结果是对该指针增加一个存储单元。对于数组而言,地址会增加到下一个元素的地址,而不是下一个字节。这就是为什么在声明指针时必须声明它所指向对象的类型。计算机需要知道存储对象所用的字节数,所以只有地址信息是不够的。

5.在函数原型中,由于名称可以省略,则下面四种原型是等价的:

a) int sum(int *ar, int n)

b) int sum(int *, int)

c) int sum(int ar[], int n)

d) int sum(int [], int)

在定义函数时,名称是不可以省略的,因此在定义函数时以下两种方式等价:

a) int sum(int *ar, int n)

{

//code

}

b) int sum (int ar[], int n)

{

//code

}

其中,有一点提出的是, 在函数原型和函数定义这两种场合中, int* ar 和 int ar[]是等价的。

6. c中数组和指针的关系允许您在数组符号中使用指针ar。

int sum(int *ar, int n)

{

ar[i] = ...

}

但在这种情况下,sizeof ar 为 4. 即使为

int sum(int ar[], int n)

{

}

这种情况下sizeof ar 任然为4.

然而,如果在定义的区域内查看sizeof,如:

int marbles[10] = {1,2,3,4,5,6,7,8,9,10}

printf("The size of marbles is %zd bytes.\n.", sizeof marbles);

这种情况下,会输出40.(10 * 4)

第12章:存储类,链接和内存管理

1.文件作用域变量有时也被称为全局变量。

2.一个C变量具有下列链接之一:外部链接(external linkage)(static), 内部链接,或空链接。具有代码块作用域或者函数原型作用域的变量具有空链接,以为着他们是由其定义所在的代码块或函数原型所私有的。具有文件作用域的变量可能有内部或者外部链接。一个具有外部链接的变量可以再一个多文件程序的任何地方使用。一个具有内部链接的变量可以在一个文件的任何地方使用。

3.在内层代码块中定义的名字是内层代码块所使用的变量,我们称之为内层定义覆盖(hide)了外部定义,但当运行离开内层代码块时,外部变量重新恢复作用。

4.可能需要 -std=C99来激活编译器的C99支持。

5.在C中,除非显示地初始化自动变量,否则它不会被自动初始化。

6. void trystat() {

int fade = 1;

static int stay = 1;

}

这两个声明看起来很相似,但是第一个语句确实是函数trystat()的一部分,每次调用该函数都会执行它,它是个运行时动作,而第二个语句实际上并不是函数的一部分。静态变量和外部变量在程序调入内存时已经就位了,把这个语句放在函数内部是为了告诉编译器只有函数trystat()可以看到该变量,它不是在运行时执行的语句。

7. 外部变量

1)把变量的定义声明放在所有函数之外,即创建了一个外部变量。

2)在使用外部变量的函数中通过使用extern关键字来再次声明它

3)如果变量实在别的文件中定义的(而不仅仅是在文件头部定义的话),使用extern来声明一下该变量就是必须的。

8. 定义和声明的区别

int tern = 1;

main()

{

external int tern;

...

}

这里tern声明了两次。第一次声明为变量留出了存储空间,构成了变量的定义,称为定义声明

第二次声明只是告诉编译器要使用先前定义的变量tern,因此不是一个定义,为引用声明,关键字extern表明该声明不是一个定义。

9. 一个外部变量只可以进行一次初始化,而且一定是在变量被定义时进行。下面的语句是错误的

extern char permis = 'Y';

10.具有内部链接的静态变量

普通的外部变量可以被程序的任一文件所包含的程序使用,而具有内部链接的静态变量只可以被与它在同一个文件中的函数使用。可以在函数中使用存储类说明符extern来再次声明任何具有文件作用域的变量。这样的声明并不改变链接。

11.除了一个定义声明外,其他所有声明都必须使用关键字extern,并且只有在定义声明中才可以对该变量进行初始化。

12. 函数可以是外部的,静态的或者内联的。与变量类似。

12.将头文件文件名置于双引号而不是非尖括号中,是为了只是编译器在本地寻找文件,而不是到编译器存放标准头文件的标准位置去寻找文件。一些常见的做法是将头文件与源代码文件放在同一个目录或文件夹中,或者与工程文件放在同一个目录或文件夹中。

13.stdlib.h里包括的函数原型:rand(), malloc(),free(),exit()

14.free()只释放它的参数所指向的内存块,如果free()在一个程序的最后然后马上退出的话,没有free()也可以,因为在程序终止后所有已经分配的内存都将会被自动释放。

15.一个理想模型:程序将它的可用内存分为三个独立的部分:一个是具有外部链接的,具有内部链接的以及具有空链接的静态变量的部分;一个是自动变量的部分;一个是动态分配的内存的部分:

1)在编译时就已经知道了静态存储时期存储类变量所需的内存数量,存储在这一部分的数据在整个程序运行时都可用。这一类型的每个变量在程序开始时就已存在,到程序结束时终止。

2)一个自动变量在程序进入包含该变量定义的代码块时产生,在退出这一代码块时终止。因此,伴随程序对函数的调用和终止,自动变量使用的内存数量也在增加和减少。典型的,将这一部分内存处理为一个堆栈。这意味在内存中,新变量在创建时按顺序加入,在消亡时按相反顺序移除。

3)动态分配的内存在调用malloc()或相关函数时产生,在调用free()时释放。由程序员而不是一系列固定的规则控制内存持续时间,因此内存块可以在一个函数中创建,而在另一个函数中释放。由于这点,动态内存分配所用的内存部分可能变成碎片状,也就是说,在活动的内存块之间散布着未使用的字节片。不管怎样,使用动态内存往往导致进程比使用堆栈慢。

16. restrict关键字告诉编译器某个指针是访问它所指向数据块的唯一初始方式,编译器可以放心去寻找计算的捷径。比如合并两次加法。

17. 从宏变成最终的替换文本的过程称为宏展开

18. C编译器在编译时对所有常量表达式(只包含常量的表达式)求值,所以实际相乘过程发生在编译阶段,而不是预处理阶段。预处理器不进行计算,他只是按照指令进行文字替换操作。

19.对于#include。 使用双引号意味着首先搜索本地目录,但是具体搜索那个目录依赖于编译器,有些编译器搜索源代码文件所在目录,有些则搜索当前工作目录,
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: