Home 世界杯图标 《head first c》学习笔记及C语言有用的函数

《head first c》学习笔记及C语言有用的函数

动态库及静态库

动态库是在运行时链接程序,静态库一旦链接,就不能改变。

#include <>查找包括/usr/include在内的标准目录

gcc -fPIC 令目标代码位置无关,例如: gcc -c -fPIC test.c -o test.o(因为头文件在标准目录中,所以不需要加上-I选项)

gcc -i<路径名> 会链接标准目录( 例如/usr/lib)下的文件

gcc -I<路径> 表示头文件在<路径>下

gcc -L<路径名> 在标准lib目录下添加目录

gcc -shared 把目标文件转化为动态库

gcc -s 生成汇编文件

ar 命令创建目标文件的存档(静态库)

动态库的后缀名有.so(linux系统) .dylib(Mac系统) .dll.a(windows下的cygwin)

有用的函数

stdlib.h

getenv() 获取环境变量

system() 调用其他程序,接受一个字符串参数,这个函数容易出错。

unistd.h

exec() 函数运行其他程序替换当前进程,例如:execl(<程序>,<命令行参数>,<命令行参数>,NULL),命令行参数可以有很多,最后必须有NULL结尾列表。

列表函数execl()、execlp()、execle() 数组函数execv()、execvp()、execve()

errno.h

errno 变量定义标准错误码, EPERM=1 不允许操作

ENOENT=2 没有该文件或目录

ESRCH=3 没有该进程

string.h

strerror() 函数查询标准错误消息,例如:puts(strerror(errno)); 通过标准错误的标号,获得错误的描述字符串 ,将单纯的错误标号转为字符串描述,方便用户查找错误。

fork() 克隆进程,例如pid_t pid = fork();然后在新的进程里exec(),如果fork返回0,说明代码运行在子进程中,如果返回-1说明克隆出现问题还是处于父进程。

如果子进程需要修改储存器中的数据,系统会为他复制一份,这叫写时复制(copy on time)。pid_t 是不同系统保存的进程ID,在不同系统用不同的整型。

strstr(char* s1, char * s2) 函数用于判断字符串str2是否是str1的子串。如果是,则该函数返回str2在str1中首次出现的地址;否则,返回NULL

char *strtok(char s[], const char *delim); 分解字符串为一组字符串。s为要分解的字符,delim为分隔符字符(如果传入字符串,则传入的字符串中每个字符均为分割 符)。首次调用时,s指向要分解的字符串,之后再次调用要把s设成NULL。

char *strcpy(char* dest, const char *src) 把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间

int strcmp(const char *s1,const char *s2)当s1s2时,返回正数。

char *fgets(char *buf, int bufsize, FILE *stream) *buf: 字符型指针,指向用来存储所得数据的地址。bufsize: 整型数据,指明存储数据的大小。*stream: 文件结构体

指针,将要读取的文件流。

int fputs(char *str,FILE *fp) str是字符型指针,可以是字符串常量,或者存放字符串的数组首地址。fp通过打开文件函数fopen()获得的。

stdio.h

int sscanf(const char *buffer,const char *format,[argument ]...)

参数buffer:储存的数据, format:格式控制字符串, argument:选择性设定字符串。

进程间通信

可以用">"运算符吧标准输出重定向到文件。"2>" 重定向错误输出。"2>&1" 把标准输出和标准错误重定向到一个地方,

进程用文件描述符来表示数据流(就是一个数字 - -),数字0 代表标准输入-键盘, 1 代表标准输出-屏幕, 2 代表标准错误-屏幕,3 代表数据库连接。

fileno()函数返回文件描述符,例如:FILE *my_file = fopen("guitar.mp3", "r"); int descriptor =fileno(my_file);

dup2()函数修改一个注册的描述符重新指向另一个,例如:dup2(4, 3); //将4号注册的文件指针同时连接到3号指针。

exit() 函数系统调用结束进程,例如:exit(1);//把程序结束,并且退出码为1。

waitpid()函数会等到子进程结束以后才返回。例如:waitpid(pid, &pid_status, 0); //pid是父进程fork后得到的子进程号;pid_status是进程信息,因为waitpid()需要修改他,所以是指针;0是选项可以使用man waitpid()查询,当为0时,函数等待进程结束。pid_status的值传给WEXITSTATUS()宏来处理,因为pid_status只有前8位表示进程的退出状态。

pipe()函数创建管道,例如:int fd[2]; piple(fd); //fd[0]是管道读取端,fd[1]是管道写入端。

close(fd[0])关闭管道读取端。

中断

sigaction是一个结构体,用于告诉系统收到某个信号时应该调用那个函数,sigaction包装的函数叫处理器。sigaction(signal_no, &new_action, &old_action)函数用来注册sigaction。

中断信号有一个信号映射表,信号SIGINT 的处理函数调用exit(), SIGINT的值是2。当在输入名字时,使用Ctrl-C,操作系统自动向进程发送中断信号(SIGINT),我们注册的sigaction结构体来处理这个信号,sigaction中国年有一个指向diediedie函数的指针,程序通过调用这个函数,显示消息并调用exit。

#include

#include

#include

void diediedie(int sig)//信号处理器,返回void

{

puts ("Goodbye bob!");

exit(1);

}

int catch_signal(int signal, void (*handler)(int))

{

struct sigaction action;

action.sa_handler = handler;

sigemptyset(&action.sa_mask);

action.sa_flags = 0;

return sigaction(signal, &action, NULL);

}

int main(){

if (catch_signal(SIGINT, diediedie)== -1) {

fprintf(stderr, "Can't map the handler\n" );

exit(2);

}

char name[20];

printf("Enter your name: \n" );

fgets(name, 30, stdin);

printf("Hello %s\n", name);

return 0;

}

kill的命令能够结束程序,并发送信号,需要相关进程的pid,kill -KILL一定能终止进程。

raise()函数能够发送信号,例如:raise(SIGINT);

alarm(120)函数能够在120秒后发出SIGALRM信号,不要同时使用sleep()和alarm()函数,他们使用间隔计数器。

可变参数函数

va_start、va_arg、va_end是宏,在编译前预处理器根据这些指令插入相关代码。

#include //处理可变函数的代码在这个头文件中

void print_ints(int args, ...)//...表示省略符号

{

va_list ap;//va_list用来保存传给函数的其他参数

va_start(ap,args);//需要把最后一个普通参数告诉从哪里开始

int i;

for(i = 0; i < args; i++){

printf("argument: %i\n", va_arg(ap, int));//va_arg可以读取参数

}

va_end(ap);

}

网络与套接字

网络连接四部曲:绑定(Bind)、监听(Listen)、接受(Accept)、开始(Begin)

getaddrinfo()获得域名地址,需要头文件,使用freeaddrinfo()清除它这个远程连接。

使用send()向套接字发送数据,用recv()从套接字读数据,服务器连接本地端口,客户端连接远程端口,客户端和服务器使用套接字通信。

线程

对于共享的变量有些时候需要对它上锁。

pthread_mutex_t beers_lock = PTHREAD_MUTEX_INITIALIZER;//创建互斥锁

void* drink_lots(void *a){

int i;

pthread_mutex_lock(&beers_lock);//只允许一个线程通过

for (i = 0; i < 1000000; i++) {

beers = beers - 1;

}

pthread_mutex_unlock(&beers_lock);//其他线程也能使用

printf("%d\n", beers);

}

开发工具

gdb:允许在程序运行期间研究它的代码。

gprof:分许程序性能,找到程序的瓶颈。

gcov:gnu覆盖率测试工具,用来检查代码哪些部分运行,哪些部分没有运行。