《C语言程序设计现代方法(第二版)》笔记
NOTE:本笔记仅为个人学习整理,拿出来给大家一起学习!
章节性点:
1.循环(退出循环)
Break:退出switch, while, do, for 等循环;
Continue:退出本次循环,而不是全部;
Goto:跳转到本函数中的任意有标号的语句处,往下执行,注意标号一定在同一个函数内。
2.Exit函数:任何函数都可以调用,Exit(0)和Exit(1)等价于Exit(EXIT_SUCCESS)和 Exit(EXIT_FAILURE);
3.指针
1)如果指针变量p没有初始化,那么对于*p的值是未定义的,尤其是直接给*p赋值,如*p = 1, 因为p可以指向内存的任何地方,所以赋值改变了某些未知的内存单元;
2)对于指针变量p和q,q = &i, p = q: 表示把q所指向的i的地址复制给p,结果使得p与q都指向i的地址,注意与*p = *q的区别;
3)指针作为实参,用实例说明,如下:
void decompose(float x, int *intPart, float *fracPart)
{
*intPart = (int)x;
*fracPart = x - *intPart;
}
对于函数调用:decompose(3.1415, &i, &j), 很明显会改变i与j的值,因为intPart与fracPart是指向i与j的内存单元,修改了内存单元的值,那么i与j显然是会变的。
4)用const保护实际参数:void fun(const *p); 表明函数不会改变传递给函数指 针所指向的对象,只是作为一种检查,而不修改;如果试图修改,编译前会发出特定消 息。
5)指针作为返回值:返回值为内存位置而不是具体的数值。注意:
int *fun(void){int i; ... Return &i;} 永远都不会返回指向自动局部变量的指 针,因为一旦fun返回,变量i就不存在了,指向i的指针将是无效的。
6)指针的高级应用:
(1)内存分配函数:
Malloc函数---分配内存块,但是不对内存块进行初始化;
Calloc函数---分配内存块,并且对内存块进行擦除;
Realloc函数---调整先前分配的内存块;
(2)链表(略);
7)指向函数的指针:
E.g: double integrate(double (*f)(double), double a, double b);
调用为 integrate(sin, 0.0, PI/2), 其中*f周围的括号说明f是个指向函数的指针,而不是函数的返回值为指针。但把f声明成好像就是函数也是合法的,在编译器看来是一样的,即double integrate(double f(double), double a, double b);
4.结构体
1)每个结构都表示一种新的范围。任何声明在此范围内的名字都不会和程序中其他名字冲突;
2)结构变量的初始化,任何用于结构变量的初始化式都必须是常量;
5.程序设计(C++)
1)C++与C相比较的新特性:
(1)支持面向对象的程序设计,通过允许从已经存在的类“派生”出新的类,而不 是从头编写新的类,从而确保更高的代码复用率;
(2)运算符重载,可以给传统的C语言的运算符赋予新的含义,可以定义新的数据 类型,这些新的数据类型甚至与基本数据类型毫无差别,从而扩展编程语言本身;
(3)模板,可以写出通用的、高度可复用的类与函数;
(4)异常处理,一种统一的方式来检测并响应错误;
2)类
(1)运算符重载, E.g:
class Fraction{
public:
...
Fraction operator*(Fraction f);
private:
int numerator ;
int denominator;
...
};
Fraction Fraction :: operator*(Fraction f)
{
Fraction result;
result.numerator = numerator*f.numerator;
result.denominator = denominator*f.denominator;
return result;
}
Fraction f1, f2, f3;
f3 = f1 * f2; 等价于f3 = f1.operator*(f2);
(2)面向对象编程:
封装--具有能够定义新的类型以及一组对这个类型的操作的能力,而不会暴露类型的具体实现;
继承--具有能够定义新的类型,并在新的类型中继承已经存在的类型的属性的能力;
多态性--对于同样的操作,对象能够根据它所属的类采取不同的响应。
(3)派生:E.g:
class shape{
public:
virtual void grow();
void changeColor(int newColor);
void move(int xchange, int ychange);
...
private:
int x, y;
int color;
};
Shape为基类,Circle, Square,...为派生类,每个类都会包含基类中的所有属性,以及它自身所特有的属性,E.g:
class Circle:public Shape{
public:
void grow(){ radius++; }
...
private:
int radius;
};
除了radius, Circle类的对象还会包含成员x, y 和Color(从Shape中继承的);当一个类从另一个类中派生时,C++允许基类的指针指向派生类的实例。例如,Shape*类型的变量可以指向Circle、Square...对象;
Circle c;
Shape *p = &C;
(4)虚函数:通过在上面例子中加上红色字virtual,从而对于不同的派生类中的grow函数,通过指针当前所指向的对象的实际类型,来决定所调用的函数版本。E.g
Shape *p;
Circle c;
Square s;
P = &c; //p points to a Circle
P->grow(); //calls Circle: grow();
p = &s;
P->grow();
虚函数依赖于“动态绑定技术”,由于编译器不能总是能够判断应该调用哪个函数的版本。
(5)模板:构造类所使用的“模式”(暂略)
3)
6.输入输出
1)文件操作:
(1)打开文件: FILE *fopen(const char *filename, const char *mode );需要始终测试fopen的函数返回值,确保文件是打开的;mode的字符串的内容 有:”r”(读), “w”(写), “a”(追加), “r+”(用于读写,从文件头开始), “W+”(用于读写,如果文件存在就截去), “a+”(如果文件存在就追加);
(2)关闭文件: int fclose(FILE *stream);关闭文件成功返回0,失败返回EOF;
(3)为流附加文件: FILE *freopen(const char *filename, const char *mode, FILE *stream);stream参数为stdin, stdout or stderr.
(4)从命令行获取文件名:如果从name.dat, dates.dat中获取文件名,
E.g:
main(int argc, char *argv[])
{
...
}
argc是命令行实际参数的数量,而argv是一个指针数组,数组中的指针都指向实际参数字符串。argv[0]指向程序的名字,从argv[1]到argv[argc - 1]都指向剩余的实际参数,而argv[argc]为空指针;
(5)临时文件: FILE *tmpfile(void); char *tmpnam(char *sptr);
(6)文件缓冲:int fflush(FILE *stream);
int setvbuf(FILE *stream, char *buf, int type, unsigned size);buf为期望缓冲区的地址,type为期望缓冲区的类型:_IOFBF(满缓冲),当缓冲区空,从流写入数据。 或者当缓冲区满,向流写入数据;_IOLBF(行缓冲):每次从流中读入一行数据或者向流中写入一行数据;_IONBF(无缓冲):直接从流中读入数据或者直接向流中写 入数据,而没有缓冲区。
(7)其他文件操作: int remove(const char *filename);
int rename(const char *old, const char *new);
2)格式化的输入与输出
(1)...printf函数
int fprintf(FILE *stream, const char *format,...);
int printf(const char *format,...);
(2)...scanf类
Int fscanf(FILE *stream, const char *format,...);
Int scanf(const char *format,...);
3)字符的输入输出:
(1)输出函数:
int fputc(int c, FILE *stream);
int putc(int c, FILE *stream);
int putchar(int c);
(2)输入函数:
int fgetc(FILE *stream);
int getc(FILE *stream);
int getchar(void);
int ungetc(int c ,FILE *stream);
4)行的输入输出函数:
(1)输出:
int fputs(const char *s, FILE *stream);
int puts(const char *s);
(2)输入:
char *fgets(char *s, int n, FILE *stream);
char *gets(char *s);
5)块的输入输出:
Size_t fread(void *ptr, size_t size, size_t nmeb, FILE *stream);
Size_t fwrite(const void*ptr,size_t size,size_t nmeb,FILE *stream);
6)文件的定位:
int fseek(FILE*stream, long offset, int fromwhere);
long ftell(FILE *stream);
int fgetpos(FILE *stream, fpos_t *filepos);
7)字符串的输入输出:
int sprintf(char *s, const char *format, ...);
Int sscanf(const char *s, const char *format,...);
7.其他库函数(略);