读书笔记之:C/C++程序员实用大全—C/C++最佳编程指南

这本书中列出了31章共1500个知识点,带有很多的例子。本书适合对C/C++有一些了解的程序员进行查缺补漏。因为这里边对知识点的讲解比较凌乱不是很条理,前面的内容有时就用到了后面内容,如果你不是了解的话,读起来就比较困难了。

本书还有一个很大的特点是很多地方是针对Dos 平台的,我是使用的linux,所以有很多地方是不适合的。即便是对于windows 平台,有些地方可能也不适用了。因为这本书还是比较老的。有些不需要的地方可以跳过。关于C++的介绍,如果你是刚刚学C++话还是要先读《C++ Primer》,那本书比较条理,可以让你理清关系。了解各个知识点。

书最后的关于Windows编程的部分我基本没有看,因为相对来说知识比较旧了,并且我是Linux平台的。

 第1章 C语言入门

1. 许多C编译器把%i格式符等价于%d。最好使用%d,因为%i是一个比较陈旧的格式符,以后的编译器可能不支持它。

%ld可以来显示长整型

%e 科学计数法显示浮点数

%g 根据实际情况自行选择使用%f还是%e来显示浮点数

显示数值正负号:在格式符中紧跟%后添加一个+号即可。如%+d,%+f

%05d 其中5用来表示显示数值时所采用的最少的字符数目,0表示使用0填充,

%8.3f表示共至少8位,其中小数点后保留3位

%-5d 左对齐

2. 为了引导printf在八进制或十六进制前添加合适的前缀,可紧跟格式符号%后置入#。如:

printf("value is %#x\n",value);

3. 判断printf已经显示的字符数目

当程序作复杂的屏幕格式化时,有时需要知道printf已经显示的字符数目,可以使用%n

如:printf("abd%n 123456%n\n",&a,&b);

执行完之后a=3,b=10

printf的返回值是已经输出的字符总数

4.ANSI设备驱动器

 

第2章 宏与常量

1. 预定义宏

__FILE__ __LINE__ __DATE__ __TIME__

__STDC__用来判断是否是ANSI C编译器

2.改变与处理器行计数

利用#line预处理来改变行号

如:#line 100 "FILENAME.c" //表示当前行为100行,下面如果出现__LINE__的话,是从现在开始计数的

 

第3章 字符串

1. C中常用的字符处理函数

#include <ctype.h>

int isalnum(int c);

int isalpha(int c);

int iscntrl(int c);

int isascii(int c);

#include <ctype.h>

int isdigit(int c);

int isodigit(int c);

int isxdigit(int c);

#include <ctype.h>

int isgraph(int c);

int ispunct(int c);

int isprint(char c);

#include <ctype.h>

int islower(int c);

int isupper(int c);

#include <ctype.h>

int isblank(int c);

int isspace(int c);

ing iswhite(int c);

#include <ctype.h>

int tolower(int c);

int toupper(int c);

 

2. 常用的字符串处理函数

#include <string.h>

char* strcat(char*dest,const char*src);

char* strncat(char*dest,const char*src,size_t n);

#include <string.h>

int strcmp(const char *s1,const char *s2);

int strncmp(const char *s1,const char *s2,size_t n);

#include <string.h>

size_t strlen(const char*s);

#include <string.h>

char*strstr(const char*src,cosnt char*sub);

char*strtok(char* str,const char*set);

#include <string.h>

char *strchr(const char*s,int c);

char *strrchr(const char*s,int c);

#include <stdlib.h>

double strtod(const char *nptr, char **endptr);

float strtof(const char *nptr, char **endptr);

long double strtold(const char *nptr, char **endptr);

#include <stdlib.h>

double atof(const char*str);

int atoi(const char*str);

long atol(const char*str);

long long atoll(const char*str);

#include <string.h>

char* strcpy(char*dest,const char*src);

char* strncpy(char*dest,const char*src,size_t n);

#include <string.h>

int strcoll(const char*s1,const char*s2);

size_t strxfrm(char *dest,const char*src,size_t len);

#include <string.h>

size_t strspn(const char*s,cosnt char*set);

size_t strcspn(const char*s,cosnt char*set);

char* strpbrk(const char*s,const char*set);

 

第4章 函数

1. 在C语言中,如果用户自定义的函数名称和库函数的名称是一样的,那么编译器一般会选择使用用户定义的函数。

堆栈的基本目的就是用来支持函数调用的。函数调用的时候,编译器会将返回地址和参数压入堆栈。

程序员将计算机用来压入和弹出堆栈所花费的时间成为函数的开销。

2. volatile关键字

