linux下的C编程.pdf
第一篇:起步篇第一篇:起步篇 千里之行,始于足下。第一章第一章 UNIX初步初步 UNIX自 1969 年诞生以来,已经发展为 System III&V、BSD 和 Linux 三大分支。UniX通过 shell 与用户交互,它是用户与系统间的界面。使用好 shell 对于学习使用 UNIX来说是必须的。不需要你记住所有的命令,但基础的文件操作、目录操作及系统命令等却是必须的。Vi 对于初学者是难点,不过只要通过一段时间的练习就能习惯;而且你会很快发现,它功能强大、更加灵活。这里不多说了:)第二章第二章 编程套件编程套件 学习 UNIX 对于初学者有几种选择。一种就是最直接的,在本机上安装 UNIX系统,不如说 Linux 分支中的 Red Hat等;一种是在 Windows环境下使用虚拟机方式安装 UNIX 系统;另一种则是使用网络终端登录到网络环境中的某个 UNIX系统中。如果你相对黑洞洞的 UNIX字符界面更喜欢舒适美观的 Windows界面,那么推荐你选择第三种方式。开发套件包括:编辑器 UltraEdit、网络终端 SecureCRT 或其他。编译器就不用说了,自然是 cc(gcc或 xlc 系列)。这是 C 语言开发必不可少的。其中要注意-I(加载头文件路径)、-L(加载库文件路径)及-D(宏定义)参数的使用。Make 工具使用。如何编写 makefile是关键。后面项目中使用时会详细介绍。Gdb 调试器。Gdb 乃符号级调试工具,它控制程序的内部执行,利用断点设置、单步运行等手段,将程序的执行过程逐步展示在调试者目前。这种调试方式在短代码中可以发挥得很好。事实上,随着软件项目的扩大化、复杂化和分布化,很少有程序员直接通过 Gdb 等工具调试;使用日志记录调试方法比Gdb 等调试工具更为便捷和广泛。C 工具:lint检查源代码是否正确,gprof分析程序时间消费量,cflow生成 C 语言流程图。第三章第三章 库的使用库的使用 库分静态库和动态库两种。静态库的操作工具:ar命令。编写及使用静态库编写及使用静态库(1)设计库源码 pr1.c和 pr2.c rootbillstone make_lib#cat pr1.c void print1()printf(This is the first lib src!n);rootbillstone make_lib#cat pr2.c void print2()printf(This is the second src lib!n);(2)编译.c 文件 billbillstone make_lib$cc-O-c pr1.c pr2.c billbillstone make_lib$ls-l pr*.o-rw-rw-r-1 bill bill 804 4月 15 11:11 pr1.o-rw-rw-r-1 bill bill 804 4月 15 11:11 pr2.o(3)链接静态库 为了在编译程序中正确找到库文件,静态库必须按照 libname.a 的规则命名,如下例中name=pr.billbillstone make_lib$ar-rsv libpr.a pr1.o pr2.o a-pr1.o a-pr2.o billbillstone make_lib$ls-l*.a-rw-rw-r-1 bill bill 1822 4月 15 11:12 libpr.a billbillstone make_lib$ar-t libpr.a pr1.o pr2.o(4)调用库函数代码 main.c billbillstone make_lib$cat main.c int main()print1();print2();return 0;(5)编译链接选项 -L 及-l 参数放在后面.其中,-L 加载库文件路径,-l 指明库文件名字.billbillstone make_lib$gcc-o main main.c-L./-lpr billbillstone make_lib$ls-l main*-rwxrwxr-x 1 bill bill 11805 4 月 15 11:17 main-rw-rw-r-1 bill bill 50 4月 15 11:15 main.c (6)执行目标程序 billbillstone make_lib$./main This is the first lib src!This is the second src lib!billbillstone make_lib$编写动态库编写动态库(1)设计库代码 billbillstone make_lib$cat pr1.c int p=2;void print()printf(This is the first dll src!n);billbillstone make_lib$(2)生成动态库 billbillstone make_lib$gcc-O-fpic-shared-o dl.so pr1.c billbillstone make_lib$ls-l*.so-rwxrwxr-x 1 bill bill 6592 4月 15 15:19 dl.so billbillstone make_lib$动态库的隐式调用动态库的隐式调用 在编译调用库函数代码时指明动态库的位置及名字,看下面实例 billbillstone make_lib$cat main.c int main()print();return 0;billbillstone make_lib$gcc-o tdl main.c./dl.so billbillstone make_lib$./tdl This is the first dll src!billbillstone make_lib$当动态库的位置活名字发生改变时,程序将无法正常运行;而动态库取代静态库的好处之一则是通过更新动态库而随时升级库的内容.动态库的显式调用动态库的显式调用 显式调用动态库需要四个函数的支持,函数 dlopen 打开动态库,函数 dlsym获取动态库中对象基址,函数 dlerror获取显式动态库操作中的错误信息,函数 doclose 关闭动态库.billbillstone make_lib$cat main.c#include int main()void*pHandle;void(*pFunc)();/指向函数的指针 int*p;pHandle=dlopen(./d1.so,RTLD_NOW);/打开动态库 if(!pHandle)printf(Cant find d1.so n);exit(1);pFunc=(void(*)()dlsym(pHandle,print);/获取库函数 print 的地址 if(pFunc)pFunc();else printf(Cant find function printn);p=(int*)dlsym(pHandle,p);/获取库变量 p的地址 if(p)printf(p=%dn,*p);else printf(Cant find int pn);dlclose(pHandle);/关闭动态库 return 0;billbillstone make_lib$gcc-o tds main.c-ldl billbillstone make_lib$./tds This is the first dll src!p=2 billbillstone make_lib$上面的程序 tds显式调用了共享库 d1.so 中的函数 print 和变量 p.第二篇:文件子系统 普天之下,莫非王土;率土之滨,莫非王臣.UNIX 之中,莫非文件.第四章第四章 文件系统结构文件系统结构 磁盘在使用前,需要分区和格式化.格式化操作将在磁盘分区中创建文件系统,它们将确定文件的存储方式和索引方法,确定磁盘空间分配和回收算法.UNIX文件系统的存储由三级构成,其中目录存储了文件的层次结构,数据块存储了文件的具体信息,i 节点是连接文件层次结构与其数据内容的桥梁.UNIX文件系统将磁盘空间划分为一系列大小相同的块,划分为引导块,超级块,i 节点区和数据区四个部分.文件系统通过 i 节点对文件进行控制和管理.其中,每个文件对应一个 i 节点,每个 i 节点具有唯一的节点号,记录了文件的属性和内容在磁盘上的存储位置.但文件名并不记录在 i 节点里,而是存储在目录文件中.磁盘文件如何存储磁盘文件如何存储?文件系统通过目录记载文件名及其对应的 i 节点编号,通过 i节点记录文件的信息和内容.事实上,i 节点直接记录的只是文件的属性,文件的具体内容存储在数据区的数据块中,i 节点中仅保留了一个来记录文件内容存储的位置.由 13 个块号组成,每个块号占用 4 个字节,代表了数据区中的一个数据块编号.UNIX文件系统采用三级索引结构存储文件,它把分为直接索引地址,一级索引地址,二级索引地址和三级索引地址等四个部分.其中前 10 项为直接索引地址,直接指向文件数据所在磁盘快的块号.第11/12/13 项分别为一级/二级/三级索引地址.一级间接索引的含义在于其存储的并非文件数据所在磁盘块的块号,而是先指向一个然后再指向具体磁盘块的块号.同理,二级/三级间接索引则是先间接指向了两次才指向具体磁盘快的块号.如果文件系统的数据块大小为 1kB,每个能够记录 256 个数据项.那么,直接索引能管辖10 个数据块,而一级索引能管辖 1*256 个数据块,二级索引能管辖 1*256*256(65536)个数据块,三级索引能管辖 1*256*256*256(16777216)个数据块.例题:大小为 56000K的文件,占用多少索引块空间?答:因为(10+256)56000 tm_year+1900,mtime-tm_mon+1,mtime-tm_mday);设计类似于 UNIX命令的程序 lsl,主程序如下 billbillstone Unix_study$cat lsl.c#include#include#include#include int GetFileType(mode_t st_mode,char*resp);int GetFileMode(mode_t st_mode,char*resp);int GetFileOtherAttr(struct stat info,char*resp);int main(int argc,char*argv)struct stat info;char buf100,*p=buf;if(argc!=2)printf(Usage:lsl filenamen);return;memset(buf,0,sizeof(buf);if(lstat(argv1,&info)=0)p+=GetFileType(info.st_mode,p);p+=GetFileMode(info.st_mode,p);p+=GetFileOtherAttr(info,p);printf(%s%sn,buf,argv1);else printf(Open file failed!n);return 0;运行结果如下:billbillstone Unix_study$make lsl cc lsl.c -o lsl billbillstone Unix_study$./lsl Usage:lsl filename billbillstone Unix_study$./lsl/etc/passwd-rw-r-r-1 0 0 1639 20090328/etc/passwd billbillstone Unix_study$ls-l/etc/passwd-rw-r-r-1 root root 1639 3月 28 16:38/etc/passwd 第五章第五章 标准文件编程库标准文件编程库 在 UNIX的应用中,读写文件是最常见的任务.标准文件编程库就是操作文件最简单的工具.标准编程函数库对文件流的输入输出操作非常灵活,我们既可以采用所见即所得的方式,以无格式方式读写文件,又可以对输入输出数据进行转化,以有格式方式读写文件.文件的无格式读写文件的无格式读写 无格式读写分三类:按字符读写,按行读写和按块读写.字符读写函数族:#include int getc(FILE*stream);int fgetc(FILE*stream);int putc(int c,FILE*stream);int fputc(int c,FILE*stream);函数 fgetc的功能类似于 getc,不同的是,它的执行速度远低于 getc.行读写函数族:#include char*gets(char*s);char*fgets(char*s,int n,FILE*stream);int puts(const char*s);int fputs(const char*s,FILE*stream);函数 fgets中加入了放溢出控制,应该优先选用.注意函数 fputs把字符串 s(不包括结束符0)写入文件流 stream中,但不在输出换行符n;而函数 puts 则自动输出换行符.块读写函数族:#include size_t fread(void*ptr,size_t size,size_t nitems,FILE*stream);size_t fwrite(const void*ptr,size_t size,size_t nitems,FILE*stream);函数 fread和 fwrite 都不返回实际读写的字符个数,而返回的是实际读写的数据项数.块读写函数常用于保存和恢复内存数据.文件的格式化读写文件的格式化读写 文件格式化读写时能够自动转换的数据格式有:数据类型,精度,宽度,进制和标志等,而其一般格式为%标志 宽度.精度 类型 格式化输出函数族#include int printf(const char*format,/*arg,*/.);int fprintf(FILE*stream,const char*format,/*arg,*/.);int sprintf(char*s,const char*format,/*arg,*/.);在做字符串处理时应该善用 sprintf函数.格式化输入函数族#include int scanf(const char format,/*pointer,*/.);int fscanf(FILE*stream,const char format,/*pointer,*/.);int sscanf(const char*s,const char format,/*pointer,*/.);二进制读写与文本读写二进制读写与文本读写 记得刚开始学习 C 语言的文件操作时,这是一个最让我疑惑的问题.我们都知道在调用 fopen 函数时需要指定操作类型,比如说文本写r和二进制写rb.那么它们究竟有何区别呢?这要牵涉到两种存储方式:以字符为单位存储的文本文件和以二进制数据为单位存储的二进制文件.举个例子:我们通常阅读的 Readme.txt文件就是文本文件,该类型文件存储的是一个一个的字符,这些字符往往是可以打印的;而我们的可执行程序(比如 a.out)则是二进制文件,该文件是不可读的,需要解析才能识别.那么在调用 fopen 函数时该如何选择呢?如果你是先写入再从另外的地方读出,那么两种方式都可以;只要按写入时的方式读取就可以了.但是,比起文本方式,二进制方式在保存信息时有着优势:a)加快了程序的执行速度,提高了软件的执行效率.内存中存储的都是二进制信息,直接以二进制方式与文件交互,可以免除二进制格式与文本格式之间的信息转换过程.b)节省了存储空间.一般来讲,二进制信息比文件信息占用更少的空间,比如 8 位的整型数采用文本方式存储至少需要 8 字节,而采用二进制存储只需一个整型即 4 个字节.编写变长参数函数编写变长参数函数 文件的格式化输入输出函数都支持变长参数.定义时,变长参数列表通过省略号.表示,因此函数定义格式为:type 函数名(参数 1,参数 2,参数 n,.);UNIX的变长参数通过 va_list 对象实现,定义在文件stdarg.h中,变长参数的应用模板如下所示:#include function(parmN,.)va_list pvar;.va_start(pvar,parmN);while().f=va_arg(pvar,type);.va_end(pvar);va_list 数据类型变量 pvar访问变长参数列表中的参数.宏 va_start 初始化变长参数列表,根据 parmN判断参数列表的起始位置.va_arg 获取变长列表中参数的值,type指示参数的类型,也使宏 va_arg 返回数值的类型.宏 va_arg 执行完毕后自动更新对象 pvar,将其指向下一个参数.va_end 关闭对变长参数的访问.下面给出一个实例 mysum,计算输入参数的和并返回 billbillstone Unix_study$cat mysum.c#include int mysum(int i,.)/参数列表中,第一个参数指示累加数的个数 int r=0,j=0;va_list pvar;va_start(pvar,i);for(j=0;ji;j+)r+=va_arg(pvar,int);va_end(pvar);return(r);int main()printf(sum(1,4)=%dn,mysum(1,4);printf(sum(2,4,8)=%dn,mysum(2,4,8);return 0;billbillstone Unix_study$make mysum cc mysum.c -o mysum billbillstone Unix_study$./mysum sum(1,4)=4 sum(2,4,8)=12 billbillstone Unix_study$第六章第六章 低级文件编程库低级文件编程库 低级文件编程库常常用于访问终端,管道,设备和套接字等特殊文件,一般不用于普通磁盘文件,这是标准文件编程库的特长.低级文件编程库听起来似乎低级,其实它是 UNIX中的 I/O系统调用.它们使用文件描述符,直接读写各类文件.低级文件编程库在输入输出上只有块读写的功能.文件锁文件锁 多用户多任务操作系统非常重要的一个内容就是文件锁.用户在更新文件时,期望可以使用某种机制,防止两进程同时更新文件同一区域而造成写丢失,或者防止文件内容在未更新完毕时被读取等并发引起的问题,这种机制就是文件锁.进程在操作文件期间,可以使用文件锁,锁定文件中的敏感信息,防止其他进程越权操作该部分信息.函数 fcntl 提供了对文件任意区域设置锁的能力,既可以锁住全部文件,又可以锁住文件的部分记录,故文件锁又称为记录锁.根据文件锁的访问方式,可以区分为读锁和写锁两种.文件记录在同一时刻,可以设置多个读锁,但仅能设置一个写锁,并且读写锁不能同时存在.当函数 fcntl 专用于锁操作时,其原型为 int fcntl(int fildes,int cmd,struct flock*arg);其中,结构 flock 用于描述文件锁的信息,定义于头文件fcntl.h中,如下所示 struct flock short l_type;/锁类型,取值为 F_RDLCK,F_WRLCK 或 F_UNLCK 之一 short l_whence;/锁区域开始地址的相对位置,取值为 SEEK_SET,SEEK_CUR 或 SEEK_END 之一 off_t l_start;/锁区域开始地址偏移量 off_t l_len;/锁区域的长度,0 表示锁至文件末 pid_t l_pid;/拥有锁的进程 ID号;函数 fcntl在专用于锁操作时,参数 cmd 有三种取值:(a)F_GETLK.获取文件描述符 fileds对应文件指定区域的文件锁信息.(b)F_SETLK.在文件描述符 fileds对应的文件中指定区域设置锁信息.(c)F_SETLKW.该命令是 F_SETLK命令的阻塞版本.文件锁最典型应用于两个方面:一是锁定文件中的临界数据,比如并发投票时文件记录的投票数;二是利用具有互斥性质的写锁,实现进程的并发控制.在锁机制的使用中,最常见的操作有锁的请求,释放和测试等,下面一一说明.(a)测试锁.设计函数 SeeLock,查询文件描述符 fd 对应文件的锁信息.void SeeLock(int fd,int start,int len)/查询描述符 fd对应文件从 start 处开始的 len字节中的锁信息 struct flock arg;arg.l_type=F_WRLCK;arg.l_whence=SEEK_SET;arg.l_start=start;arg.l_len=len;if(fcntl(fd,F_GETLK,&arg)=-1)fprintf(stderr,See Lock failed.n);else if(arg.l_type=F_UNLCK)fprintf(stderr,No Lock From%d to%dn,start,start+len);else if(arg.l_type=F_WRLCK)fprintf(stderr,Write Lock From%d to%d,id=%dn,start,start+len,arg.l_pid);else if(arg.l_type=F_RDLCK)fprintf(stderr,Read Lock From%d to%d,id=%dn,start,start+len,arg.l_pid);(b)申请读锁.以阻塞方式设计共享读锁申请函数 GetReadLock.void GetReadLock(int fd,int start,int len)/以阻塞方式在描述符 fd对应文件中从 start 处的 len字节上申请共享读锁 struct flock arg;arg.l_type=F_RDLCK;arg.l_whence=SEEK_SET;arg.l_start=start;arg.l_len=len;if(fcntl(fd,F_SETLKW,&arg)=-1)fprintf(stderr,%d See Read Lock failed.n,getpid();else fprintf(stderr,%d Set Read Lock From%d to%dn,getpid(),start,start+len);(c)申请写锁.以阻塞方式设计互斥写锁申请函数 GetWrtieLock.void GetWriteLock(int fd,int start,int len)/以阻塞方式在描述符 fd对应文件中从 start 处的 len字节上申请互斥写锁 struct flock arg;arg.l_type=F_WRLCK;arg.l_whence=SEEK_SET;arg.l_start=start;arg.l_len=len;if(fcntl(fd,F_SETLKW,&arg)=-1)fprintf(stderr,%d See Write Lock failed.n,getpid();else fprintf(stderr,%d Set Write Lock From%d to%dn,getpid(),start,start+len);(d)释放锁.设计文件锁释放函数 ReleaseLock.void ReleaseLock(int fd,int start,int len)/在描述符 fd对应文件中释放从 start 处的 len字节上的锁 struct flock arg;arg.l_type=F_UNLCK;arg.l_whence=SEEK_SET;arg.l_start=start;arg.l_len=len;if(fcntl(fd,F_SETLKW,&arg)=-1)fprintf(stderr,%d UnLock failed.n,getpid();else fprintf(stderr,%d UnLock From%d to%dn,getpid(),start,start+len);下面设计一个文件锁控制进程的实例 lock1.为了观察阻塞方式下的锁申请,在释放锁前休眠 30秒.#include#include int main()int fd;struct flock arg;if(fd=open(/tmp/tlockl,O_RDWR|O_CREAT,0755)0)fprintf(stderr,open file failed.n);exit(1);SeeLock(fd,0,10);GetReadLock(fd,0,10);SeeLock(fd,11,20);GetWriteLock(fd,11,20);sleep(30);ReleaseLock(fd,0,10);ReleaseLock(fd,11,20);return 0;下面是执行情况:billbillstone Unix_study$make lockl cc lockl.c -o lockl billbillstone Unix_study$./lockl&/先在后台执行 2 12725 No Lock From 0 to 10 12725 Set Read Lock From 0 to 10 No Lock From 11 to 31 12725 Set Write Lock From 11 to 31 /此后休眠 30秒 billbillstone Unix_study$./lockl /再次执行 Read Lock From 0 to 10,id=12725 12726 Set Read Lock From 0 to 10 /可在同一区域申请多个共享读锁 Write Lock From 11 to 31,id=12725 12725 UnLock From 0 to 10 12725 UnLock From 11 to 31 12726 Set Write Lock From 11 to 31 /在同一区域只能申请一个互斥写锁 12726 UnLock From 0 to 10 12726 UnLock From 11 to 31 2+Done ./lockl billbillstone Unix_study$第七章第七章 目录文件编程库目录文件编程库 UNIX专门给出了一组用于目录操作的函数,可以方便地获取目录项的确切含义.工作目录工作目录 进程在搜索文件相对路径时都会有一个起始点,这个起始点称为当前工作目录.在 UNIX中对工作目录的操作可分为读取工作目录和更改工作目录两种.(1)读取工作目录.函数 getcwd 和 getwd 都返回工作目录的绝对路径#include char*getcwd(char*buf,size_t size);char*getwd(char*pathname);(2)更改工作目录.#include int chhdir(const char*path);int fchdir(int fildes);下面是一个读取和更改当前工作目录的例子 billbillstone Unix_study$cat dirl.c#include#include int main()char buf255;fprintf(stderr,pwd=%s n,getcwd(buf,sizeof(buf);chdir(./);/更改工作目录为上一级目录 fprintf(stderr,pwd=%s n,getcwd(buf,sizeof(buf);return 0;billbillstone Unix_study$make dirl cc dirl.c -o dirl billbillstone Unix_study$pwd/home/bill/Unix_study billbillstone Unix_study$./dirl pwd=/home/bill/Unix_study pwd=/home/bill ;更改成功 billbillstone Unix_study$pwd/home/bill/Unix_study ;不影响当前 Shell 的工作目录 billbillstone Unix_study$读取目录读取目录 目录文件编程库不提倡直接更改目录文件内容,它仅仅执行读取操作#include DIR*opendir(const char*dirname);struct dirent*readdir(DIR*dirp);int closedir(DIR*dirp);函数 opendir打开目录文件 dirname,并返回一个目录流,存储为 DIR 结构.函数 readdir 读取当前目录项内容存入参数 dirp指向的结构 dirent 中,并移动目录文件指针到下一目录项.目录中每个目录项采用结构 dirent描述.struct dirent long d_ino;/文件对应 i 节点编号 _kernel_off_t d_off;unsigned short d_reclen;char d_name256;/文件名称;下面是一个简单的读取目录程序 ls2,它列举了目录下的全部文件及其对应的 i 节点编号.billbillstone Unix_study$cat ls2.c#include#include int main(int argc,char*argv)DIR*pdir;struct dirent*pent;if(argc!=2)fprintf(stderr,Usage:ls2 n);return 0;if(pdir=opendir(argv1)=NULL)fprintf(stderr,open dir failed.n);exit(1);while(1)if(pent=readdir(pdir)=NULL)break;fprintf(stderr,%5d%sn,pent-d_ino,pent-d_name);closedir(pdir);return 0;执行结果如下:billbillstone Unix_study$make ls2 cc ls2.c -o ls2 billbillstone Unix_study$./ls2/home/bill/Doc 134706.29.134708 学习笔记.doc billbillstone Unix_study$ls-ai/home/bill/Doc 134706.29.134708 学习笔记.doc 第三篇第三篇 并发程序设计并发程序设计 业精于勤,而荒于嬉.第九章第九章 进程控制进程控制 进程是程序的一次执行,是运行在自己的虚拟地址空间的一个具有独立功能的程序.进程是分配和释放资源的基本单位,当程序执行时,系统创建进程,分配内存和 CPU等资源;进程结束时,系统回收这些资源.线程与进程线程与进程 线程又名轻负荷进程,它是在进程基础上程序的一次执行,一个进程可以拥有多个线程.线程没有独立的资源,它共享进程的 ID,共享进程的资源.线程是 UNIX中最小的调度单位,目前有系统级调度和进程级调度两种线程调度实行方式:系统级调度的操作系统以线程为单位进行调度;进程级调度的操作系统仍以进程为单位进行调度,进程再为其上运行的线程提供调度控制.环境变量环境变量 UNIX中,存储了一系列的变量,在 shell 下执行env命令,就可以得到环境变量列表.环境变量分为系统环境变量和用户环境变量两种.系统环境变量在注册时自动设置,大部分具有特定的含义;用户环境变量在 Shell 中使用赋值命令和 export 命令设置.如下例先设置了变量 XYZ,再将其转化为用户环境变量:billbillstone Unix_study$XYZ=/home/bill billbillstone Unix_study$env|grep XYZ billbillstone Unix_study$export XYZ billbillstone Unix_study$env|grep XYZ XYZ=/home/bill billbillstone Unix_study$UNIX下 C 程序中有两种获取环境变量值的方法:全局变量法和函数调用法 (a)全局变量法 UNIX系统中采用一个指针数组来存储全部环境值:Extern char*environ;该法常用于将 environ 作为参数传递的语句中,比如后面提到的 execve 函数等.billbillstone Unix_study$cat env1.c#include extern char*environ;int main()char*p=environ;while(*p)fprintf(stderr,%sn,*p);p+;return 0;billbillstone Unix_study$make env1 cc env1.c -o env1 billbillstone Unix_study$./env1 SSH_AGENT_PID=1392 HOSTNAME=billstone DESKTOP_STARTUP_ID=SHELL=/bin/bash TERM=xterm.billbillstone Unix_study (b)函数调用法 UNIX环境下操作环境变量的函数如下:#include char*getenv(char*name);int putenv(const char*string);函数 getenv 以字符串形式返回环境变量 name 的取值,因此每次只能获取一个环境变量的值;而且要使用该函数,必须知道要获取环境变量的名字.billbillstone Unix_study$cat env2.c#include#include int main(int argc,char*argv)int i;for(i=1;iargc;i+)fprintf(stderr,%s=%sn,argvi,getenv(argvi);return 0;billbillstone Unix_study$make env2 cc env2.c -o env2 billbillstone Unix_study$./env2 HOME LOGNAME rp HOME=/home/bill LOGNAME=bill rp=(null)billbillstone Unix_study$在进程中执行新程序的三种方法在进程中执行新程序的三种方法 进程和人类一样,都有创建,发展,休眠和死亡等各种生命形态.其中,函数 fork 创建新进程,函数exec 执行新程序,函数 sleep 休眠进程,函数 wait 同步进程和函数 exit 结束进程.(1)fork-exec 调用 fork 创建的子进程,将共享父进程的代码空间,复制父进程数据空间,如堆栈等.调用 exec族函数将使用新程序的代码覆盖进程中原来的程序代码,并使进程使用函数提供的命令行参数和环境变量去执行新的程序.exec 函数族有六个函数如下:#include int execl(const char*path,const char*arg0,.,(char*)0);int execle(const char*path,const char*arg0,.,(char*)0,char*const envp);int execlp(const char*file,const char*arg0,.,(char*)0);int execv(const char*path,const char*argv);int execve(const char*path,const char*argv,const char*envp);int execvp(const