[置顶] 《C语言程序设计现代方法第二版》笔记(Part.1)

时间:2021-07-13 23:36:32

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)对于指针变量pq,q = &i, p = q: 表示把q所指向的i的地址复制给p,结果使得pq都指向i的地址,注意与*p = *q的区别;

3)指针作为实参,用实例说明,如下:

void decompose(float x, int *intPart, float *fracPart)

{

*intPart = (int)x;

*fracPart = x - *intPart;

}

对于函数调用:decompose(3.1415, &i, &j), 很明显会改变ij的值,因为intPartfracPart是指向ij的内存单元,修改了内存单元的值,那么ij显然是会变的。

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*类型的变量可以指向CircleSquare...对象;

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.其他库函数()