3. 与堆栈相关:调用结构和基指针

4. 支持参数个数可变的函数

为了支持参数可变,在C中是使用宏va_arg,va_end和va_start(在头文件stdarg.h中定义)引导程序创建自己的支持参数个数可变的函数。实质上是宏每次从堆栈中取得参数,一直到程序获取最后一个参数。使用这些宏获取参数时,必须知道每个参数的类型。在printf这个最典型的不定参数个数函数中使用标识符(如%d,%s,%f)来匹配参数类型。

可以使用类似printf中使用的格式符将参数类型传递给函数:

result=add_values("%d %d %d",1,2,3);

 

第5章 键盘操作

1.

#include <stdio.h>

int fgetc(FILE *stream);

char *fgets(char *s, int size, FILE *stream);

int getc(FILE *stream);

int getchar(void);

char *gets(char *s);

int ungetc(int c, FILE *stream);

上面几个函数的关系:

fgetc()是从stream中读取下一个字符串,然后返回,

getc和fgetc是等价的,只不过它是用宏实现的。

getchar()等价于getc(stdin)

 

gets()是从stdin读入多个字符到缓冲s中,知道遇到行终结符,并且在s中使用'\0'代替终结符

第6章 数学

1. 获得浮点数的尾数和指数

可以使用frexp函数来获得浮点数的指数和尾数

#include <math.h>

double frexp(double value,int *exponent);

其中返回值是位数,第二个参数是指数

 

类型float大小为4字节,即32位,内存中的存储方式如下:

高地址<-------------------------------------->低地址

| 符号位 | 指数 | 尾数 |

| 1 bit | 8 bit | 23 bit |

31<------>30<--------->22<---------------------->0

 

类型double大小为8字节,即64位,内存布局如下:

高地址<---------------------------------------->低地址

| 符号位 | 指数 | 尾数 |

| 1 bit | 11 bit | 52 bit |

63<------>62<------------>51<--------------------->0

 

2. 计算X*2E的结果

可以使用ldexp函数来计算x*2e

#include <math.h>

double ldexp(double value,int exponent);

3. 在文件stdlib.h提供了宏min和max

4. 把浮点值分解成整数和小数部分

使用modf函数来把浮点数分解成整数和小数部分。

#include <math.h>

double modf(double value,double *integer_part);

5. #include <math.h>

double pow(double value,double power);

double pow10(int power);

 

double log(double value);

double log10(double value);

6.生成随机数

C中提供的生成随机数函数:rand和random,它们两个都返回整型随机数。

#include <stdlib.h>

int rand(void);

int random(int ceiling);

rand返回一个范围在0和RAND_MAX之间的随机整数。第二个函数random返回一个范围0与ceiling之间的随机数,ceiling规定了随机数的最大值,主调函数把它传递给random函数。

 

第7章 文件、目录和磁盘

1. FILE结构

C中进行文件流操作的FILE是一个结构体,一般使用FILE*指针。

通常是使用fopen函数返回一个FILE*指针。

大体的FILE的结构格式如下:

2. 使用低级和高级文件I/O

其实高级I/O就是我们常用的基于流的文件功能。而所谓的低级文件I/O就是一些系统调用。上面所列出的函数都是一些系统调用,不同的系统的实现是不一样的。这儿其实就是一个"库函数与系统调用关系"的问题。

3、已知文件流指针,获取对应的文件描述符

int fileno(FILE *stream);

主要应用:如果程序先前用fopen打开了一个文件,但是又想对其进行锁定操作,

例如 int fcntl(int fildes, int command, struct flock *flock_structure)(注意:command为F_GETLK, F_SETLK, F_SETLKW中其中一者)

或者 int lockf(int fd, int cmd, off_t len),就得先用fileno得到对应的文件描述符后再进行fcntl/lockf操作。

4、已知文件描述符,获取对应的文件流指针

FILE *fdopen(int fildes, const char *type);

将一个文件流关联到一个打开的文件描述符

fildes可以是open,dup, dup2, creat, pipe, socket等系统调用返回的结果。

type指定打开的方式,同fopen的"r","w","a"等等。

fdopen的打开方式受制于fildes的打开方式,例如:open时用O_RDONLY,那么fdopen就只能用"r"方式。

主要应用:当你不得不只能打开文件号,但却想用fprintf,fscanf等流操作进行数据读写时,就再用fdopen一次便可。

5. 重命名文件

C中给出了函数rename可以来进行文件的重命名或移动

#include <stdio.h>

int rename(const char *old, const char *new);

6. 删除文件

C库函数中给出了remove函数来删除文件

#include <stdio.h>

