第一章:C语言入门【30页】
1.gcc cards.c -o cards
2.gcc cards.c -o cards && ./cards
第二章:存储器和指针【70页】
指针要点:
1.计算机会为变量在存储器中分配空间
2.局部变量位于栈中
3.全局变量位于全局量段
4.指针只是一个保存存储器地址的变量
5. &运算符可以找到变量的地址
6. *运算符可以读取存储器地址中的内容
7. *运算符还可以设置存储器地址中的内容
%p以16进制格式化内容
数组指针要点:
1.数组变量可以被用作指针
2.数组变量指向数组中第一关元素
3.如果把函数参数声明为数组,它会被当作指针处理
4.sizeof运算符返回某条数据占用空间的大小
5.也可以对某种数据类型使用sizeof,例如sizeof(int)
6.sizeof(指针)在32位操作系统中返回4,在64位系统中返回8
数组指针退化[要点]:
1.数组变量可以用作指针,但数组变量和指针又不完全相同
2.对数组变量和指针变量使用sizeof,效果不同
3.数组变量不能指向其他地方
4.把数组变量传给指针,会发生退化
5.索引本质是指针算术运算,所以数组从0开始
6.指针变量具有类型,这样就能调整指针算术运算
scanf("%i",&x)可以让用户直接输入数字x
可以简单地用fgets(but,size,stdin)输入文本
字符串要点:
1.如果在变量声明中看到*,说明变量是指针
2.字符串字面值保存在只读存储器中
3.如果想要修改字符串,需要在新的数组中创建副本
4.可以将char指针声明成const char *,以防止代码用它修改字符串
第2.5章:字符串原理
要点:
1.可以用char strings[...][...]来创建数组的数组
2.第一组方括号用来访问外层数组
3.第二组方括号用来访问每个内层数组中的元素
4.有类string.h头文件,就可以使用c标准库中的字符串处理函数
strstr(a,b)可以返回b在字符串a中的地址
strchr()用来在字符串中查找莫个字符的位置
strcmp可以比较字符串
strcpy可以复制字符串
strcat可以连接字符串
strlen()可以得到字符串的长度
第三章:创建小工具
要点:
1.printf()函数把数据发送到标准输出,默认情况下,标准输出会发送到显示器
2.可以在命令行中用>将标准输出重定向到文件
3.scanf()从标准输入中读取数据,默认情况下,标准输入会从键盘读取数据
4.可以在命令行中用<将标准输入重定向到文件
5.标准错误stderr专门用来输出错误信息
6.可以用2>重定向标准错误
小工具设计要点:
1.如果想完成一个不同的任务\应该另外写一个小工具
2.小工具应该使用标准输入和标准输出
3.小工具通常读写文本数据
4.可以用管道|连接一个进程的标准输出和另一个进程的标准输入
自定义输出要点:【184页】
1.main()函数有量个版本,一个有命令行参数,一个没有
2.命令行参数通过两个变量传递给main()函数,一个是参数的计数,另一个是指针(指向参数字符串)数组
FILE *in=fopen("spooky.scv",r);//r为"读",w为"写",a为"append"
可以用fopen("文件名",模式)创建自己的数据流,三种模式为w(写),r(读),a(append)
fprintf(stderr,...)把数据打印到标准错误
第四章:使用多个源文件【186页】
第八章:392页
静态库要点:
1.使用尖括号<>,编译器会从标准目录中读取头文件
2.常见标准头文件目录有/usr/include和c:\MInGW\include
3.一个库存档中有多个目标文件
4.可以用ar -rcs libarchive.a file0.o file1.0...创建文档
例:ar -rcs libhfsecurity.a encrypt.o checksum.o
5.库存档名应以lib开头,以.a结尾
6.如果向链接一个叫libfred.a的存档,就使用-lfred选项
7.在gcc命令中,-l[L小写]标志应该在源代码文件后出现
例:gcc test_code.c -lhfsecurity -o test_code
gcc test_code.c -L/my_lib -lhfsecurity -o test_code
动态库要点:【没看懂】
1.动态库在运行时链接程序
2.用一个或多个目标文件创建动态库
3.在一些机器上,需要使用-fPIC选项来编译目标文件
4.-fPIC令目标代码位置无关
5.在一些机器上,可以省略-fPIC
6.-shared编译选项可以创建动态库
7.动态库在不同机器上名字不同
8.如果把动态库保存在标准目录中,生活会变得更简单
9.不然,就需要设置PATH变量和LD_
LIBTAY+PATH变量
gcc -shared把目标文件转化为动态库,动态库的后缀名有.so,.dylib,.dll,不同操作系统不同
库存档名形如libXXX.a,库存档是静态链接
第九章:进程与系统调用【426页-没看懂】
要点:
1.系统调用的是操作系统内核中的函数,当进行系统调用时,相当于调用你程序外面的代码
2.system()系统调用可以运行命令字符串,但不安全
3.exec()系统调用在运行程序时给了你更多控制权,但exec()有很多版本,需要unistd.h
列表函数:execl(),execlp(),execle(),
数组函数:execv(),execvp(),execve(),
例:execl("/home/flynn/clu","/home/flynn/clu","paranoids","contract",NULL);
4.exec()系统调用出错时通常会返回-1,但不是绝对的,系统调用出错时会将errno变量设为错误码,需要errno.h
要点:
1.exec()函数替换当前进程
2.fork()函数复制当前进程,pid_t pid=fork();
第十章:进程间通信【458页】
要点:
1.exit(1);可以快速结束程序
2.所有打开的文件都记录在描述符中
3.通过修改描述符表就可以重定向输入和输出
4.fileno(*file);能在表中查找描述符
5.dup2(source,target);可以用来修改描述符表
6.waitpid()等待进程结束
要点:
1.父子进程可以通信
2.pipe()函数创建一个管道和两个描述符
3.一个描述符是管道的读取端,一个是写入端
4.可以把标准输入和标准输出重定向到管道
5.父子进程各自使用管道的一端
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
/*这个函数读取\n前的所有字符*/
int read_in(int socket,char *buf,int len){
char *s=buf;
int slen=len;
int c=recv(socket,s,slen,0);
while((c>0) && (s[c-1] !='\n')){
s+=c;
slen-=c;
c=recv(socket,s,slen,0);
}
if(c<0) return c;//防止错误
else if(c==0)//什么都没读到,返回一个空字符串
buf[0]='\0';
else s[c-1]='\0';//用\0替换\r
return len-slen;
}
int main(int argc,char *argv[]){
char *advice[]={
"Take smaller bitws\r\n",
"Go for the tight jeans. NO they do NOT make you look fat.\r\n",
"One world: inappropriate\r\n",
"Just for today, be honest. Tell your boss what you *really* think\r\n",
"You might want to rethink that haircut\r\n"
};
//0.创建套接字,listener_d是套接字描述符
int listener_d=socket(PF_INET,SOCK_STREAM,0);
if(listener_d==-1) error("socket 失败");
//1.绑定端口
struct sockaddr_in name;
name.sin_family=PF_INET;
name.sin_port=(in_port_t)htons(30000);
name.sin_addr.s_addr=htonl(INADDR_ANY);
int reuse=1;
//重新使用接口
if(setsockopt(listener_d,SOL_SOCKET,SO_REUSEADDR,(char *)&reuse,sizeof(int))==-1)
error("无法设置套接字“重新使用端口”选项");
if(bind(listener_d,(struct sockaddr *) &name,sizeof(name)==-1)
error("bind port 失败");
//2.监听
if(listen(listener_d,10)==-1)
error("listenn port 失败");
puts("Waiting for connection");
//3.接受客户端的连接
while(1){
struct sockaddr_storage client_addr;
unsigned int address_size=sizeof(client_addr);
int connect_d=accept(listener_d,(struct sockaddr *)&client_addr,&address_size);
if(connect_d==-1) error("客户端连接失败");
//3.2 connect_d是服务端和客户端建立的链接的套接字描述符
//3.3 开始通信
char *msg=advice[rand() %5];
send(connect_d,msg,strlen(msg),0);
close(connect_d);
}
return 0;
}
要点:
1.协议是一段结构化对话
2.服务器连接本地端口
3.客户端连接远程端口
4.客户端和服务端使用套接字通信
5.用send()向套接字写数据
6.用recv()从套接字读数据
7.HTTP是一种网络协议
章总结:
1.用socket()函数创建套接字
2.服务器BLAB四部曲:B=bind(),L=listen(),A=accept(),B=开始对话
3.getaddrinfo()根据域名找地址
第十二章:线程
1.能够创建线程时创建进程
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
void error(char *msg){
fprintf(stderr,"%s: %s\n",msg,strerror(errno));
exit(1);
}
void* does_not(void *a){
int i=0;
for(i=0;i<5;i++){
sleep(1);
puts("Does not!");
}
return NULL;
}
void* does_too(void *a){
int i=0;
for(i=0;i<5;i++){
sleep(1);
puts("Does too!");
}
return NULL;
}
int main(){
pthread_t t0;
pthread_t t1;
//启动线程
if(pthread_create(&t0,NULL,does_not,NULL)==-1)
error("无法创建线程t0");
if(pthread_create(&t1,NULL,does_too,NULL)==-1)
error("无法创建线程t1");
void* result;
//pthread_join()函数会等待线程结束
if(pthread_join(t0,&result)==-1)
error("无法回收线程t0");
if(pthread_join(t1,&result)==-1)
error("无法回收线程t1");
}
//线程锁:
pthread_mutex_t beers_lock=PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&beers_lock);
pthread_mutex_unlock(&beers_lock);
总结:
pthread_create()创建线程来运行函数
pthread_join()会等待线程结束
pthread_mutex_lock()在代码中创建互斥锁
pthread_mutex_unlock()释放互斥锁
1.运算符
2.预处理指令:#include #define
3.static关键字
4.数据类型的大小:LONG_MAX,SHRT_MIN
5.自动化测试
6.gcc+make
8.开发工具
9.创建GUI
10.参考书籍:《C程序设计语言》《C语言参考手册》《C专家编程》《实用C语言编程》