最近,一边在改paper,一边快速的翻看了一下《C程序设计语言》,记录了一下读书的笔记,文末附有其他人的读书笔记,对比起来,相差甚远,惭愧!
第一章
字符输入/输出
getchar();//通常通过键盘输入
putchar();
'c'和"c"不同,后者多个'\0'
在复制文件内容时,可以使用getchar();
#include <stdio.h>
/* 将输入复制到数出 */
main()
{
int c;
while ((c = getchar()) != EOF) //学这种写法,在Linux那本书很多这种写法
putchar(c);
}
书里面有一句:在C语言,所有函数参数都是“通过值”传递的。
第二章
extern声明:单独放在一个头文件声明。
分清楚"定义"和"声明"
枚举常量
enum boolean {NO, YES};
任何变量的声明都可以使用const限定符限定,该指定的变量的值不能修改。
.c文件 -- 编译 --> .o文件 -- 加载(链接)--> a.out
cc main.c getline.c strindex.c
//编译这3个文件,并把生成的目标代码分别存放在文件main.o getline.o strindex.o中,然后再把这3个文件一起加载到可执行文件a.out
cc main.c getline.o strindex.o
//对main.c进行修改后,可对main.c重新编译,和之前两个.o文件一起加载到可执行文件
逆波兰表示法:用栈来实现
第四章
外部变量
构成C语言程序的函数与外部变量可以分开进行编译。一个程序可以存放在几个文件中,原先已编译的函数可以从库中进行加载。注意几个问题:
- 如何进行声明才能确保变量在编译时被正确声明?
- 如何安排声明的位置才能确保程序在加载时各部分能正确连接?
- 如何组织程序中的声明才能确保只有一份副本?
- 如何初始化外部变量?
如果要在外部变量定义之前使用该变量,或者外部变量的定义与变量的使用不在同一个源文件中,则必须在相应的变量声明中强制性地使用关键字extern
在一个源程序的所有源文件中,一个外部变量只能在某个文件中定义一次,而其他文件可以通过extern声明来访问它(定义外部变量的源文件中也可以包含对给外部变量的extern声明)
Ex1:
//file1
extern int sp;
extern double val[];
...
//file2
int sp = 0;
double val[MAXVAL];
Ex2:
//file1
extern int sp;
extern double val[];
...
int sp = 0;
double val[MAXVAL];
静态变量
用static声明限定外部变量与函数,可以将其后声明的对象的作用域限定为被编译源文件的剩余部分。
static的作用??
寄存器变量
register声明告诉编译器,它所声明的变量在程序中使用频率较高。其思想是,将register变量放在机器的寄存器中,这样可以使程序更小,执行速度更快。
递归
递归实现快速排序
C预处理器
- 文件包含
#include "文件名"
#include <文件名>
- 宏定义 (注意宏定义的使用,例如要记得加括号)
#define 名字 替换文本
//替换文本是任意的,如下:
#define MAXVAL 100
#define forever for(;;) /*无限循环*/
#define MAX(A,B) ((A) > (B) ? (A) : (B)) /*看着像函数,实际只是起文本替换作用*/
- 注意
#undef getchar //取消getchar宏定义
//为了保证hdr.h文件的内容只被包含一次
#if !define(HDR) or #ifndef HDR
#define HDR
/* hdr.h文件的内容放在这里 */
#endif
//先测试系统是哪个版本的,引入对应的头文件
#if SYSTEM == SYSV
#define HDR "sysv.h"
#elif SYSTEM == BSD
#define HDR "bsd.h"
#elif SYSTEM == MSDOS
#define HDR "msdos.h"
#else
#define HDR "default.h"
#endif
#include HDR
第五章
- 指针与函数参数
由于C语言是以传值的方式将参数值传递给被调用函数,因此,被调用函数不能直接修改主调函数中变量的值。
void swap(int x, int y){
int temp;
temp = x;
x = y;
y = temp;
}
int mian(){
int a = 10, b = 20;
swap(a, b);//无法实现交换,该函数仅仅交换了a和b的副本的值
}
那应该怎么办呢?传值变成传指针!!!
void swap(int *x, int *y){ /* 交换*x和*y */
int temp;
temp = *x;
*x = *y;
*y = temp;
}
int mian(){
int a = 10, b = 20;
swap(&a, &b);//传指针,指针参数使得被调用函数swap能够访问和修改主调函数main中对象的值
}
- 指针与数组
//在函数定义中,形式参数
char s[];和char *s;是等价的 //char *s; 是字符指针
- 指针数组以及指向指针的指针
void qsort(char *v[], int left, int right){
int i, last;
void swap(char *v[], int i, int j);
if (left >= right)
return;
swap(v, left, (left + right)/2);
last = left;
for (i = left+1; i <= right; i++)
if (strcmp(v[i], v[left]) < 0)
swap(v, ++last, i);
swap(v, left, last);
qsort(v, left, last-1);
qsort(v, last+1, right);
}
void swap(char *v[], int i, int j){
char *temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
- 命令行参数
int main(int argc, char *argv[]) {} //字符指针数组,数组元素是字符指针
- 指向函数的指针
void qsort(void *lineptr[], int left, int right, int (*comp)(void *, void *));
int (*comp)(void *, void *) //表明comp是一个指向函数的指针,该函数具有两个void*类型的参数,其返回值类型为int。
C++的qsort:qsort函数定义在头文件<algorithm>中
void qsort (void* base, size_t num, size_t size,
int (*compar)(const void*,const void*));
int compar (const void* p1, const void* p2);
//example
/* qsort example */
#include <stdio.h> /* printf */
#include <stdlib.h> /* qsort */
int values[] = { 40, 10, 100, 90, 20, 25 };
int compare (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
int main ()
{
int n;
qsort (values, 6, sizeof(int), compare);
for (n=0; n<6; n++)
printf ("%d ",values[n]);
return 0;
}
第六章
- 结构基本知识
结构是一个或多个变量的集合,这些变量可能为不同的类型。
struct point {
int x;
int y;
};
struct {...} x, y, z; //struct声明定义了一种数据类型,在标志结构成员表结束的右括号之后可以跟一个变量表,这与其他基本类型的变量声明是相同的。
int x, y, z; //本质是一样的。
struct point pt;
struct point maxpt = {320, 200};
printf("%d,%d", pt.x, pt.y);
struct rect {
struct point pt1;
struct point pt2;
};
struct rect scream;
scream.px1.x;
- 结构与函数
struct point makepoint(int x, int y){ //参数名和结构成员同名不会引起冲突
struct point temp;
temp.x = x;
temp.y = y;
return temp;
}
- 结构指针
struct point *pp; //定义pp为一个指向struct point类型对象的指针
如果pp指向一个point结构,那么*pp即为该结构,而(*pp).x和(*pp).y则是结构成员
struct point origin, *pp;
pp = &origin;
printf("%d,%d",(*pp).x, (*pp).y);
//p->结构成员(->指针使用)
printf("%d,%d",pp->x, pp->y);
struct rect r, *rp = &r;
//以下四个等价
r.pt1.x;
rp->pt1.x;
(r.pt1).x;
(rp->pt1).x;
- 结构数组
struct point {
int x;
int y;
} points[10];
struct point points[10];
sizeof(对象) sizeof(类型名) 返回一个整型值(size_t),等于指定对象和类型占用的存储空间字节数
- 自引用结构
常用于树结构
- 表查找
哈希表
- typedef
typedef int Length;
Length len, maxlen;
Length *lengths[];
typedef char *String;//将String定义为char*字符指针
String p;
- 联合
和访问结构的方式一样,是一种“特殊的”结构
第七章&第八章
第七章讲输入/输出标准库,第八章讲Unix系统的接口,文件操作,与《UNIX环境高级编程》一书某些章节一样,在看这本书时再展开。
最后,分享几个别人的读书笔记
https://www.cnblogs.com/xkfz007/archive/2012/08/05/2623702.html
https://www.cnblogs.com/xkfz007/articles/2566424.html
https://github.com/1326670425/TCPL
http://kissg.me/2016/07/10/notes-on-the-c-programming-language/