int remove(const char *pathname);

同时在unix操作系统中还提供了函数来删除文件

#include <unistd.h>

int unlink(const char *path);

7. 判断程序如何访问文件

C函数access检查指定文件是否存在,以及用户是否能按要求打开文件。

这个一般是操作系统提供实现方式。

8.将缓冲写入磁盘

C中提供函数fflush将缓存中的数据写入到磁盘中去。

#include <stdio.h>

int fflush(FILE *stream);

9. 获取文件流的文件句柄

#include <stdio.h>

int fileno(FILE *stream);

10. 临时文件C接口

如果在C程序中碰到文本处理,极有可能会涉及到临时文件的处理。

在不同情境下,可能对临时文件接口有不同的需求。比如有时只是将临时文件作为临时的数据存储空间,无需与其它进程共享,这时可以直接使用tmpfile()函数。tmpfile()返回的是一个FILE *句柄,由tmpfile()创建的临时文件没有实际的文件名,这样处理的好处是,当程序结束时,文件不需要程序手动删除。

但如果你需要与其它进程共享临时文件,或是需要以临时文件的文件名作为参数调用其它程序以传递数据,tmpfile()就不能胜任了,这时就需要用到mkstemp()。mkstemp()通过传入的模板字符串生成一个不存在的文件名,同时创建该文件,将文件句柄做为函数返回值返回,而文件名可以从被修改了的模板字符串中得到。

以上两个函数算是比较现代的了,如果对于历史感兴趣,可以看看下面三个函数。

mktemp()函数用于生成一个不存在的文件名。这个函数现在已经不提倡使用,在POSIX.1-2008中甚至已经将其删除了。从glibc mktemp(3)中可以了解到,不提倡使用mktemp()的主要原因是mktemp()只是生成一个当前不存在的文件名,而没有直接创建该文件。而如果需要创建这个文件,那么在mktemp()和creat()之间可能这个临时文件被其它进程创建,从而导致文件创建失败。

tmpnam()函数有与mktemp()一样的问题,同时,当传入参数为NULL时,由于需要用到static变量,所以不是线程安全的。在POSIX.1-2008中已经不建议使用。

tempnam()与tmpnam()相似,只是参数更多,可控性更高。同样,在POSIX.1-2008中已不建议使用。

11. 每次读写一个字

C中提供了函数getw和putw来读写一个字

#include <stdio.h>

int getw(FILE *stream);

int putw(int w, FILE *stream);

 

12. 读写结构体

低级的read和write函数

高级fread和fwrite函数都可以进行结构体读写

13. 把文件句柄和文件流联系起来

可以使用fdopen函数来晶文件句柄和文件流联系起来:

#include <stdio.h>

FILE *fdopen(int fd, const char *mode);

14. 目录操作

打开目录:opendir

读取目录:readdir

重置目录列表:rewinddir

 

15. 按行读取和写文本

使用函数fgets和fputs

 

16. 为什么不能使用fgets和fputs来复制二进制文件

因为在fgets函数在读取文本时,fgets把CTRL+Z(ASCII值为26)当作文件结尾。因为二进制文件中很可能多次出现数值26,fgets将在第一次遇到26时就结束拷贝过程。所以要想可靠的拷贝二进制文件的话,必须使用C 的低级I/O函数。

17. 判断文件结尾

当fgets函数遇到文件结尾时,它返回NULL,同样当fgetc遇到文件结尾时返回EOF。所以在程序进行某些特定操作之前,很有必要判断文件指针是否处于文件尾端。一般使用函数feof。

#include <stdio.h>

int feof(FILE *stream);

18. 获取文件句柄信息

#include <sys/types.h>

#include <sys/stat.h>

#include <unistd.h>

int stat(const char *path, struct stat *buf);

int fstat(int fd, struct stat *buf);

int lstat(const char *path, struct stat *buf);

stat结构体

struct stat {

dev_t st_dev; /* ID of device containing file */

ino_t st_ino; /* inode number */

mode_t st_mode; /* protection */

nlink_t st_nlink; /* number of hard links */

uid_t st_uid; /* user ID of owner */

gid_t st_gid; /* group ID of owner */

dev_t st_rdev; /* device ID (if special file) */

off_t st_size; /* total size, in bytes */

blksize_t st_blksize; /* blocksize for file system I/O */

blkcnt_t st_blocks; /* number of 512B blocks allocated */

time_t st_atime; /* time of last access */

time_t st_mtime; /* time of last modification */

time_t st_ctime; /* time of last status change */

};

 

 

posted @ 2012-03-30 16:49  Mr.Rico  阅读(...)  评论(...编辑  收藏