Linux C
这是一本名為“Linux C 函数參考”的在线函数参考手册. 原文来自于 https://people.cs.nycu.edu.tw/~yslin/library/linuxc/. 原文为繁体字,部分为日语, 遂决定进行繁转简.
声明: 本人不拥有文章所有权.
isalnum
isalnum(测试字符是否为英文或数字)
相关函数:isalpha,isdigit,islower,isupper
表头文件:#include <ctype.h>
定义函数:int isalnum(int c)
函数说明:检查参数c是否为英文字母或阿拉伯数字,在标准c中相当于使用"isalpha(c) || isdigit(c)"做测试。
返回值:若参数c为字母或数字,则返回TRUE,否则返回NULL(0)。
附加说明:此为宏定义,非真正函数。
范例:
/* 找出str字符串中为英文字母或数字的字符 */
#include <ctype.h>
main()
{
char str[] = "123c@#FDsP[e?";
int i;
for (i = 0; str[i] != 0; i++)
if (isalnum(str[i])) printf("%c is an alphanumeric character\n", str[i]);
}
执行: 1 is an apphabetic character
2 is an apphabetic character
3 is an apphabetic character
c is an apphabetic character
F is an apphabetic character
D is an apphabetic character
s is an apphabetic character
P is an apphabetic character
e is an apphabetic character
isalpha
isalpha(测试字符是否为英文字母)
相关函数:isalnum,islower,isupper
表头文件:#include <ctype.h>
定义函数:int isalpha (int c)
函数说明:检查参数c是否为英文字母,在标准c中相当于使用"isupper(c)||islower(c)"做测试。
返回值:若参数c为英文字母,则返回TRUE,否则返回NULL(0)。
附加说明:此为宏定义,非真正函数。
范例:
/* 找出str字符串中为英文字母的字符 */
#include <ctype.h>
main()
{
char str[]="123c@#FDsP[e?";
int i;
for (i=0; str[i]!=0; i++) if(isalpha(str[i])) printf("%c is an alphanumeric character\n",str[i]);
}
执行: c is an apphabetic character
F is an apphabetic character
D is an apphabetic character
s is an apphabetic character
P is an apphabetic character
e is an apphabetic character
isascii
isascii(测试字符是否为ASCII码字符)
相关函数:iscntrl
表头文件:#include <ctype.h>
定义函数:int isascii(int c);
函数说明:检查参数c是否为ASCII码字符,也就是判断c的范围是否在0到127之间。
返回值:若参数c为ASCII码字符,则返回TRUE,否则返回NULL(0)。
附加说明:此为宏定义,非真正函数。
范例:
/* 判断int i是否具有对应的ASCII码字符 */
#include <ctype.h>
main()
{
int i;
for (i = 125; i < 130; i++)
if (isascii(i))
printf("%d is an ascii character:%c\n", i, i);
else
printf("%d is not an ascii character\n", i);
}
执行: 125 is an ascii character:}
126 is an ascii character:~
127 is an ascii character:
128 is not an ascii character
129 is not an ascii character
iscntrl
iscntrl(測試字符是否為ASCII 碼的控制字符) 相關函數 isascii 表頭文件 #include <ctype.h> 定義函數 int iscntrl(int c); 函數說明 檢查參數c是否為ASCII控制碼,也就是判斷c的範圍是否在0到30之間。 返回值:若參數c為ASCII控制碼,則返回TRUE,否則返回NULL(0)。 附加說明 此為宏定義,非真正函數。
isdigit
isdigit(测试字符是否为阿拉伯数字)
相关函数:isxdigit
表头文件:#include <ctype.h>
定义函数:int isdigit(int c)
函数说明:检查参数c是否为阿拉伯数字0到9。
返回值:若参数c为阿拉伯数字,则返回TRUE,否则返回NULL(0)。
附加说明:此为宏定义,非真正函数。
范例:
/* 找出str字符串中为阿拉伯数字的字符 */
#include <ctype.h>
main()
{
char str[]="123@#FDsP[e?";
int i;
for(i=0; str[i]!=0; i++) if(isdigit(str[i])) printf("%c is an digit character\n",str[i]);
}
执行: 1 is an digit character
2 is an digit character
3 is an digit character
isgraphis
isgraphis(测试字符是否为可打印字符)
相关函数:isprint
表头文件:#include <ctype.h>
定义函数:int isgraph (int c)
函数说明:检查参数c是否为可打印字符,若c所对应的ASCII码可打印,且非空格字符则返回TRUE。
返回值:若参数c为可打印字符,则返回TRUE,否则返回NULL(0)。
附加说明:此为宏定义,非真正函数。
范例:
/* 判断str字符串中哪些为可打印字符 */
#include <ctype.h>
main()
{
char str[]="a5 @;
";
int i;
for(i=0; str[i]!=0; i++) if(isgraph(str[i])) printf("str[%d] is printable character:%d\n",i,str[i]);
}
执行: str[0] is printable character:a
str[1] is printable character:5
str[3] is printable character:@
str[4] is printable character:;
islower
islower(测试字符是否为小写字母)
相关函数:isalpha,isupper
表头文件:#include <ctype.h>
定义函数:int islower(int c)
函数说明:检查参数c是否为小写英文字母。
返回值:若参数c为小写英文字母,则返回TRUE,否则返回NULL(0)。
附加说明:此为宏定义,非真正函数。
范例:
#include <ctype.h>
main()
{
char str[]="123@#FDsP[e?";
int i;
for(i=0; str[i]!=0; i++) if(islower(str[i])) printf("%c is a lower-case character\n",str[i]);
}
执行: c is a lower-case character
s is a lower-case character
e is a lower-case character
isprint
isprint(测试字符是否为可打印字符)
相关函数:isgraph
表头文件:#include <ctype.h>
定义函数:int isprint(int c);
函数说明:检查参数c是否为可打印字符,若c所对应的ASCII码可打印,其中包含空格字符,则返回TRUE。
返回值:若参数c为可打印字符,则返回TRUE,否则返回NULL(0)。
附加说明:此为宏定义,非真正函数。
范例:
/* 判断str字符串中哪些为可打印字符包含空格字符 */
#include <ctype.h>
main()
{
char str[]="a5 @;
";
int i;
for(i=0; str[i]!=0; i++) if(isprint(str[i])) printf("str[%d] is printable character:%d\n",i,str[i]);
}
执行: str[0] is printable character:a
str[1] is printable character:5
str[2] is printable character:
str[3] is printable character:@
str[4] is printable character:;
isspace
isspace(测试字符是否为空格字符)
相关函数:isgraph
表头文件:#include <ctype.h>
定义函数:int isspace(int c)
函数说明:检查参数c是否为空格字符,也就是判断是否为空格('')、定位字符('\t')、CR('\r')、换行('\n')、垂直定位字符('\v')或翻页('\f')的情况。
返回值:若参数c为空格字符,则返回TRUE,否则返回NULL(0)。
附加说明:此为宏定义,非真正函数。
范例:
/* 将字符串str[]中内含的空格字符找出,并显示空格字符的ASCII码 */
#include <ctype.h>
main()
{
char str="123c @# FD\tsP[e?\n";
int i;
for(i=0; str[i]!=0; i++) if(isspace(str[i])) printf("str[%d] is a white-space character:%d\n",i,str[i]);
}
执行: str[4] is a white-space character:32
str[7] is a white-space character:32
str[10] is a white-space character:9 /* \t */
str[16] is a white-space character:10 /* \t */
ispunct
ispunct(测试字符是否为标点符号或特殊符号)
相关函数:isspace,isdigit,isalpha
表头文件:#include <ctype.h>
定义函数:int ispunct(int c)
函数说明:检查参数c是否为标点符号或特殊符号。返回TRUE也就是代表参数c为非空格、非数字和非英文字母。
返回值:若参数c为标点符号或特殊符号,则返回TRUE,否则返回NULL(0)。
附加说明:此为宏定义,非真正函数。
范例:
/* 列出字符串str中的标点符号或特殊符号 */
#include <ctype.h>
main()
{
char str[]="123c@ #FDsP[e?";
int i;
for(i=0; str[i]!=0; i++) if(ispunct(str[i])) printf("%c\n",str[i]);
}
执行: @ # [ ?
isupper
isupper(测试字符是否为大写英文字母)
相关函数:isalpha,islower
表头文件:#include <ctype.h>
定义函数:int isupper(int c)
函数说明:检查参数c是否为大写英文字母。
返回值:若参数c为大写英文字母,则返回TRUE,否则返回NULL(0)。
附加说明:此为宏定义,非真正函数。
范例:
/* 找出字符串str中为大写英文字母的字符 */
#include <ctype.h>
main()
{
char str[]="123c@#FDsP[e?";
int i;
for(i=0; str[i]!=0; i++) if(isupper(str[i])) printf("%c is an uppercase character\n",str[i]);
}
执行: F is an uppercase character
D is an uppercase character
P is an uppercase character
isxdigit
isxdigit(测试字符是否为16进制数字)
相关函数:isalnum,isdigit
表头文件:#include <ctype.h>
定义函数:int isxdigit (int c)
函数说明:检查参数c是否为16进制数字,只要c为下列其中一个情况则返回TRUE。16进制数字:0123456789ABCDEF。
返回值:若参数c为16进制数字,则返回TRUE,否则返回NULL(0)。
附加说明:此为宏定义,非真正函数。
范例:
/* 找出字符串str中为十六进制数字的字符 */
#include <ctype.h>
main()
{
char str[]="123c@#FDsP[e?";
int i;
for(i=0; str[i]!=0; i++) if(isxdigit(str[i])) printf("%c is a hexadecimal digits\n",str[i]);
}
执行: 1 is a hexadecimal digits
2 is a hexadecimal digits
3 is a hexadecimal digits
c is a hexadecimal digits
F is a hexadecimal digits
D is a hexadecimal digits
e is a hexadecimal digits
atof
atof(将字符串转换成浮点型数)
相关函数:atoi,atol,strtod,strtol,strtoul
表头文件:#include <stdlib.h>
定义函数:double atof(const char *nptr);
函数说明:atof()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时('\0')才结束转换,并将结果返回。参数nptr字符串可包含正负号、小数点或E(e)来表示指数部分,如123.456或123e-2。
返回值:返回转换后的浮点型数。
附加说明:atof()与使用strtod(nptr,(char**)NULL)结果相同。
范例:
/* 将字符串a与字符串b转换成数字后相加 */
#include <stdlib.h>
main()
{
char *a="-100.23";
char *b="200e-2";
float c;
c=atof(a)+atof(b);
printf("c=%.2f\n",c);
}
执行: c=-98.23
atoi
atoi(将字符串转换成整型数)
相关函数:atof,atol,strtod,strtol,strtoul
表头文件:#include <stdlib.h>
定义函数:int atoi(const char *nptr);
函数说明:atoi()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时('\0')才结束转换,并将结果返回。
返回值:返回转换后的整型数。
附加说明:atoi()与使用strtol(nptr,(char**)NULL,10);结果相同。
范例:
/* 将字符串a与字符串b转换成数字后相加 */
#include <stdlib.h>
main()
{
char a[]="-100";
char b[]="456";
int c;
c=atoi(a)+atoi(b);
printf("c=%d\n",c);
}
执行: c=356
atol
atol(将字符串转换成长整型数)
相关函数:atof,atoi,strtod,strtol,strtoul
表头文件:#include <stdlib.h>
定义函数:long atol(const char *nptr);
函数说明:atol()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时('\0')才结束转换,并将结果返回。
返回值:返回转换后的长整型数。
附加说明:atol()与使用strtol(nptr,(char**)NULL,10);结果相同。
范例:
/* 将字符串a与字符串b转换成数字后相加 */
#include <stdlib.h>
main()
{
char a[]="1000000000";
char b[]=" 234567890";
long c;
c=atol(a)+atol(b);
printf("c=%d\n",c);
}
执行: c=1234567890
gcvt
gcvt(将浮点型数转换为字符串,取四舍五入)
相关函数:ecvt,fcvt,sprintf
表头文件:#include <stdlib.h>
定义函数:char *gcvt(double number, size_t ndigits, char *buf);
函数说明:gcvt()用来将参数number转换成ASCII码字符串,参数ndigits表示显示的位数。gcvt()与ecvt()和fcvt()不同的地方在于,gcvt()所转换后的字符串包含小数点或正负符号。若转换成功,转换后的字符串会放在参数buf指针所指的空间。
返回值:返回一字符串指针,此地址即为buf指针。
附加说明:
范例:
#include <stdlib.h>
main()
{
double a=123.45;
double b=-1234.56;
char *ptr;
int decpt,sign;
ptr=gcvt(a,5,ptr);
printf("a value=%s\n",ptr);
ptr=gcvt(b,6,ptr);
printf("b value=%s\n",ptr);
}
执行: a value=123.45 b value=-1234.56
strtol
strtol(将字符串转换成长整型数)
相关函数:atof,atoi,atol,strtod,strtoul
表头文件:#include <stdlib.h>
定义函数:long int strtol(const char *nptr, char **endptr, int base);
函数说明:strtol()会将参数nptr字符串根据参数base来转换成长整型数。参数base范围从2至36,或0。参数base代表采用的进制方式,如base值为10则采用10进制,若base值为16则采用16进制等。当base值为0时则是采用10进制做转换,但遇到如'0x'前置字符则会使用16进制做转换。一开始strtol()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,再遇到非数字或字符串结束时('\0')结束转换,并将结果返回。若参数endptr不为NULL,则会将遇到不合条件而终止的nptr中的字符指针由endptr返回。
返回值:返回转换后的长整型数,否则返回ERANGE并将错误代码存入errno中。
附加说明:ERANGE指定的转换字符串超出合法范围。
范例:
/* 将字符串a,b,c分别采用10,2,16进制转换成数字 */
#include <stdlib.h>
main()
{
char a[]="1000000000";
char b[]="1000000000";
char c[]="ffff";
printf("a=%d\n",strtol(a,NULL,10));
printf("b=%d\n",strtol(b,NULL,2));
printf("c=%d\n",strtol(c,NULL,16));
}
执行: a=1000000000 b=512 c=65535
strtoul
strtoul(将字符串转换成无符号长整型数)
相关函数:atof,atoi,atol,strtod,strtol
表头文件:#include <stdlib.h>
定义函数:unsigned long int strtoul(const char *nptr, char **endptr, int base);
函数说明:strtoul()会将参数nptr字符串根据参数base来转换成无符号的长整型数。参数base范围从2至36,或0。参数base代表采用的进制方式,如base值为10则采用10进制,若base值为16则采用16进制数等。当base值为0时则是采用10进制做转换,但遇到如'0x'前置字符则会使用16进制做转换。一开始strtoul()会扫描参数nptr字符串,跳过前面的空格字符串,直到遇上数字或正负符号才开始做转换,再遇到非数字或字符串结束时('\0')结束转换,并将结果返回。若参数endptr不为NULL,则会将遇到不合条件而终止的nptr中的字符指针由endptr返回。
返回值:返回转换后的长整型数,否则返回ERANGE并将错误代码存入errno中。
附加说明:ERANGE指定的转换字符串超出合法范围。
范例:参考strtol()
toascii
toascii(将整型数转换成合法的ASCII码字符)
相关函数:isascii,toupper,tolower
表头文件:#include <ctype.h>
定义函数:int toascii(int c)
函数说明:toascii()会将参数c转换成7位的unsigned char值,第八位则会被清除,此字符即会被转成ASCII码字符。
返回值:将转换成功的ASCII码字符值返回。
范例:
#include <ctype.h>
main()
{
int a=217;
char b;
printf("before toascii() : a value =%d(%c)\n",a,a);
b=toascii(a);
printf("after toascii() : a value =%d(%c)\n",b,b);
}
执行: beforetoascii() : a value =217()
aftertoascii() : a value =89(Y)
tolower
tolower(将大写字母转换成小写字母)
相关函数:isalpha,toupper
表头文件:#include <ctype.h>
定义函数:int tolower(int c);
函数说明:若参数c为大写字母则将该对应的小写字母返回。
返回值:返回转换后的小写字母,若不须转换则将参数c值返回。
附加说明:
范例:
/* 将s字符串内的大写字母转换成小写字母 */
#include <ctype.h>
main()
{
char s[]="aBcDeFgH12345;
!#$";
int i;
printf("before tolower() : %s\n",s);
for(i=0; i<sizeof(s); i++) s[i]=tolower(s[i]);
printf("after tolower() : %s\n",s);
}
执行: before tolower() : aBcDeFgH12345;!#
$ after tolower() : abcdefgh12345;!#
$
toupper
toupper(将小写字母转换成大写字母)
相关函数:isalpha,tolower
表头文件:#include <ctype.h>
定义函数:int toupper(int c);
函数说明:若参数c为小写字母则将该对应的大写字母返回。
返回值:返回转换后的大写字母,若不须转换则将参数c值返回。
附加说明:
范例:
/* 将s字符串内的小写字母转换成大写字母 */
#include <ctype.h>
main()
{
char s[]="aBcDeFgH12345;
!#$";
int i;
printf("before toupper() : %s\n",s);
for(i=0; i<sizeof(s); i++) s[i]=toupper(s[i]);
printf("after toupper() : %s\n",s);
}
执行: before toupper() : aBcDeFgH12345;!#
$ after toupper() : ABCDEFGH12345;!#
$
内存控制篇 3
TODO
calloc
calloc(配置内存空间)
相关函数:malloc,free,realloc,brk
表头文件:#include <stdlib.h>
定义函数:void *calloc(size_t nmemb, size_t size);
函数说明:calloc()用来配置nmemb个相邻的内存单位,每一单位的大小为size,并返回指向第一个元素的指针。这和下列的方式效果相同:malloc(nmemb*size);不过,在利用calloc()配置内存时会将内存内容初始化为0。
返回值:若配置成功则返回一指针,失败则返回NULL。
范例:
/* 动态配置10个struct test空间 */
#include <stdlib.h>
struct test
{
int a[10];
char b[20];
}
main()
{
struct test *ptr=calloc(sizeof(
struct test),10);
}
free
free(释放原先配置的内存)
相关函数:malloc,calloc,realloc,brk
表头文件:#include <stdlib.h>
定义函数:void free(void *ptr);
函数说明:参数ptr为指向先前由malloc()、calloc()或realloc()所返回的内存指针。调用free()后ptr所指的内存空间便会被收回。假若参数ptr所指的内存空间已被收回或是未知的内存地址,则调用free()可能会有无法预期的情况发生。若参数ptr为NULL,则free()不会有任何作用。
getpagesize
getpagesize(取得内存分页大小)
相关函数:sbrk
表头文件:#include <unistd.h>
定义函数:size_t getpagesize(void);
函数说明:返回一分页的大小,单位为字节(byte)。此为系统的分页大小,不一定会和硬件分页大小相同。
返回值:内存分页大小。附加说明在Intel x86上其返回值应为4096bytes。
范例:
#include <unistd.h>
main()
{
printf("page size = %d\n",getpagesize());
}
malloc
malloc(配置内存空间)
相关函数:calloc,free,realloc,brk
表头文件:#include <stdlib.h>
定义函数:void * malloc(size_t size);
函数说明:malloc()用来配置内存空间,其大小由指定的size决定。
返回值:若配置成功则返回一指针,失败则返回NULL。
范例:
void p = malloc(1024);
/*配置1k的内存*/
mmap
mmap(建立内存映射)
相关函数:munmap,open
表头文件:#include <unistd.h> #include <sys/mman.h>
定义函数:void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offsize);
函数说明:mmap()用来将某个文件内容映射到内存中,对该内存区域的存取即是直接对该文件内容的读写。参数start指向欲对应的内存起始地址,通常设为NULL,代表让系统自动选定地址,对应成功后该地址会返回。参数length代表将文件中多大的部分对应到内存。 参数 prot代表映射区域的保护方式有下列组合 PROT_EXEC 映射区域可被执行 PROT_READ 映射区域可被读取 PROT_WRITE 映射区域可被写入 PROT_NONE 映射区域不能存取 参数 flags会影响映射区域的各种特性 MAP_FIXED 如果参数start所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。通常不鼓励用此旗标。 MAP_SHARED 对映射区域的写入数据会复制回文件内,而且允许其他映射该文件的进程共享。 MAP_PRIVATE 对映射区域的写入操作会产生一个映射文件的复制,即私人的"写入时复制"(copy on write)对此区域作的任何修改都不会写回原来的文件内容。 MAP_ANONYMOUS 建立匿名映射。此时会忽略参数fd,不涉及文件,而且映射区域无法和其他进程共享。 MAP_DENYWRITE 只允许对映射区域的写入操作,其他对文件直接写入的操作将会被拒绝。 MAP_LOCKED 将映射区域锁定住,表示该区域不会被置换(swap)。 在调用mmap()时必须指定MAP_SHARED或MAP_PRIVATE。参数fd为open()返回的文件描述词,代表欲映射到内存的文件。参数offset为文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是分页大小的整数倍。
返回值:若映射成功则返回映射区的内存起始地址,否则返回MAP_FAILED(-1),错误原因存于errno中。
错误代码:EBADF 参数fd不是有效的文件描述词 EACCES 存取权限有误。如果是MAP_PRIVATE情况下文件必须可读,使用MAP_SHARED则要有PROT_WRITE以及该文件要能写入。 EINVAL 参数start、length或offset有一个不合法。 EAGAIN 文件被锁住,或是有太多内存被锁住。 ENOMEM 内存不足。
范例:
/* 利用mmap()来读取/etc/passwd文件内容 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
main()
{
int fd;
void *start;
struct stat sb;
fd=open("/etc/passwd",O_RDONLY);
/*打开/etc/passwd*/
fstat(fd,&sb);
/*取得文件大小*/
start=mmap(NULL,sb.st_size,PROT_READ,MAP_PRIVATE,fd,0);
if(start == MAP_FAILED)
/*判断是否映射成功*/ return;
printf("%s",start);
munmap(start,sb.st_size);
/*解除映射*/
closed(fd);
}
执行: root : x :0 : root : /root : /bin/bash
bin : x :1 :1 : bin : /bin :
daemon : x :2 : 2 :daemon : /sbin
adm : x :3 :4 : adm : /var/adm :
lp : x :4 :7 : lp : /var/spool/lpd :
sync : x :5 :0 : sync : /sbin : bin/sync :
shutdown : x :6 :0 : shutdown : /sbin : /sbin/shutdown
halt : x :7 :0 : halt : /sbin : /sbin/halt
mail : x :8 :12 : mail : /var/spool/mail :
news : x :9 :13 : news : /var/spool/news :
uucp : x :10 :14 : uucp : /var/spool/uucp :
operator : x :11 : 0 :operator : /root:
games : x : 12 :100 : games :/usr/games:
gopher : x :13 :30 : gopher : /usr/lib/gopher-data:
ftp : x :14 :50 : FTP User : /home/ftp:
nobody : x :99:99: Nobody : /:
xfs :x :100 :101 : X Font Server : /etc/xll/fs : /bin/false
gdm : x : 42 :42::/home/gdm:/bin/bash
kids:x:500:500:/home/kids:/bin/bash
munmap
munmap(解除内存映射)
相关函数:mmap
表头文件:#include <unistd.h> #include <sys/mman.h>
定义函数:int munmap(void *start, size_t length);
函数说明:munmap()用来取消参数start所指的映射内存起始地址,参数length则是欲取消的内存大小。当进程结束或利用exec相关函数来执行其他程序时,映射内存会自动解除,但关闭对应的文件描述词时不会解除映射。
返回值:如果解除映射成功则返回0,否则返回-1,错误原因存于errno中错误代码EINVAL 参数 start或length不合法。
范例:参考mmap()
日期时间篇 4
TODO
asctime
asctime(将时间和日期以字符串格式表示)
相关函数:time,ctime,gmtime,localtime
表头文件:#include <time.h>
定义函数:char *asctime(const struct tm *timeptr);
函数说明:asctime()将参数timeptr所指的tm结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果以字符串形态返回。此函数已经由时区转换成当地时间,字符串格式为:"Wed Jun 30 21:49:08 1993\n"
返回值:若再调用相关的时间日期函数,此字符串可能会被破坏。此函数与ctime不同处在于传入的参数是不同的结构。
附加说明:返回一字符串表示目前当地的时间日期。
范例:
#include <time.h>
main()
{
time_t timep;
time(&timep);
printf("%s",asctime(gmtime(&timep)));
}
执行: Sat Oct 28 02:10:06 2000
ctime
ctime(将时间和日期以字符串格式表示)
相关函数:time,asctime,gmtime,localtime
表头文件:#include <time.h>
定义函数:char *ctime(const time_t *timep);
函数说明:ctime()将参数timep所指的time_t结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果以字符串形态返回。此函数已经由时区转换成当地时间,字符串格式为"Wed Jun 30 21:49:08 1993\n"。若再调用相关的时间日期函数,此字符串可能会被破坏。
返回值:返回一字符串表示目前当地的时间日期。
范例:
#include <time.h>
main()
{
time_t timep;
time(&timep);
printf("%s",ctime(&timep));
}
执行: Sat Oct 28 10:12:05 2000
gettimeofday
gettimeofday(取得目前的时间)
相关函数:time,ctime,ftime,settimeofday
表头文件:#include <sys/time.h> #include <unistd.h>
定义函数:int gettimeofday(struct timeval *tv, struct timezone *tz)
函数说明:gettimeofday()会把目前的时间有tv所指的结构返回,当地时区的信息则放到tz所指的结构中。 timeval结构定义为: struct timeval{ long tv_sec; /秒/ long tv_usec; /微秒/ }; timezone结构定义为: struct timezone{ int tz_minuteswest; /和Greenwich时间差了多少分钟/ int tz_dsttime; /日光节约时间的状态/ }; 上述两个结构都定义在/usr/include/sys/time.h。tz_dsttime所代表的状态如下 DST_NONE /不使用/ DST_USA /美国/ DST_AUST /澳洲/ DST_WET /西欧/ DST_MET /中欧/ DST_EET /东欧/ DST_CAN /加拿大/ DST_GB /大不列颠/ DST_RUM /罗马尼亚/ DST_TUR /土耳其/ DST_AUSTALT /澳洲(1986年以后)/
返回值:成功则返回0,失败返回-1,错误代码存于errno。附加说明EFAULT指针tv和tz所指的内存空间超出存取权限。
范例:
#include <sys/time.h>
#include <unistd.h>
main()
{
struct timeval tv;
struct timezone tz;
gettimeofday(&tv, &tz);
printf("tv_sec: %d\n", tv.tv_sec);
printf("tv_usec: %d\n", tv.tv_usec);
printf("tz_minuteswest: %d\n", tz.tz_minuteswest);
printf("tz_dsttime: %d\n", tz.tz_dsttime);
}
执行: tv_sec: 974857339
tv_usec: 136996
tz_minuteswest: -540
tz_dsttime: 0
gmtime
gmtime(取得目前时间和日期)
相关函数:time, asctime, ctime, localtime
表头文件:#include <time.h>
定义函数:struct tm *gmtime(const time_t *timep);
函数说明:gmtime()将参数timep所指的time_t结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果由结构tm返回。 结构tm的定义为 struct tm { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; }; int tm_sec 代表目前秒数,正常范围为0-59,但允许至61秒 int tm_min 代表目前分数,范围0-59 int tm_hour 从午夜算起的时数,范围为0-23 int tm_mday 目前月份的日数,范围01-31 int tm_mon 代表目前月份,从一月算起,范围从0-11 int tm_year 从1900年算起至今的年数 int tm_wday 一星期的日数,从星期一开始算,范围为0-6 int tm_yday 从今年1月1日算起至今的天数,范围为0-365 int tm_isdst 日光节约时间的旗标 此函数返回的时间日期未经时区转换,而是UTC时间。
返回值:返回结构tm代表目前UTC时间
范例:
#include <time.h>
main()
{
char *wday[]=
{
"Sun","Mon","Tue","Wed","Thu","Fri","Sat"
};
time_t timep;
struct tm *p;
time(&timep);
p = gmtime(&timep);
printf("%d%d%d", (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday);
printf("%s%d:%d:%d\n", wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec);
}
执行: 2000/10/28 Sat 8:15:38
localtime
localtime(取得当地目前时间和日期)
相关函数:time, asctime, ctime, gmtime
表头文件:#include <time.h>
定义函数:struct tm *localtime(const time_t *timep);
函数说明:localtime()将参数timep所指的time_t结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果由结构tm返回。结构tm的定义请参考gmtime()。此函数返回的时间日期已经转换成当地时区。
返回值:返回结构tm代表目前的当地时间。
范例:
#include <time.h>
main()
{
char *wday[]=
{
"Sun","Mon","Tue","Wed","Thu","Fri","Sat"
} ; time_t timep; struct tm *p; time(&timep); p=localtime(&timep); /*取得当地时间*/ printf("%d%d%d", (1900+p->tm_year), (1+p->tm_mon), p->tm_mday); printf("%s%d:%d:%d\n", wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec);
}
执行: 2000/10/28 Sat 11:12:22
mktime
mktime(将时间结构数据转换成经过的秒数)
相关函数:time,asctime,gmtime,localtime
表头文件:#include <time.h>
定义函数:time_t mktime(struct tm *timeptr);
函数说明:mktime()用来将参数timeptr所指的tm结构数据转换成从公元1970年1月1日0时0分0秒算起至今的UTC时间所经过的秒数。
返回值:返回经过的秒数。
范例:
/* 用time()取得时间(秒数),利用localtime() 转换成struct tm 再利用mktime()将struct tm转换成原来的秒数 */
#include <time.h>
main()
{
time_t timep;
struct tm *p;
time(&timep);
printf("time() : %d\n",timep);
p=localtime(&timep);
timep = mktime(p);
printf("time()->localtime()->mktime():%d\n",timep);
}
执行: time():974943297
time()->localtime()->mktime():974943297
settimeofday
settimeofday(设置目前时间)
相关函数:time,ctime,ftime,gettimeofday
表头文件:#include <sys/time.h> #include <unistd.h>
定义函数:int settimeofday(const struct timeval *tv, const struct timezone *tz);
函数说明:settimeofday()会把目前时间设成由tv所指的结构信息,当地时区信息则设成tz所指的结构。详细的说明请参考gettimeofday()。注意,只有root权限才能使用此函数修改时间。
返回值:成功则返回0,失败返回-1,错误代码存于errno。
错误代码:EPERM 并非由root权限调用settimeofday(),权限不够。 EINVAL 时区或某个数据是不正确的,无法正确设置时间。
time
time(取得目前的时间)
相关函数:ctime,ftime,gettimeofday
表头文件:#include <time.h>
定义函数:time_t time(time_t *t);
函数说明:此函数会返回从公元1970年1月1日的UTC时间从0时0分0秒算起到现在所经过的秒数。如果t并非空指针的话,此函数也会将返回值存到t指针所指的内存。
返回值:成功则返回秒数,失败则返回((time_t)-1)值,错误原因存于errno中。
范例:
#include <time.h>
main()
{
int seconds= time((time_t *)NULL);
printf("%d\n",seconds);
}
执行: 9.73E+08
内存及字符串操作篇 5
TODO
bcmp
bcmp(比较内存内容)
相关函数:bcmp,strcasecmp,strcmp,strcoll,strncmp,strncasecmp
表头文件:#include <string.h>
定义函数:int bcmp(const void *s1, const void *s2, int n);
函数说明:bcmp()用来比较s1和s2所指的内存区间前n个字节,若参数n为0,则返回0。
返回值:若参数s1和s2所指的内存内容都完全相同则返回0值,否则返回非零值。
附加说明:建议使用memcmp()取代。
范例:参考memcmp()。
bcopy
bcopy(拷贝内存内容)
相关函数:memccpy,memcpy,memmove,strcpy,strncpy
表头文件:#include <string.h>
定义函数:void bcopy(const void *src, void *dest, int n);
函数说明:bcopy()与memcpy()一样都是用来拷贝src所指的内存内容前n个字节到dest所指的地址,不过参数src与dest在传给函数时是相反的位置。
返回值:
附加说明:建议使用memcpy()取代
范例:
#include <string.h>
main()
{
char dest[30]="string(a)";
char src[30]="string\0string";
int i;
bcopy(src,dest,30);
/* src指针放在前 */
printf("bcopy(): ");
for(i=0; i<30; i++) printf("%c",dest[i]);
memcpy(dest, src,30);
/* dest指针放在后 */
printf("\nmemcpy() : ");
for(i=0; i<30; i++) printf("%c",dest[i]);
}
执行: bcopy() : string string
memcpy() : string string
bzero
bzero(将一段内存内容全清为零)
相关函数:memset,swab
表头文件:#include <string.h>
定义函数:void bzero(void *s, int n);
函数说明:bzero()会将参数s所指的内存区域前n个字节,全部设为零值。相当于调用memset((void*)s,0,size_t n);
返回值:
附加说明:建议使用memset取代
范例:参考memset()。
index
index(查找字符串中第一个出现的指定字符)
相关函数:rindex,strchr,strrchr
表头文件:#include <string.h>
定义函数:char *index(const char *s, int c);
函数说明:index()用来找出参数s字符串中第一个出现的参数c地址,然后将该字符出现的地址返回。字符串结束字符(NULL)也视为字符串一部分。
返回值:如果找到指定的字符则返回该字符所在地址,否则返回0。
范例:
#include <string.h>
main()
{
char *s ="0123456789012345678901234567890";
char *p;
p = index(s,'5');
printf("%s\n",p);
}
执行: 5.68E+25
memccpy
memccpy(拷贝内存内容)
相关函数:bcopy,memcpy,memmove,strcpy,strncpy
表头文件:#include <string.h>
定义函数:void *memccpy(void *dest, const void *src, int c, size_t n);
函数说明:memccpy()用来拷贝src所指的内存内容前n个字节到dest所指的地址上。与memcpy()不同的是,memccpy()会在复制时检查参数c是否出现,若是则返回dest中值为c的下一个字节地址。
返回值:返回指向dest中值为c的下一个字节指针。返回值为0表示在src所指内存前n个字节中没有值为c的字节。
范例:
#include <string.h>
main()
{
char a[]="string[a]";
char b[]="string(b)";
memccpy(a,b,'B',sizeof(b));
printf("memccpy():%s\n",a);
}
执行: memccpy():string(b)
memchr
memchr(在某一内存范围中查找一特定字符)
相关函数:index,rindex,strchr,strpbrk,strrchr,strsep,strspn,strstr
表头文件:#include <string.h>
定义函数:void *memchr(const void *s, int c, size_t n);
函数说明:memchr()从头开始搜寻s所指的内存内容前n个字节,直到发现第一个值为c的字节,则返回指向该字节的指针。
返回值:如果找到指定的字节则返回该字节的指针,否则返回0。
范例:
#include <string.h>
main()
{
char *s="0123456789012345678901234567890";
char *p;
p=memchr(s,'5',10);
printf("%s\n",p);
}
执行: 5.68E+25
memcmp
memcmp(比较内存内容)
相关函数:bcmp,strcasecmp,strcmp,strcoll,strncmp,strncasecmp
表头文件:#include <string.h>
定义函数:int memcmp(const void *s1, const void *s2, size_t n);
函数说明:memcmp()用来比较s1和s2所指的内存区间前n个字符。字符串大小的比较是以ASCII码表上的顺序来决定,次顺序亦为字符的值。memcmp()首先将s1第一个字符值减去s2第一个字符的值,若差为0则再继续比较下个字符,若差值不为0则将差值返回。例如,字符串"Ac"和"ba"比较则会返回字符'A'(65)和'b'(98)的差值(-33)。
返回值:若参数s1和s2所指的内存内容都完全相同则返回0值。s1若大于s2则返回大于0的值。s1若小于s2则返回小于0的值。
范例:
#include <string.h>
main()
{
char *a ="aBcDeF";
char *b="AbCdEf";
char *c="aacdef";
char *d="aBcDeF";
printf("memcmp(a,b):%d\n",memcmp((void*)a,(void*)b,6));
printf("memcmp(a,c):%d\n",memcmp((void*)a,(void*)c,6));
printf("memcmp(a,d):%d\n",memcmp((void*)a,(void*)d,6));
}
执行: memcmp(a,b):1 /字符串a>字符串b,返回1/ memcmp(a,c):-1 /* 字符串a<字符串c,返回-1*/ memcmp(a,d):0 /字符串a=字符串d,返回0/
memcpy
memcpy(拷贝内存内容)
相关函数:bcopy,memccpy,memcpy,memmove,strcpy,strncpy
表头文件:#include <string.h>
定义函数:void *memcpy(void *dest, const void *src, size_t n);
函数说明:memcpy()用来拷贝src所指的内存内容前n个字节到dest所指的内存地址上。与strcpy()不同的是,memcpy()会完整的复制n个字节,不会因为遇到字符串结束'\0'而结束。
返回值:返回指向dest的指针。
附加说明:指针src和dest所指的内存区域不可重叠。
范例:
#include <string.h>
main()
{
char a[30]="string (a)";
char b[30]="string\0string";
int i;
strcpy(a,b);
printf("strcpy():");
for(i=0; i<30; i++) printf("%c",a[i]);
memcpy(a,b,30);
printf("\nmemcpy() :");
for(i=0; i<30; i++) printf("%c",a[i]);
}
执行: strcpy() : string a )
memcpy() : string string
memmove
memmove(拷贝内存内容)
相关函数:bcopy,memccpy,memcpy,strcpy,strncpy
表头文件:#include <string.h>
定义函数:void *memmove(void *dest, const void *src, size_t n);
函数说明:memmove()与memcpy()一样都是用来拷贝src所指的内存内容前n个字节到dest所指的地址上。不同的是,当src和dest所指的内存区域重叠时,memmove()仍然可以正确的处理,不过执行效率上会比使用memcpy()略慢些。
返回值:返回指向dest的指针。
附加说明:指针src和dest所指的内存区域可以重叠。
范例:参考memcpy()。
memset
memset(将一段内存空间填入某值)
相关函数:bzero,swab
表头文件:#include <string.h>
定义函数:void *memset(void *s, int c, size_t n);
函数说明:memset()会将参数s所指的内存区域前n个字节以参数c填入,然后返回指向s的指针。在编写程序时,若需要将某一数组作初始化,memset()会相当方便。
返回值:返回指向s的指针。
附加说明:参数c虽声明为int,但必须是unsigned char,所以范围在0到255之间。
范例:
#include <string.h>
main()
{
char s[30];
memset(s,'A',sizeof(s));
s[30]='\0';
printf("%s\n",s);
}
执行: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
rindex
rindex(查找字符串中最后一个出现的指定字符)
相关函数:index,memchr,strchr,strrchr
表头文件:#include <string.h>
定义函数:char *rindex(const char *s, int c);
函数说明:rindex()用来找出参数s字符串中最后一个出现的参数c地址,然后将该字符出现的地址返回。字符串结束字符(NULL)也视为字符串一部分。
返回值:如果找到指定的字符则返回该字符所在的地址,否则返回0。
范例:
#include <string.h>
main()
{
char *s ="0123456789012345678901234567890";
char *p;
p=rindex(s,'5');
printf("%s\n",p);
}
执行: 567890
strcasecmp
strcasecmp(忽略大小写比较字符串)
相关函数:bcmp,memcmp,strcmp,strcoll,strncmp
表头文件:#include <string.h>
定义函数:int strcasecmp(const char *s1, const char *s2);
函数说明:strcasecmp()用来比较参数s1和s2字符串,比较时会自动忽略大小写的差异。
返回值:若参数s1和s2字符串相同则返回0。s1长度大于s2长度则返回大于0的值,s1长度若小于s2长度则返回小于0的值。
范例:
#include <string.h>
main()
{
char *a="aBcDeF";
char *b="AbCdEf";
if(!strcasecmp(a,b)) printf("%s=%s\n",a,b);
}
执行: aBcDeF=AbCdEf
strcat
strcat(连接两字符串)
相关函数:bcopy,memccpy,memcpy,strcpy,strncpy
表头文件:#include <string.h>
定义函数:char *strcat(char *dest, const char *src);
函数说明:strcat()会将参数src字符串拷贝到参数dest所指的字符串尾。第一个参数dest要有足够的空间来容纳要拷贝的字符串。
返回值:返回参数dest的字符串起始地址
范例:
#include <string.h>
main()
{
char a[30]="string(1)";
char b[]="string(2)";
printf("before strcat() : %s\n",a);
printf("after strcat() : %s\n",strcat(a,b));
}
执行: beforestrcat() : string(1)
afterstrcat() : string(1)string(2)
strchr
strchr(查找字符串中第一个出现的指定字符)
相关函数:index,memchr,rindex,strpbrk,strsep,strspn,strstr,strtok
表头文件:#include <string.h>
定义函数:char *strchr(const char *s, int c);
函数说明:strchr()用来找出参数s字符串中第一个出现的参数c地址,然后将该字符出现的地址返回。
返回值:如果找到指定的字符则返回该字符所在地址,否则返回0。
范例:
#include <string.h>
main()
{
char *s="0123456789012345678901234567890";
char *p;
p=strchr(s,'5');
printf("%s\n",p);
}
执行: 5.68E+25
strcmp
strcmp(比较字符串)
相关函数:bcmp,memcmp,strcasecmp,strncasecmp,strcoll
表头文件:#include <string.h>
定义函数:int strcmp(const char *s1, const char *s2);
函数说明:strcmp()用来比较参数s1和s2字符串。字符串大小的比较是以ASCII码表上的顺序来决定,此顺序亦为字符的值。strcmp()首先将s1第一个字符值减去s2第一个字符值,若差值为0则再继续比较下个字符,若差值不为0则将差值返回。例如字符串"Ac"和"ba"比较则会返回字符"A"(65)和'b'(98)的差值(-33)。
返回值:若参数s1和s2字符串相同则返回0。s1若大于s2则返回大于0的值。s1若小于s2则返回小于0的值。
范例:
#include <string.h>
main()
{
char *a="aBcDeF";
char *b="AbCdEf";
char *c="aacdef";
char *d="aBcDeF";
printf("strcmp(a,b) : %d\n",strcmp(a,b));
printf("strcmp(a,c) : %d\n",strcmp(a,c));
printf("strcmp(a,d) : %d\n",strcmp(a,d));
}
执行: strcmp(a,b) : 32 strcmp(a,c) :-31 strcmp(a,d) : 0
strcoll
strcoll(采用目前区域的字符排列次序来比较字符串)
相关函数:strcmp,bcmp,memcmp,strcasecmp,strncasecmp
表头文件:#include <string.h>
定义函数:int strcoll(const char *s1, const char *s2);
函数说明:strcoll()会依环境变量LC_COLLATE所指定的文字排列次序来比较s1和s2字符串。
返回值:若参数s1和s2字符串相同则返回0。s1若大于s2则返回大于0的值。s1若小于s2则返回小于0的值。
附加说明:若LC_COLLATE为"POSIX"或"C",则strcoll()与strcmp()作用完全相同。
范例:参考strcmp()。
strcpy
strcpy(拷贝字符串)
相关函数:bcopy,memcpy,memccpy,memmove
表头文件:#include <string.h>
定义函数:char *strcpy(char *dest, const char *src);
函数说明:strcpy()会将参数src字符串拷贝至参数dest所指的地址。
返回值:返回参数dest的字符串起始地址。
附加说明:如果参数dest所指的内存空间不够大,可能会造成缓冲溢出(buffer Overflow)的错误情况,在编写程序时请特别留意,或者用strncpy()来取代。
范例:
#include <string.h>
main()
{
char a[30]="string(1)";
char b[]="string(2)";
printf("before strcpy() :%s\n",a);
printf("after strcpy() :%s\n",strcpy(a,b));
}
执行: beforestrcpy() :string(1)
afterstrcpy() :string(2)
strcspn
strcspn(返回字符串中连续不含指定字符串内容的字符数)
相关函数:strspn
表头文件:#include <string.h>
定义函数:size_t strcspn(const char *s, const char *reject);
函数说明:strcspn()从参数s字符串的开头计算连续的字符,而这些字符都完全不在参数reject所指的字符串中。简单地说,若strcspn()返回的数值为n,则代表字符串s开头连续有n个字符都不含字符串reject内的字符。
返回值:返回字符串s开头连续不含字符串reject内的字符数目。
范例:
#include <string.h>
main()
{
char *str="Linux was first developed for 386/486-based pcs.";
printf("%d\n",strcspn(str," "));
printf("%d\n",strcspn(str,"/-"));
printf("%d\n",strcspn(str,"1234567890"));
}
执行: 5 /* 只计算到""的出现,所以返回"Linux"的长度 */
33 /* 计算到出现"/"或"-",所以返回到"6"的长度 */
30 /* 计算到出现数字字符为止,所以返回"3"出现前的长度 */
strdup
strdup(复制字符串)
相关函数:calloc,malloc,realloc,free
表头文件:#include <string.h>
定义函数:char *strdup(const char *s);
函数说明:strdup()会先用malloc()配置与参数s字符串相同的空间大小,然后将参数s字符串的内容复制到该内存地址,然后把该地址返回。该地址最后可以利用free()来释放。
返回值:返回一字符串指针,该指针指向复制后的新字符串地址。若返回NULL表示内存不足。
范例:
#include <string.h>
main()
{
char a[]="strdup";
char *b;
b=strdup(a);
printf("b[]=\"%s\"\n",b);
}
执行: b[]="strdup"
strlen
strlen(返回字符串长度)
相关函数:
表头文件:#include <string.h>
定义函数:size_t strlen(const char *s);
函数说明:strlen()用来计算指定的字符串s的长度,不包括结束字符"\0"。
返回值:返回字符串s的字符数。
范例:
/* 取得字符串str的长度 */
#include <string.h>
main()
{
char *str = "12345678";
printf("str length = %d\n", strlen(str));
}
执行: str length = 8
strncasecmp
strncasecmp(忽略大小写比较字符串)
相关函数:bcmp,memcmp,strcmp,strcoll,strncmp
表头文件:#include <string.h>
定义函数:int strncasecmp(const char *s1, const char *s2, size_t n);
函数说明:strncasecmp()用来比较参数s1和s2字符串前n个字符,比较时会自动忽略大小写的差异。
返回值:若参数s1和s2字符串相同则返回0。s1若大于s2则返回大于0的值,s1若小于s2则返回小于0的值。
范例:
#include <string.h>
main()
{
char *a="aBcDeF";
char *b="AbCdEf";
if(!strncasecmp(a,b,6)) printf("%s =%s\n",a,b);
}
执行: aBcDeF=AbCdEf
strncat
strncat(连接两字符串)
相关函数:bcopy,memccpy,memcpy,strcpy,strncpy
表头文件:#include <string.h>
定义函数:char *strncat(char *dest, const char *src, size_t n);
函数说明:strncat()会将参数src字符串拷贝n个字符到参数dest所指的字符串尾。第一个参数dest要有足够的空间来容纳要拷贝的字符串。
返回值:返回参数dest的字符串起始地址。
范例:
#include <string.h>
main()
{
char a[30]="string(1)";
char b[]="string(2)";
printf("before strncat() :%s\n", a);
printf("after strncat() :%s\n", strncat(a,b,6));
}
执行: beforestrncat() : string(1)
afterstrncat() : string(1) string
strncpy
strncpy(拷贝字符串)
相关函数:bcopy,memccpy,memcpy,memmove
表头文件:#include <string.h>
定义函数:char *strncpy(char *dest, const char *src, size_t n);
函数说明:strncpy()会将参数src字符串拷贝前n个字符至参数dest所指的地址。
返回值:返回参数dest的字符串起始地址。
范例:
#include <string.h>
main()
{
char a[30]="string(1)";
char b[]="string(2)";
printf("before strncpy() : %s\n",a);
printf("after strncpy() : %s\n",strncpy(a,b,6));
}
执行: beforestrncpy() : string(1)
afterstrncpy() : string(1)
strpbrk
strpbrk(查找字符串中第一个出现的指定字符)
相关函数:index,memchr,rindex,strpbrk,strsep,strspn,strstr,strtok
表头文件:#include <string.h>
定义函数:char *strpbrk(const char *s, const char *accept);
函数说明:strpbrk()用来找出参数s字符串中最先出现存在参数accept字符串中的任意字符。
返回值:如果找到指定的字符则返回该字符所在地址,否则返回0。
范例:
#include <string.h>
main()
{
char *s="0123456789012345678901234567890";
char *p;
p=strpbrk(s,"a1 839");
/*1会最先在s字符串中找到*/
printf("%s\n",p);
p=strpbrk(s,"4398");
/*3会最先在s字符串中找到*/
printf("%s\n",p);
}
执行: 1.23E+29
strrchr
strrchr(查找字符串中最后出现的指定字符)
相关函数:index,memchr,rindex,strpbrk,strsep,strspn,strstr,strtok
表头文件:#include <string.h>
定义函数:char *strrchr(const char *s, int c);
函数说明:strrchr()用来找出参数s字符串中最后一个出现的参数c地址,然后将该字符出现的地址返回。
返回值:如果找到指定的字符则返回该字符所在地址,否则返回0。
范例:
#include <string.h>
main()
{
char *s="0123456789012345678901234567890";
char *p;
p=strrchr(s,'5');
printf("%s\n",p);
}
执行: 567890
strspn
strspn(返回字符串中连续不含指定字符串内容的字符数)
相关函数:strcspn,strchr,strpbrk,strsep,strstr
表头文件:#include <string.h>
定义函数:size_t strspn(const char *s, const char *accept);
函数说明:strspn()从参数s字符串的开头计算连续的字符,而这些字符都完全是accept所指字符串中的字符。简单地说,若strspn()返回的数值为n,则代表字符串s开头连续有n个字符都是属于字符串accept内的字符。
返回值:返回字符串s开头连续包含字符串accept内的字符数目。
范例:
#include <string.h>
main()
{
char *str="Linux was first developed for 386/486-based PCs.";
char *t1="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
printf("%d\n",strspn(str,t1));
}
执行: 5 /计算大小写字母。不包含" ",所以返回Linux的长度。/
strstr
strstr(在一字符串中查找指定的字符串)
相关函数:index,memchr,rindex,strchr,strpbrk,strsep,strspn,strtok
表头文件:#include <string.h>
定义函数:char *strstr(const char *haystack, const char *needle);
函数说明:strstr()会从字符串haystack中搜寻字符串needle,并将第一次出现的地址返回。
返回值:返回指定字符串第一次出现的地址,否则返回0。
范例:
#include <string.h>
main()
{
char *s="012345678901234567890123456789";
char *p;
p=strstr(s,"901");
printf("%s\n",p);
}
执行: 9.01E+21
strtok
strtok(分割字符串)
相关函数:index,memchr,rindex,strpbrk,strsep,strspn,strstr
表头文件:#include <string.h>
定义函数:char *strtok(char *s, const char *delim);
函数说明:strtok()用来将字符串分割成一个个片段。参数s指向欲分割的字符串,参数delim则为分割字符串,当strtok()在参数s的字符串中发现到参数delim的分割字符时则会将该字符改为\0字符。在第一次调用时,strtok()必需给予参数s字符串,往后的调用则将参数s设置成NULL。每次调用成功则返回下一个分割后的字符串指针。
返回值:返回下一个分割后的字符串指针,已无从分割则返回NULL。
范例:
#include <string.h>
main()
{
char s[]="ab-cd : ef;
gh :i-jkl;
mnop;
qrs-tu: vwx-y;
z";
char *delim="-: ";
char *p;
printf("%s ",strtok(s,delim));
while((p=strtok(NULL,delim))) printf("%s ",p);
printf("\n");
}
执行: ab cd ef;gh i jkl;mnop;qrs tu vwx y;z /-与:字符已经被\0字符取代/
常用数学函数篇 6
TODO
abs
abs(计算整型数的绝对值)
相关函数:labs, fabs
表头文件:#include <stdlib.h>
定义函数:int abs(int j)
函数说明:abs()用来计算参数j的绝对值,然后将结果返回。
返回值:返回参数j的绝对值结果。
范例:
#include <stdlib.h>
main()
{
int answer;
answer = abs(-12);
printf("|-12| = %d\n", answer);
}
执行: |-12| = 12
acos
acos(取反余弦函数数值)
相关函数:asin, atan, atan2, cos, sin, tan
表头文件:#include <math.h>
定义函数:double acos(double x);
函数说明:acos()用来计算参数x的反余弦值,然后将结果返回。参数x范围为-1至1之间,超过此范围则会失败。
返回值:返回0至PI之间的计算结果,单位为弧度,在函数库中角度均以弧度来表示。
错误代码:EDOM参数x超出范围。
附加说明:使用GCC编译时请加入-lm。
范例:
#include <math.h>
main()
{
double angle;
angle = acos(0.5);
printf("angle = %f\n", angle);
}
执行: angle = 1.047198
asin
asin(取反正弦函数值)
相关函数:acos, atan, atan2, cos, sin, tan
表头文件:#include <math.h>
定义函数:double asin(double x)
函数说明:asin()用来计算参数x的反正弦值,然后将结果返回。参数x范围为-1至1之间,超过此范围则会失败。
返回值:返回-PI/2至PI/2之间的计算结果。
错误代码:EDOM参数x超出范围
附加说明:使用GCC编译时请加入-lm
范例:
#include <math.h>
main()
{
double angle;
angle = asin(0.5);
printf("angle = %f\n",angle);
}
执行: angle = 0.523599
atan
atan(取反正切函数值)
相关函数:acos,asin,atan2,cos,sin,tan
表头文件:#include <math.h>
定义函数:double atan(double x);
函数说明:atan()用来计算参数x的反正切值,然后将结果返回。
返回值:返回-PI/2至PI/2之间的计算结果。
附加说明:使用GCC编译时请加入-lm
范例:
#include <math.h>
main()
{
double angle;
angle = atan(1);
printf("angle = %f\n",angle);
}
执行: angle = 1.570796
atan2
atan2(取得反正切函数值)
相关函数:acos,asin,atan,cos,sin,tan
表头文件:#include <math.h>
定义函数:double atan2(double y, double x);
函数说明:atan2()用来计算参数y/x的反正切值,然后将结果返回。
返回值:返回-PI/2至PI/2之间的计算结果。
附加说明:使用GCC编译时请加入-lm。
范例:
#include <math.h>
main()
{
double angle;
angle = atan2(1,2);
printf("angle = %f\n", angle);
}
执行: angle = 0.463648
ceil
ceil(取不小于参数的最小整型数)
相关函数:fabs
表头文件:#include <math.h>
定义函数:double ceil(double x);
函数说明:ceil()会返回不小于参数x的最小整数值,结果以double形态返回。
返回值:返回不小于参数x的最小整数值。
附加说明:使用GCC编译时请加入-lm。
范例:
#include <math.h>
main()
{
double value[]=
{
4.8,1.12,-2.2,0
} ; int i; for (i=0;value[i]!=0;i++) printf("%f=>%f\n",value[i],ceil(value[i]));
}
执行: 4.800000=>5.000000 1.120000=>2.000000 -2.200000=>-2.000000
cos
cos(取余弦函数值)
相关函数:acos,asin,atan,atan2,sin,tan
表头文件:#include <math.h>
定义函数:double cos(double x);
函数说明:cos()用来计算参数x的余弦值,然后将结果返回。
返回值:返回-1至1之间的计算结果。
附加说明:使用GCC编译时请加入-lm。
范例:
#include <math.h>
main()
{
double answer = cos(0.5);
printf("cos(0.5) = %f\n",answer);
}
执行: cos(0.5) = 0.877583
cosh
cosh(取双曲线余弦函数值)
相关函数:sinh,tanh
表头文件:#include <math.h>
定义函数:double cosh(double x);
函数说明:cosh()用来计算参数x的双曲线余弦值,然后将结果返回。数学定义式为:(exp(x)+exp(-x))/2。
返回值:返回参数x的双曲线余弦值。
附加说明:使用GCC编译时请加入-lm。
范例:
#include <math.h>
main()
{
double answer = cosh(0.5);
printf("cosh(0.5) = %f\n",answer);
}
执行: cosh(0.5) = 1.127626
exp
exp(计算指数)
相关函数:log,log10,pow
表头文件:#include <math.h>
定义函数:double exp(double x);
函数说明:exp()用来计算以e为底的x次方值,即ex值,然后将结果返回。
返回值:返回e的x次方计算结果。
附加说明:使用GCC编译时请加入-lm。
范例:
#include <math.h>
main()
{
double answer;
answer = exp(10);
printf("e^10 =%f\n", answer);
}
执行: e^10 = 22026.465795
frexp
frexp(将浮点型数分为底数与指数)
相关函数:ldexp,modf
表头文件:#include <math.h>
定义函数:double frexp(double x, int *exp);
函数说明:frexp()用来将参数x的浮点型数切割成底数和指数。底数部分直接返回,指数部分则借参数exp指针返回,将返回值乘以2的exp次方即为x的值。
返回值:返回参数x的底数部分,指数部分则存于exp指针所指的地址。
附加说明:使用GCC编译时请加入-lm。
范例:
#include <math.h>
main()
{
int exp;
double fraction;
fraction = frexp(1024,&exp);
printf("exp = %d\n",exp);
printf("fraction = %f\n", fraction);
}
执行: exp = 11 fraction = 0.500000 /* 0.5*(2^11)=1024 */
ldexp
ldexp(计算2的次方值)
相关函数:frexp
表头文件:#include <math.h>
定义函数:double ldexp(double x, int exp);
函数说明:ldexp()用来将参数x乘上2的exp次方值,即x*2exp。
返回值:返回计算结果。
附加说明:使用GCC编译时请加入-lm。 范例: /* 计算3*(2^2)=12 / #include <math.h> main() { int exp; double x,answer; answer = ldexp(3,2); printf("32^(2) = %f\n",answer); }
执行: 3*2^(2) = 12.000000
log
log(计算以e为底的对数值)
相关函数:exp,log10,pow
表头文件:#include <math.h>
定义函数:double log(double x);
函数说明:log()用来计算以e为底的x对数值,然后将结果返回。
返回值:返回参数x的自然对数值。
错误代码:EDOM参数x为负数,ERANGE参数x为零值,零的对数值无定义。
附加说明:使用GCC编译时请加入-lm。
范例:
#include <math.h>
main()
{
double answer;
answer = log(100);
printf("log(100) = %f\n",answer);
}
执行: log(100) = 4.605170
log10
log10(计算以10为底的对数值)
相关函数:exp,log,pow
表头文件:#include <math.h>
定义函数:double log10(double x);
函数说明:log10()用来计算以10为底的x对数值,然后将结果返回。
返回值:返回参数x以10为底的对数值。
错误代码:EDOM参数x为负数。RANGE参数x为零值,零的对数值无定义。
附加说明:使用GCC编译时请加入-lm。
范例:
#include <math.h>
main()
{
double answer;
answer = log10(100);
printf("log10(100) = %f\n",answer);
}
执行: log10(100) = 2.000000
pow
pow(计算次方值)
相关函数:exp,log,log10
表头文件:#include <math.h>
定义函数:double pow(double x, double y);
函数说明:pow()用来计算以x为底的y次方值,即xy值,然后将结果返回。
返回值:返回x的y次方计算结果。
错误代码:EDOM参数x为负数且参数y不是整数。
附加说明:使用GCC编译时请加入-lm。
范例:
#include <math.h>
main()
{
double answer;
answer = pow(2,10);
printf("2^10 = %f\n", answer);
}
执行: 2^10 = 1024.000000
sin
sin(取正弦函数值)
相关函数:acos,asin,atan,atan2,cos,tan
表头文件:#include <math.h>
定义函数:double sin(double x);
函数说明:sin()用来计算参数x的正弦值,然后将结果返回。
返回值:返回-1至1之间的计算结果。
附加说明:使用GCC编译时请加入-lm。
范例:
#include <math.h>
main()
{
double answer = sin(0.5);
printf("sin(0.5) = %f\n",answer);
}
执行: sin(0.5) = 0.479426
sinh
sinh(取双曲线正弦函数值)
相关函数:cosh,tanh
表头文件:#include <math.h>
定义函数:double sinh(double x);
函数说明:sinh()用来计算参数x的双曲线正弦值,然后将结果返回。数学定义式为:(exp(x)-exp(-x))/2。
返回值:返回参数x的双曲线正弦值。
附加说明:使用GCC编译时请加入-lm。
范例:
#include <math.h>
main()
{
double answer = sinh(0.5);
printf("sinh(0.5) = %f\n",answer);
}
执行: sinh(0.5) = 0.521095
sqrt
sqrt(计算平方根值)
相关函数:hypotq
表头文件:#include <math.h>
定义函数:double sqrt(double x);
函数说明:sqrt()用来计算参数x的平方根,然后将结果返回。参数x必须为正数。
返回值:返回参数x的平方根值。
错误代码:EDOM参数x为负数。
附加说明:使用GCC编译时请加入-lm。
范例:
/* 计算200的平方根值 */
#include <math.h>
main()
{
double root;
root = sqrt(200);
printf("answer is %f\n",root);
}
执行: answer is 14.142136
tan
tan(取正切函数值)
相关函数:atan,atan2,cos,sin
表头文件:#include <math.h>
定义函数:double tan(double x);
函数说明:tan()用来计算参数x的正切值,然后将结果返回。
返回值:返回参数x的正切值。
附加说明:使用GCC编译时请加入-lm。
范例:
#include <math.h>
main()
{
double answer = tan(0.5);
printf("tan(0.5) = %f\n",answer);
}
执行: tan(0.5) = 0.546302
tanh
tanh(取双曲线正切函数值)
相关函数:cosh,sinh
表头文件:#include <math.h>
定义函数:double tanh(double x);
函数说明:tanh()用来计算参数x的双曲线正切值,然后将结果返回。数学定义式为:sinh(x)/cosh(x)。
返回值:返回参数x的双曲线正切值。
附加说明:使用GCC编译时请加入-lm。
范例:
#include <math.h>
main()
{
double answer = tanh(0.5);
printf("tanh(0.5) = %f\n",answer);
}
执行: tanh(0.5) = 0.462117
用户组篇 7
TODO
endgrent
endgrent(结束组用户数据存取)
相关函数:getgrent,setgrent
表头文件:#include <grp.h> #include <sys/types.h>
定义函数:void endgrent(void);
函数说明:endgrent()用于关闭由getgrent()所打开的密码文件。
返回值:
endpwent
endpwent(结束密码文件数据存取)
相关函数:getpwent,setpwent
表头文件:#include <pwd.h> #include <sys/types.h>
定义函数:void endpwent(void);
函数说明:endpwent()用于关闭由getpwent()所打开的密码文件。
返回值:
endutent
endutent(结束用户登录数据存取)
相关函数:getutent,setutent
表头文件:#include <utmp.h>
定义函数:void endutent(void);
函数说明:endutent()用于关闭由getutent()所打开的utmp文件。
返回值:
fgetgrent
fgetgrent(从指定的文件来读取组格式数据)
相关函数:getgrent,setgrent
表头文件:#include <grp.h> #include <sys/types.h>
定义函数:struct group *fgetgrent(FILE *stream);
函数说明:fgetgrent()会从参数stream所指定的文件中读取组格式数据。文件格式必须与组文件相同,每一次调用只读取一行,返回一个group结构。返回后,group结构指针指向已分配的内存空间,之后不要再使用fgetgrent()读取,不然内存空间会被覆盖。函数说明请参考getgrent()。
返回值:如果成功返回group结构指针,如果出错或文件已结束则返回NULL。
附加说明:参数stream所指定的文件必须有组数据文件格式。
范例:
/* 将/etc/group中的账号数据由标准输出设备打印出来 */
#include <grp.h>
#include <sys/types.h>
#include <stdio.h>
main()
{
struct group *group;
FILE *stream;
stream = fopen("/etc/group", "r");
while ((group = fgetgrent(stream)) != NULL) printf("name:%s,password:%s,gid:%d\n", group->gr_name, group->gr_passwd, group->gr_gid);
fclose(stream);
}
执行: name:root,password:x,
gid:0name:bin,password:x,
gid:1name:daemon,password:x,
gid:2name:sys,password:x,
gid:3name:adm,password:x,
gid:4name:tty,password:x,
gid:5name:disk,password:x,
gid:6name:lp,password:x,
gid:7name:mem,password:x,
gid:8name:kmem,password:x,
gid:9 …….
fgetpwent
fgetpwent(从指定的文件来读取密码格式数据)
相关函数:getpwent,setpwent
表头文件:#include <pwd.h> #include <sys/types.h>
定义函数:struct passwd *fgetpwent(FILE *stream);
函数说明:fgetpwent()会从参数stream所指定的文件中读取密码格式数据。文件格式必须与密码文件相同,每一次调用只读取一行,返回一个passwd结构。返回后,passwd结构指针指向已分配的内存空间,之后不要再使用fgetpwent()读取,不然内存空间会被覆盖。函数说明请参考getpwent()。
返回值:如果成功返回passwd结构指针,如果出错或文件已结束则返回NULL。
附加说明:参数stream所指定的文件必须有密码数据文件格式。
范例:
/* 将/etc/passwd中的账号数据由标准输出设备打印出来 */
#include <pwd.h>
#include <sys/types.h>
#include <stdio.h>
main()
{
struct passwd *user;
FILE *stream;
stream = fopen("/etc/passwd", "r");
while ((user = fgetpwent(stream)) != NULL) printf("name:%s,uid:%d,home:%s\n", user->pw_name, user->pw_uid, user->pw_dir);
fclose(stream);
}
执行: name:root,
uid:0,home:/rootname:bin,
uid:1,home:/binname:daemon,
uid:2,home:/sbinname:adm,
uid:3,home:/var/admname:lp,
uid:4,home:/var/spool/lpdname:sync,
uid:5,home:/sbinname:shutdown,
uid:6,home:/sbinname:halt,
uid:7,home:/sbin …….
getegid
getegid(取得有效的组识别码)
相关函数:getgid,setgid,setregid
表头文件:#include <unistd.h> #include <sys/types.h>
定义函数:uid_t getegid(void);
函数说明:getegid()用来取得执行目前进程的有效组识别码。有效的组识别码用来决定进程执行的权限范围。如果进程调用setegid(),有效的组识别码可能会与实际的组识别码不同。
返回值:返回有效的组识别码。
范例:
/* 显示进程的实际和有效的组识别码 */
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
main()
{
printf("egid is %d\n", getegid());
}
执行: egid is 0
geteuid
geteuid(取得有效的用户识别码)
相关函数:getuid,setreuid,seteuid
表头文件:#include <unistd.h> #include <sys/types.h>
定义函数:uid_t geteuid(void);
函数说明:geteuid()用来取得执行目前进程的有效用户识别码。有效的用户识别码用来决定进程执行的权限范围。如果进程调用seteuid(),有效的用户识别码可能会与实际的用户识别码不同。
返回值:返回有效的用户识别码。
范例:
/* 显示进程的实际和有效的用户识别码 */
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
main()
{
printf("euid is %d\n", geteuid());
}
执行: euid is 0
getgid
getgid(取得组识别码)
相关函数:getegid,setgid,setregid
表头文件:#include <unistd.h> #include <sys/types.h>
定义函数:gid_t getgid(void);
函数说明:getgid()用来取得执行目前进程的组识别码。
返回值:返回组识别码。
范例:
/* 显示进程的组识别码 */
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
main()
{
printf("gid is %d\n", getgid());
}
执行: gid is 0
getgrent
getgrent(取得组数据文件内容)
相关函数:fgetgrent,setgrent,endgrent
表头文件:#include <grp.h> #include <sys/types.h>
定义函数:struct group *getgrent(void);
函数说明:getgrent()用来从组文件(/etc/group)中读取组数据,每一次调用只读取一行数据。第一次调用时,会打开组文件并返回第一个组数据;之后每调用一次就会返回下一组数据,直到文件末尾或发生错误。getgrent()会返回一个group结构指针。返回后,group结构指针指向已分配的内存空间,之后不要再使用getgrent()读取,不然内存空间会被覆盖。
返回值:如果成功返回group结构指针,如果出错或文件已结束则返回NULL。
附加说明:组文件格式请参考/etc/group。 struct group { char gr_name; / 组名称 */ char gr_passwd; / 组密码 / gid_t gr_gid; / 组识别码 */ char *gr_mem; / 组账号 */ };
范例:
/* 将/etc/group中的账号数据由标准输出设备打印出来 */
#include <grp.h>
#include <sys/types.h>
#include <stdio.h>
main()
{
struct group *group;
while ((group = getgrent()) != NULL) printf("name:%s,password:%s,gid:%d\n", group->gr_name, group->gr_passwd, group->gr_gid);
endgrent();
}
执行: name:root,password:x,
gid:0name:bin,password:x,
gid:1name:daemon,password:x,
gid:2name:sys,password:x,
gid:3name:adm,password:x,
gid:4name:tty,password:x,
gid:5name:disk,password:x,
gid:6name:lp,password:x,
gid:7name:mem,password:x,
gid:8name:kmem,password:x,
gid:9 …….
getgrgid
getgrgid(从组识别码取得组数据)
相关函数:getgrnam,getgrent
表头文件:#include <grp.h> #include <sys/types.h>
定义函数:struct group *getgrgid(gid_t gid);
函数说明:getgrgid()用来根据参数gid指定的组识别码来查找组数据,返回一个group结构指针。返回后,group结构指针指向已分配的内存空间,之后不要再使用getgrgid()读取,不然内存空间会被覆盖。
返回值:如果成功返回group结构指针,如果出错或文件已结束则返回NULL。
范例:
/* 利用组识别码取得组数据 */
#include <grp.h>
#include <sys/types.h>
#include <stdio.h>
main()
{
struct group *group;
group = getgrgid(0);
if (group != NULL)
printf("name:%s,password:%s,gid:%d\n", group->gr_name, group->gr_passwd, group->gr_gid);
}
执行: name:root,password:x,
gid:0
getgrnam
getgrnam(从组名称取得组数据)
相关函数:getgrgid,getgrent
表头文件:#include <grp.h> #include <sys/types.h>
定义函数:struct group *getgrnam(const char *name);
函数说明:getgrnam()用来根据参数name指定的组名称来查找组数据,返回一个group结构指针。返回后,group结构指针指向已分配的内存空间,之后不要再使用getgrnam()读取,不然内存空间会被覆盖。
返回值:如果成功返回group结构指针,如果出错或文件已结束则返回NULL。
范例:
/* 利用组名称取得组数据 */
#include <grp.h>
#include <sys/types.h>
#include <stdio.h>
main()
{
struct group *group;
group = getgrnam("root");
if (group != NULL)
printf("name:%s,password:%s,gid:%d\n", group->gr_name, group->gr_passwd, group->gr_gid);
}
执行: name:root,password:x,
gid:0
getgroups
getgroups(取得一组组识别码)
相关函数:initgroups,setgroups,getgid
表头文件:#include <unistd.h> #include <sys/types.h>
定义函数:int getgroups(int size, gid_t list[]);
函数说明:getgroups()用来将目前进程所属用户的组识别码列表放到参数list所指向的内存空间中。参数size代表list数组的最大容量。如果size为0,则getgroups()仅返回用户所属的组识别码总数。
返回值:如果成功则返回组识别码总数,如果出错则返回-1。
错误代码:EFAULT:参数list的地址无效。
范例:
/* 显示进程所属用户的组识别码 */
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
main()
{
gid_t list[100];
int i;
int num = getgroups(100, list);
for (i = 0; i < num; i++) printf("%d\n", list[i]);
}
执行: 0 1 2 3 4 5 6 7 8 9 …….
tgetpw
tgetpw(从用户识别码取得用户数据)
相关函数:getpwnam,getpwuid
表头文件:#include <pwd.h> #include <sys/types.h>
定义函数:int getpw(uid_t uid, char *buf);
函数说明:getpw()用来根据参数uid指定的用户识别码来查找用户数据,将结果存放到参数buf所指向的内存空间中。buf的大小至少要有256个字节。由于getpw()所使用的算法老旧、容易发生错误,建议不要使用,改用getpwuid()。
返回值:如果成功返回0,如果出错则返回-1。
范例:
#include <pwd.h>
#include <sys/types.h>
#include <stdio.h>
main()
{
char buf[256];
getpw(0, buf);
printf("%s\n", buf);
}
执行: root:?:
0:0:root:/root:/bin/bash
getpwent
getpwent(取得密码文件数据内容)
相关函数:getpw,fgetpwent,setpwent,endpwent
表头文件:#include <pwd.h> #include <sys/types.h>
定义函数:struct passwd *getpwent(void);
函数说明:getpwent()用来从密码文件(/etc/passwd)中读取用户数据,每一次调用只读取一行数据。第一次调用时,会打开密码文件并返回第一个用户数据;之后每调用一次就会返回下一用户数据,直到文件末尾或发生错误。getpwent()会返回一个passwd结构指针。返回后,passwd结构指针指向已分配的内存空间,之后不要再使用getpwent()读取,不然内存空间会被覆盖。
返回值:如果成功返回passwd结构指针,如果出错或文件已结束则返回NULL。
附加说明:密码文件格式请参考/etc/passwd。 struct passwd { char pw_name; / 用户名称 */ char pw_passwd; / 用户密码 / uid_t pw_uid; / 用户识别码 / gid_t pw_gid; / 组识别码 */ char pw_gecos; / 用户全名 */ char pw_dir; / 主目录 */ char pw_shell; / 使用的shell */ };
范例:
/* 将/etc/passwd中的账号数据由标准输出设备打印出来 */
#include <pwd.h>
#include <sys/types.h>
#include <stdio.h>
main()
{
struct passwd *user;
while ((user = getpwent()) != NULL) printf("name:%s,uid:%d,home:%s\n", user->pw_name, user->pw_uid, user->pw_dir);
endpwent();
}
执行: name:root,
uid:0,home:/rootname:bin,
uid:1,home:/binname:daemon,
uid:2,home:/sbinname:adm,
uid:3,home:/var/admname:lp,
uid:4,home:/var/spool/lpdname:sync,
uid:5,home:/sbinname:shutdown,
uid:6,home:/sbinname:halt,
uid:7,home:/sbin …….
getpwnam
getpwnam(从用户名称取得用户数据)
相关函数:getpwuid,getpwent
表头文件:#include <pwd.h> #include <sys/types.h>
定义函数:struct passwd *getpwnam(const char *name);
函数说明:getpwnam()用来根据参数name指定的用户名称来查找用户数据,返回一个passwd结构指针。返回后,passwd结构指针指向已分配的内存空间,之后不要再使用getpwnam()读取,不然内存空间会被覆盖。
返回值:如果成功返回passwd结构指针,如果出错或文件已结束则返回NULL。
范例:
/* 利用用户名称取得用户数据 */
#include <pwd.h>
#include <sys/types.h>
#include <stdio.h>
main()
{
struct passwd *user;
user = getpwnam("root");
if (user != NULL)
printf("name:%s,uid:%d,home:%s\n", user->pw_name, user->pw_uid, user->pw_dir);
}
执行: name:root,
uid:0,home:/root
getpwuid
getpwuid(从用户识别码取得用户数据)
相关函数:getpwnam,getpwent
表头文件:#include <pwd.h> #include <sys/types.h>
定义函数:struct passwd *getpwuid(uid_t uid);
函数说明:getpwuid()用来根据参数uid指定的用户识别码来查找用户数据,返回一个passwd结构指针。返回后,passwd结构指针指向已分配的内存空间,之后不要再使用getpwuid()读取,不然内存空间会被覆盖。
返回值:如果成功返回passwd结构指针,如果出错或文件已结束则返回NULL。
范例:
/* 利用用户识别码取得用户数据 */
#include <pwd.h>
#include <sys/types.h>
#include <stdio.h>
main()
{
struct passwd *user;
user = getpwuid(0);
if (user != NULL)
printf("name:%s,uid:%d,home:%s\n", user->pw_name, user->pw_uid, user->pw_dir);
}
执行: name:root,
uid:0,home:/root
getuid
getuid(取得用户识别码)
相关函数:geteuid,setreuid,seteuid
表头文件:#include <unistd.h> #include <sys/types.h>
定义函数:uid_t getuid(void);
函数说明:getuid()用来取得执行目前进程的用户识别码。
返回值:返回用户识别码。
范例:
/* 显示进程的用户识别码 */
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
main()
{
printf("uid is %d\n", getuid());
}
执行: uid is 0
getutent
getutent(从utmp文件中取得账号登录数据)
相关函数:getutid,getutline,setutent,endutent,pututline,utmpname
表头文件:#include <utmp.h>
定义函数:struct utmp *getutent(void);
函数说明:getutent()用来从utmp文件(/var/run/utmp)中读取用户登录数据,每一次调用只读取一行数据。第一次调用时,会打开utmp文件并返回第一个用户数据;之后每调用一次就会返回下一用户数据,直到文件末尾或发生错误。getutent()会返回一个utmp结构指针。返回后,utmp结构指针指向已分配的内存空间,之后不要再使用getutent()读取,不然内存空间会被覆盖。
返回值:如果成功返回utmp结构指针,如果出错或文件已结束则返回NULL。 struct utmp { short int ut_type; /* 登录类型 / pid_t ut_pid; / 登录进程的pid / char ut_line[UT_LINESIZE]; / 设备名 / char ut_id[4]; / 登录记录id / char ut_user[UT_NAMESIZE]; / 用户名 / char ut_host[UT_HOSTSIZE]; / 远程主机名 / struct exit_status ut_exit; / 进程退出状态 / long int ut_session; / 会话id / struct timeval ut_tv; / 登录时间 / int32_t ut_addr_v6[4]; / 远程主机IP地址 / char __unused[20]; / 保留 */ };
范例:
#include <utmp.h>
#include <stdio.h>
main()
{
struct utmp *ut;
while ((ut = getutent()) != NULL) printf("%s %s %s\n", ut->ut_user, ut->ut_line, ut->ut_host);
endutent();
}
执行: reboot ~
root tty1
dmtsai tty2
dmtsai pts/0
getutid
getutid(从utmp文件中查找特定记录)
相关函数:getutent,getutline,setutent,endutent,pututline,utmpname
表头文件:#include <utmp.h>
定义函数:struct utmp *getutid(const struct utmp *ut);
函数说明:getutid()用来从utmp文件中查找参数ut所指定的记录。ut结构中有ut_type和ut_id两个字段。如果ut_type为RUN_LVL、BOOT_TIME、OLD_TIME、NEW_TIME之一,则查找ut_type相符的记录;否则查找ut_id相符的记录。找到则返回utmp结构指针,以后续调用可返回下一个匹配的记录。
返回值:如果成功返回utmp结构指针,如果出错或文件已结束则返回NULL。
范例:
#include <utmp.h>
#include <stdio.h>
main()
{
struct utmp ut, *u;
ut.ut_type = BOOT_TIME;
u = getutid(&ut);
if (u != NULL)
printf("Boot time %s\n", ctime(&(u->ut_tv.tv_sec)));
endutent();
}
执行: Boot time Mon Jan 20 10:59:27 2003
getutline
getutline(从utmp文件中查找特定设备记录)
相关函数:getutent,getutid,setutent,endutent,pututline,utmpname
表头文件:#include <utmp.h>
定义函数:struct utmp *getutline(const struct utmp *ut);
函数说明:getutline()用来从utmp文件中查找参数ut所指定的ut_line设备记录,找到则返回utmp结构指针。
返回值:如果成功返回utmp结构指针,如果出错或文件已结束则返回NULL。
范例:
#include <utmp.h>
#include <stdio.h>
main()
{
struct utmp ut, *u;
strcpy(ut.ut_line, "tty1");
u = getutline(&ut);
if (u != NULL)
printf("%s %s %s\n", u->ut_user, u->ut_line, u->ut_host);
endutent();
}
执行: root tty1
initgroups
initgroups(初始化组列表)
相关函数:setgroups,getgroups,getgid
表头文件:#include <grp.h> #include <sys/types.h>
定义函数:int initgroups(const char *user, gid_t group);
函数说明:initgroups()用来从组文件(/etc/group)中读取参数user所属组的组识别码,然后调用setgroups()将组识别码添加到进程的组列表中。参数group为附加的组识别码。
返回值:如果成功返回0,如果出错则返回-1。
pututline
pututline(将utmp记录写入文件)
相关函数:getutent,getutid,getutline,setutent,endutent,utmpname
表头文件:#include <utmp.h>
定义函数:void pututline(const struct utmp *ut);
函数说明:pututline()用来将参数ut所指向的utmp结构写入utmp文件。
返回值:
seteuid
seteuid(设置有效的用户识别码)
相关函数:setuid,setreuid,geteuid
表头文件:#include <unistd.h> #include <sys/types.h>
定义函数:int seteuid(uid_t euid);
函数说明:seteuid()用来设置当前进程的有效用户识别码。参数euid为新的有效用户识别码。如果进程有root权限,则可以将有效用户识别码设置为任意值;否则只能设置为实际用户识别码或保存的设置用户识别码。
返回值:如果成功返回0,如果出错则返回-1。
错误代码:EPERM:进程权限不足。
范例:
#include <unistd.h>
#include <sys/types.h>
main()
{
seteuid(500);
}
setfsgid
setfsgid(设置文件系统组识别码)
相关函数:setfsuid,setgid
表头文件:#include <unistd.h> #include <sys/types.h>
定义函数:int setfsgid(uid_t fsgid);
函数说明:setfsgid()用来设置当前进程的文件系统组识别码。一般情况下文件系统组识别码与有效组识别码相同。参数fsgid为新的文件系统组识别码。如果进程有root权限,则可以将文件系统组识别码设置为任意值;否则只能设置为实际组识别码或有效组识别码。
返回值:如果成功返回原来的文件系统组识别码,如果出错则返回-1。
setfsuid
setfsuid(设置文件系统用户识别码)
相关函数:setfsgid,setuid
表头文件:#include <unistd.h> #include <sys/types.h>
定义函数:int setfsuid(uid_t fsuid);
函数说明:setfsuid()用来设置当前进程的文件系统用户识别码。一般情况下文件系统用户识别码与有效用户识别码相同。参数fsuid为新的文件系统用户识别码。如果进程有root权限,则可以将文件系统用户识别码设置为任意值;否则只能设置为实际用户识别码或有效用户识别码。
返回值:如果成功返回原来的文件系统用户识别码,如果出错则返回-1。
setgid
setgid(设置组识别码)
相关函数:getgid,setregid,getegid
表头文件:#include <unistd.h> #include <sys/types.h>
定义函数:int setgid(gid_t gid);
函数说明:setgid()用来设置当前进程的组识别码。如果进程有root权限,则可以将组识别码设置为任意值;否则只能设置为实际组识别码或有效组识别码。设置后实际组识别码和有效组识别码都会改变。
返回值:如果成功返回0,如果出错则返回-1。
错误代码:EPERM:进程权限不足。
范例:
#include <unistd.h>
#include <sys/types.h>
main()
{
setgid(500);
}
setgrent
setgrent(从头读取组数据文件)
相关函数:getgrent,endgrent
表头文件:#include <grp.h> #include <sys/types.h>
定义函数:void setgrent(void);
函数说明:setgrent()用来将getgrent()的读取位置移动到组数据文件的开头,以便重新读取组数据。
返回值:
setgroups
setgroups(设置组识别码列表)
相关函数:initgroups,getgroups,getgid
表头文件:#include <grp.h> #include <sys/types.h>
定义函数:int setgroups(size_t size, const gid_t *list);
函数说明:setgroups()用来将参数list所指的组识别码列表设置为当前进程的组识别码。参数size为list数组的大小。此函数需要root权限才能执行。
返回值:如果成功返回0,如果出错则返回-1。
错误代码:EPERM:进程权限不足。 EFAULT:参数list的地址无效。
setpwent
setpwent(从头读取密码数据文件)
相关函数:getpwent,endpwent
表头文件:#include <pwd.h> #include <sys/types.h>
定义函数:void setpwent(void);
函数说明:setpwent()用来将getpwent()的读取位置移动到密码数据文件的开头,以便重新读取密码数据。
返回值:
setregid
setregid(设置实际及有效的组识别码)
相关函数:setgid,setegid
表头文件:#include <unistd.h> #include <sys/types.h>
定义函数:int setregid(gid_t rgid, gid_t egid);
函数说明:setregid()用来将当前进程的实际组识别码和有效组识别码分别设置为参数rgid和egid的值。如果rgid为-1,则不改变实际组识别码;如果egid为-1,则不改变有效组识别码。如果进程有root权限,则可以将组识别码设置为任意值。
返回值:如果成功返回0,如果出错则返回-1。
错误代码:EPERM:进程权限不足。
范例:
#include <unistd.h>
#include <sys/types.h>
main()
{
setregid(500, 500);
}
setreuid
setreuid(设置实际及有效的用户识别码)
相关函数:setuid,seteuid
表头文件:#include <unistd.h> #include <sys/types.h>
定义函数:int setreuid(uid_t ruid, uid_t euid);
函数说明:setreuid()用来将当前进程的实际用户识别码和有效用户识别码分别设置为参数ruid和euid的值。如果ruid为-1,则不改变实际用户识别码;如果euid为-1,则不改变有效用户识别码。如果进程有root权限,则可以将用户识别码设置为任意值。
返回值:如果成功返回0,如果出错则返回-1。
错误代码:EPERM:进程权限不足。
范例:
#include <unistd.h>
#include <sys/types.h>
main()
{
setreuid(500, 500);
}
setuid
setuid(设置用户识别码)
相关函数:getuid,setreuid,seteuid
表头文件:#include <unistd.h> #include <sys/types.h>
定义函数:int setuid(uid_t uid);
函数说明:setuid()用来设置当前进程的用户识别码。如果进程有root权限,则可以将用户识别码设置为任意值;否则只能设置为实际用户识别码或有效用户识别码。设置后实际用户识别码和有效用户识别码都会改变。
返回值:如果成功返回0,如果出错则返回-1。
错误代码:EPERM:进程权限不足。
范例:
#include <unistd.h>
#include <sys/types.h>
main()
{
setuid(500);
}
setutent
setutent(从头读取utmp文件)
相关函数:getutent,endutent
表头文件:#include <utmp.h>
定义函数:void setutent(void);
函数说明:setutent()用来将getutent()的读取位置移动到utmp文件的开头,以便重新读取utmp数据。
返回值:
utmpname
utmpname(指定utmp文件名)
相关函数:getutent,getutid,getutline,setutent,endutent,pututline
表头文件:#include <utmp.h>
定义函数:void utmpname(const char *file);
函数说明:utmpname()用来指定utmp文件名称,供后续的getutent()、getutid()、getutline()及pututline()使用。如果不调用utmpname(),默认使用/var/run/utmp文件。
返回值:
数据结构及算法篇 8
TODO
crypt
crypt(密码加密函数)
相关函数:getpass
表头文件:#define _XOPEN_SOURCE #include <unistd.h>
定义函数:char *crypt(const char *key, const char *salt);
函数说明:crypt()将参数key所指的字符串(通常是用户输入的密码)使用DES加密算法结合参数salt(两个字符的字符串)进行加密,返回加密后的字符串。如果salt为"$1$..."形式,则使用MD5加密算法。返回的字符串为已分配的内存空间。
返回值:返回加密后的字符串指针。
范例:
#include <stdio.h>
#define _XOPEN_SOURCE #include <unistd.h>
main()
{
char passwd[20];
printf("输入密码:");
gets(passwd);
printf("加密后的密码:%s\n", crypt(passwd, "ab"));
}
执行: 输入密码:test 加密后的密码:abOmyg3L/bjsE
bsearch
bsearch(二分查找数据)
相关函数:qsort,lfind,lsearch
表头文件:#include <stdlib.h>
定义函数:void *bsearch(const void *key, const void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
函数说明:bsearch()使用二分查找算法在参数base所指向的数组中查找与参数key所指向的数据匹配的数据元素。参数nmemb为数组中的元素个数,参数size为每个元素的大小。参数compar是一个比较函数指针,用来判断两个元素的大小关系。如果比较函数返回0,则表示找到匹配的数据。数组中的元素必须按升序排列。
返回值:如果找到匹配的数据则返回该数据的地址,否则返回NULL。
范例:
/* 二分查找 */
#include <stdio.h>
#include <stdlib.h>
#define NELEMS(arr) (sizeof(arr) / sizeof(arr[0])) int numarray[] =
{
123, 145, 512, 627, 800, 933
} ; int numeric(const int *a, const int *b)
{
return *a - *b;
}
main()
{
int key = 512;
int *element = bsearch(&key, numarray, NELEMS(numarray), sizeof(numarray[0]), (int (*)(const void *, const void *))numeric);
if (element != NULL)
printf("found number %d\n", *element);
else printf("number not found\n");
}
执行: found number 512
lfind
lfind(线性查找数据)
相关函数:lsearch,bsearch
表头文件:#include <stdlib.h>
定义函数:void *lfind(const void *key, const void *base, size_t *nmemb, size_t size, int (*compar)(const void *, const void *));
函数说明:lfind()使用线性查找算法在参数base所指向的数组中查找与参数key所指向的数据匹配的数据元素。参数nmemb为数组中的元素个数的指针,参数size为每个元素的大小。参数compar是一个比较函数指针。与lsearch()不同的是,如果找不到匹配的数据,lfind()不会将数据添加到数组末尾。
返回值:如果找到匹配的数据则返回该数据的地址,否则返回NULL。
范例:
#include <stdio.h>
#include <stdlib.h>
#define NELEMS(arr) (sizeof(arr) / sizeof(arr[0])) int numarray[] =
{
123, 145, 512, 627, 800, 933
} ; int numeric(const int *a, const int *b)
{
return *a - *b;
}
main()
{
int key = 512;
size_t nmemb = NELEMS(numarray);
int *element = lfind(&key, numarray, &nmemb, sizeof(numarray[0]), (int (*)(const void *, const void *))numeric);
if (element != NULL)
printf("found number %d\n", *element);
else printf("number not found\n");
}
执行: found number 512
lsearch
lsearch(线性查找数据,找不到则添加)
相关函数:lfind,bsearch
表头文件:#include <stdlib.h>
定义函数:void *lsearch(const void *key, void *base, size_t *nmemb, size_t size, int (*compar)(const void *, const void *));
函数说明:lsearch()使用线性查找算法在参数base所指向的数组中查找与参数key所指向的数据匹配的数据元素。如果找不到,则将key所指向的数据添加到数组末尾,并将*nmemb加1。
返回值:如果找到或添加成功则返回数据元素的地址。
范例:
#include <stdio.h>
#include <stdlib.h>
#define NELEMS(arr) (sizeof(arr) / sizeof(arr[0])) int numarray[] =
{
123, 145, 512, 627, 800, 933
} ; int numeric(const int *a, const int *b)
{
return *a - *b;
}
main()
{
int key = 511;
size_t nmemb = NELEMS(numarray);
int *element = lsearch(&key, numarray, &nmemb, sizeof(numarray[0]), (int (*)(const void *, const void *))numeric);
if (element != NULL)
printf("element %d %d\n", *element, (int)nmemb);
}
执行: element 511 7
qsort
qsort(快速排序)
相关函数:bsearch,lsearch
表头文件:#include <stdlib.h>
定义函数:void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
函数说明:qsort()使用快速排序算法对参数base所指向的数组进行排序。参数nmemb为数组中的元素个数,参数size为每个元素的大小。参数compar是一个比较函数指针。排序完成后数组中的元素会按升序排列。
返回值:
范例:
/* 排序一组整数 */
#include <stdio.h>
#include <stdlib.h>
#define NELEMS(arr) (sizeof(arr) / sizeof(arr[0])) int numarray[] =
{
123, 145, 512, 627, 800, 933, 1, 45, 299
} ; int numeric(const int *a, const int *b)
{
return *a - *b;
}
main()
{
int i;
qsort(numarray, NELEMS(numarray), sizeof(numarray[0]), (int (*)(const void *, const void *))numeric);
for (i = 0; i < NELEMS(numarray); i++) printf("%d ", numarray[i]);
printf("\n");
}
执行: 1 45 123 145 299 512 627 800 933
rand
rand(产生随机数)
相关函数:srand,random
表头文件:#include <stdlib.h>
定义函数:int rand(void);
函数说明:rand()用来产生随机数。如果不先调用srand()设置随机数种子,则每次产生的随机数序列会相同。rand()返回0到RAND_MAX之间的整数。
返回值:返回0到RAND_MAX之间的整数。
范例:
/* 产生1到10之间的随机数 */
#include <stdlib.h>
#include <stdio.h>
main()
{
int i, j;
for (i = 0; i < 10; i++)
{
j = 1 + (int)(10.0 * (rand() / (RAND_MAX + 1.0)));
printf("%d ", j);
}
printf("\n");
}
执行: 9 4 8 8 10 2 4 8 3 6
srand
srand(设置随机数种子)
相关函数:rand,random
表头文件:#include <stdlib.h>
定义函数:void srand(unsigned int seed);
函数说明:srand()用来设置rand()产生随机数时的随机数种子。参数seed为整数,通常可以使用time(NULL)返回的值作为seed。每次设置不同的seed,rand()会产生不同的随机数序列。
返回值:
范例:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
main()
{
int i, j;
srand((unsigned int)time(NULL));
for (i = 0; i < 10; i++)
{
j = 1 + (int)(10.0 * (rand() / (RAND_MAX + 1.0)));
printf("%d ", j);
}
printf("\n");
}
执行: 9 4 8 8 10 2 4 8 3 6
文件操作篇 9
TODO
close
close(关闭文件)
相关函数:open,fcntl,shutdown,unlink,fclose
表头文件:#include <unistd.h>
定义函数:int close(int fd);
函数说明:close()用来关闭参数fd所指向的文件。当文件关闭后,该文件描述符可以被重新使用。所有与文件相关的记录锁也会被移除。
返回值:如果成功返回0,如果出错则返回-1。
错误代码:EBADF:参数fd无效的文件描述符。
范例:
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
main()
{
int fd;
fd = open("/tmp/test.txt", O_CREAT | O_RDWR, 0777);
if (fd != -1)
{
printf("打开文件成功\n");
close(fd);
}
else printf("打开文件失败\n");
}
creat
creat(创建文件)
相关函数:open,close
表头文件:#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
定义函数:int creat(const char *pathname, mode_t mode);
函数说明:creat()用来创建一个新文件。参数pathname为要创建的文件路径,参数mode为文件的权限。creat()等价于open(pathname, O_CREAT | O_TRUNC | O_WRONLY, mode)。如果文件已存在,则会清空文件内容。
返回值:如果成功返回文件描述符,如果出错则返回-1。
错误代码:EACCES:权限不足。 EEXIST:文件已存在且设置了O_EXCL。
范例:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
main()
{
int fd;
fd = creat("/tmp/test.txt", 0755);
if (fd != -1)
{
printf("创建文件成功\n");
close(fd);
}
else printf("创建文件失败\n");
}
dup
dup(复制文件描述符)
相关函数:open,close,fcntl,dup2
表头文件:#include <unistd.h>
定义函数:int dup(int oldfd);
函数说明:dup()用来复制参数oldfd所指向的文件描述符。复制成功后,新的文件描述符和原来的文件描述符共享同一个文件指针。dup()会使用当前最小的未使用文件描述符作为新的文件描述符。
返回值:如果成功返回新的文件描述符,如果出错则返回-1。
错误代码:EBADF:参数oldfd无效的文件描述符。 EMFILE:进程已打开的文件描述符数量已达上限。
范例:
#include <unistd.h>
#include <stdio.h>
main()
{
int newfd;
newfd = dup(1);
/* 复制标准输出 */
if (newfd != -1)
printf("复制成功,新文件描述符为%d\n", newfd);
}
dup2
dup2(复制文件描述符)
相关函数:open,close,fcntl,dup
表头文件:#include <unistd.h>
定义函数:int dup2(int oldfd, int newfd);
函数说明:dup2()用来复制参数oldfd所指向的文件描述符,并将它复制到参数newfd所指定的文件描述符。如果newfd已经打开,则先将其关闭。成功复制后,两个文件描述符共享同一个文件指针。
返回值:如果成功返回新的文件描述符,如果出错则返回-1。
错误代码:EBADF:参数oldfd无效的文件描述符。 EMFILE:进程已打开的文件描述符数量已达上限。
范例:
#include <unistd.h>
#include <stdio.h>
main()
{
dup2(1, 3);
/* 复制标准输出到文件描述符3 */
printf("复制成功\n");
}
fcntl
fcntl(文件描述符控制)
相关函数:open,flock,lockf
表头文件:#include <unistd.h> #include <sys/types.h> #include <fcntl.h>
定义函数:int fcntl(int fd, int cmd, ... /* arg */);
函数说明:fcntl()用来操作文件描述符的一些属性。参数fd为文件描述符,参数cmd为操作命令。 支持的cmd命令: F_DUPFD:复制文件描述符 F_GETFD:获取文件描述符标志 F_SETFD:设置文件描述符标志 F_GETFL:获取文件状态标志 F_SETFL:设置文件状态标志 F_GETLK:获取文件锁信息 F_SETLK:设置文件锁 F_SETLKW:设置文件锁(阻塞) F_GETOWN:获取当前接收SIGIO信号的进程ID F_SETOWN:设置当前接收SIGIO信号的进程ID
返回值:如果成功则返回值取决于cmd命令,如果出错则返回-1。
错误代码:EBADF:参数fd无效的文件描述符。 EINVAL:参数cmd无效。
范例:
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
main()
{
int fd, flags;
fd = open("/tmp/test.txt", O_RDONLY);
if (fd != -1)
{
flags = fcntl(fd, F_GETFL);
/* 获取文件状态标志 */
if (flags & O_RDONLY)
printf("只读模式\n");
close(fd);
}
}
flock
flock(文件加锁/解锁)
相关函数:fcntl,lockf
表头文件:#include <sys/file.h>
定义函数:int flock(int fd, int operation);
函数说明:flock()用来对参数fd所指向的文件进行加锁或解锁操作。参数operation为操作类型。 operation取值: LOCK_SH:共享锁(多个进程可同时持有) LOCK_EX:排他锁(只有一个进程可持有) LOCK_UN:解锁 LOCK_NB:非阻塞模式(与LOCK_SH或LOCK_EX组合使用)
返回值:如果成功返回0,如果出错则返回-1。
错误代码:EBADF:参数fd无效的文件描述符。 EWOULDBLOCK:文件已被锁定(在非阻塞模式下)。
范例:
#include <sys/file.h>
#include <unistd.h>
#include <stdio.h>
main()
{
int fd;
fd = open("/tmp/test.txt", O_RDWR);
if (fd != -1)
{
if (flock(fd, LOCK_EX) == 0) /* 加排他锁 */
{
printf("加锁成功\n");
/* 对文件进行操作 */
flock(fd, LOCK_UN);
/* 解锁 */
}
close(fd);
}
}
fsync
fsync(将缓冲区数据写入磁盘)
相关函数:sync,write
表头文件:#include <unistd.h>
定义函数:int fsync(int fd);
函数说明:fsync()用来将参数fd所指向的文件的所有缓冲区数据写入磁盘。该函数会等待数据写入完成才返回。
返回值:如果成功返回0,如果出错则返回-1。
错误代码:EBADF:参数fd无效的文件描述符。 EIO:发生I/O错误。
范例:
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
main()
{
int fd;
fd = open("/tmp/test.txt", O_CREAT | O_RDWR, 0777);
if (fd != -1)
{
write(fd, "test", 4);
fsync(fd);
/* 将数据写入磁盘 */
close(fd);
}
}
lseek
lseek(移动文件的读写指针)
相关函数:fseek,ftell
表头文件:#include <sys/types.h> #include <unistd.h>
定义函数:off_t lseek(int fd, off_t offset, int whence);
函数说明:lseek()用来移动参数fd所指向的文件的读写指针位置。参数offset为偏移量,参数whence为基准位置。 whence取值: SEEK_SET:从文件开头计算 SEEK_CUR:从当前位置计算 SEEK_END:从文件末尾计算
返回值:如果成功返回指针移动后的文件位置(相对于文件开头的字节数),如果出错则返回-1。
错误代码:EBADF:参数fd无效的文件描述符。 ESPIPE:参数fd指向管道或FIFO。
范例:
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
main()
{
int fd;
off_t size;
fd = open("/tmp/test.txt", O_RDONLY);
if (fd != -1)
{
size = lseek(fd, 0, SEEK_END);
/* 移到文件末尾 */
printf("文件大小为%d字节\n", (int)size);
close(fd);
}
}
mkstemp
mkstemp(创建临时文件)
相关函数:tmpfile,tmpnam,mktemp
表头文件:#include <stdlib.h>
定义函数:int mkstemp(char *template);
函数说明:mkstemp()用来创建临时文件。参数template为文件名模板,最后六个字符必须是"XXXXXX",这些字符会被替换为随机字符,生成唯一的文件名。创建的文件权限为0600。
返回值:如果成功返回文件描述符,如果出错则返回-1。
范例:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
main()
{
char template[] = "/tmp/tempXXXXXX";
int fd;
fd = mkstemp(template);
if (fd != -1)
{
printf("临时文件%s创建成功\n", template);
close(fd);
}
}
执行: 临时文件/tmp/tempGxHsZI创建成功
open
open(打开文件)
相关函数:creat,close,read,write,fcntl,lseek
表头文件:#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>
定义函数:int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);
函数说明:open()用来打开或创建文件。参数pathname为文件路径,参数flags为打开方式。 flags取值: O_RDONLY:只读模式 O_WRONLY:只写模式 O_RDWR:读写模式 O_CREAT:如果文件不存在则创建 O_EXCL:与O_CREAT一起使用时,如果文件已存在则返回错误 O_TRUNC:如果文件存在则将文件长度截断为0 O_APPEND:追加模式 参数mode为创建文件时的权限。open()返回最小的未用文件描述符。
返回值:如果成功返回文件描述符,如果出错则返回-1。
错误代码:EACCES:权限不足。 EEXIST:文件已存在且设置了O_CREAT和O_EXCL。 EINTR:调用被信号中断。 EISDIR:pathname指向目录。 EMFILE:进程已打开的文件描述符数量已达上限。 ENOENT:文件或目录不存在。
范例:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
main()
{
int fd;
fd = open("/tmp/test.txt", O_CREAT | O_RDWR, 0777);
if (fd != -1)
{
printf("打开文件成功,文件描述符=%d\n", fd);
close(fd);
}
else printf("打开文件失败\n");
}
read
read(从文件读取数据)
相关函数:write,open,close,lseek,fcntl
表头文件:#include <unistd.h>
定义函数:ssize_t read(int fd, void *buf, size_t count);
函数说明:read()用来从参数fd所指向的文件中读取数据,读取的数据存放到参数buf所指向的内存中。参数count为要读取的字节数。实际读取的字节数可能会小于count,例如在读取到文件末尾时。
返回值:如果成功返回实际读取的字节数,如果返回0表示已到达文件末尾,如果出错则返回-1。
错误代码:EBADF:参数fd无效的文件描述符或不可读。 EFAULT:参数buf指向的内存空间不可访问。 EINTR:调用被信号中断。 EIO:发生I/O错误。
范例:
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
main()
{
int fd;
char buf[100];
fd = open("/tmp/test.txt", O_RDONLY);
if (fd != -1)
{
int n = read(fd, buf, sizeof(buf));
if (n > 0)
write(STDOUT_FILENO, buf, n);
close(fd);
}
}
sync
sync(将缓冲区数据写入磁盘)
相关函数:fsync,write
表头文件:#include <unistd.h>
定义函数:void sync(void);
函数说明:sync()用来将所有系统缓冲区中的数据写入磁盘,包括修改过的文件数据和文件系统元数据。sync()会立即返回,不等待数据写入完成。
返回值:
write
write(写入文件)
相关函数:read,open,close,lseek,fcntl
表头文件:#include <unistd.h>
定义函数:ssize_t write(int fd, const void *buf, size_t count);
函数说明:write()用来将参数buf所指向的内存中的数据写入参数fd所指向的文件中。参数count为要写入的字节数。实际写入的字节数可能会小于count。
返回值:如果成功返回实际写入的字节数,如果出错则返回-1。
错误代码:EBADF:参数fd无效的文件描述符或不可写。 EFAULT:参数buf指向的内存空间不可访问。 EINTR:调用被信号中断。 EIO:发生I/O错误。 ENOSPC:磁盘空间不足。
范例:
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
main()
{
int fd;
char buf[] = "Hello, World!";
fd = open("/tmp/test.txt", O_CREAT | O_RDWR, 0777);
if (fd != -1)
{
write(fd, buf, sizeof(buf) - 1);
close(fd);
}
}
文件内容操作篇 10
TODO
clearerr
clearerr(清除文件流的错误标志)
相关函数:feof
表头文件:#include <stdio.h>
定义函数:void clearerr(FILE *stream);
函数说明:clearerr()清除参数stream指定的文件流所使用的错误标志。
返回值:
fclose
fclose(关闭文件)
相关函数:close,fflush,fopen,setbuf
表头文件:#include <stdio.h>
定义函数:int fclose(FILE *stream);
函数说明:fclose()用来关闭先前fopen()打开的文件。此动作会让缓冲区内的数据写入文件中,并释放系统所提供的文件资源。
返回值:若关闭文件动作成功则返回0,有错误发生时则返回EOF并把错误代码存到errno。
错误代码:EBADF表示参数stream非已打开的文件。
范例:请参考fopen()。
fdopen
fdopen(将文件描述词转为文件指针)
相关函数:fopen,open,fclose
表头文件:#include <stdio.h>
定义函数:FILE *fdopen(int fildes, const char *mode);
函数说明:fdopen()会将参数fildes的文件描述词,转换为对应的文件指针后返回。参数mode字符串则代表着文件指针的流形态,此形态必须和原先文件描述词读写模式相同。关于mode字符串格式请参考fopen()。
返回值:转换成功时返回指向该流的文件指针。失败则返回NULL,并把错误代码存在errno中。
范例:
#include <stdio.h>
main()
{
FILE *fp = fdopen(0, "w+");
fprintf(fp, "%s\n", "hello!");
fclose(fp);
}
执行: hello!
feof
feof(检查文件流是否读到了文件尾)
相关函数:fopen,fgetc,fgets,fread
表头文件:#include <stdio.h>
定义函数:int feof(FILE *stream);
函数说明:feof()用来检测是否读取到了文件尾,参数stream为fopen()所返回的文件指针。如果已到文件尾则返回非零值,其他情况返回0。
返回值:返回非零值代表已到达文件尾。
fflush
fflush(更新缓冲区)
相关函数:write,fopen,fclose,setbuf
表头文件:#include <stdio.h>
定义函数:int fflush(FILE *stream);
函数说明:fflush()会强迫将缓冲区内的数据写回参数stream指定的文件中。如果参数stream为NULL,fflush()会将所有打开的文件数据更新。
返回值:成功返回0,失败返回EOF,错误代码存于errno中。
错误代码:EBADF 参数stream指定的文件未被打包,或打开状态为只读。其它错误代码参考write()。
fgetc
fgetc(由文件中读取一个字符)
相关函数:open,fread,fscanf,getc
表头文件:#include <stdio.h>
定义函数:int fgetc(FILE *stream);
函数说明:fgetc()从参数stream所指的文件中读取一个字符。若读到文件尾而无数据时便返回EOF。
返回值:getc()会返回读取到的字符,若返回EOF则表示到了文件尾。
范例:
#include <stdio.h>
main()
{
FILE *fp;
int c;
fp = fopen("exist", "r");
while ((c = fgetc(fp)) != EOF) printf("%c", c);
fclose(fp);
}
fgets
fgets(由文件中读取一字符串)
相关函数:open,fread,fscanf,getc
表头文件:#include <stdio.h>
定义函数:char *fgets(char *s, int size, FILE *stream);
函数说明:fgets()用来从参数stream所指的文件内读入字符并存到参数s所指的内存空间,直到出现换行字符、读到文件尾或是已读了size-1个字符为止,最后会加上NULL作为字符串结束。
返回值:gets()若成功则返回s指针,返回NULL则表示有错误发生。
范例:
#include <stdio.h>
main()
{
char s[80];
fputs(fgets(s, 80, stdin), stdout);
}
执行: this is a test /输入/ this is a test /输出/
fileno
fileno(返回文件流所使用的文件描述词)
相关函数:open,fopen
表头文件:#include <stdio.h>
定义函数:int fileno(FILE *stream);
函数说明:fileno()用来取得参数stream指定的文件流所使用的文件描述词。
返回值:返回文件描述词。
范例:
#include <stdio.h>
main()
{
FILE *fp;
int fd;
fp = fopen("/etc/passwd", "r");
fd = fileno(fp);
printf("fd=%d\n", fd);
fclose(fp);
}
执行: fd=3
fopen
fopen(打开文件)
相关函数:open,fclose
表头文件:#include <stdio.h>
定义函数:FILE *fopen(const char *path, const char *mode);
函数说明:参数path字符串包含欲打开的文件路径及文件名,参数mode字符串则代表着流形态。 mode有下列几种形态字符串: r 打开只读文件,该文件必须存在。 r+ 打开可读写的文件,该文件必须存在。 w 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。 w+ 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。 a 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。 a+ 以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。 上述的形态字符串都可以再加一个b字符,如rb、w+b或ab+等组合,加入b字符用来告诉函数库打开的文件为二进制文件,而非纯文本文件。不过在POSIX系统,包含Linux都会忽略该字符。由fopen()所建立的新文件会具有S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH(0666)权限,此文件权限也会参考umask值。
返回值:文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回NULL,并把错误代码存在errno中。
附加说明:一般而言,开文件后会作一些文件读取或写入的动作,若开文件失败,接下来的读写动作也无法顺利进行,所以在fopen()后请作错误判断及处理。
范例:
#include <stdio.h>
main()
{
FILE *fp;
fp = fopen("noexist", "a+");
if (fp == NULL)
return;
fclose(fp);
}
fputc
fputc(将一指定字符写入文件流中)
相关函数:fopen,fwrite,fscanf,putc
表头文件:#include <stdio.h>
定义函数:int fputc(int c, FILE *stream);
函数说明:fputc会将参数c转为unsigned char后写入参数stream指定的文件中。
返回值:fputc()会返回写入成功的字符,即参数c。若返回EOF则代表写入失败。
范例:
#include <stdio.h>
main()
{
FILE *fp;
char a[26] = "abcdefghijklmnopqrstuvwxyz";
int i;
fp = fopen("noexist", "w");
for (i = 0; i < 26; i++) fputc(a[i], fp);
fclose(fp);
}
fputs
fputs(将一指定的字符串写入文件内)
相关函数:fopen,fwrite,fscanf,fputc,putc
表头文件:#include <stdio.h>
定义函数:int fputs(const char *s, FILE *stream);
函数说明:fputs()用来将参数s所指的字符串写入到参数stream所指的文件内。
返回值:若成功则返回写出的字符个数,返回EOF则表示有错误发生。
范例:请参考fgets()。
fread
fread(从文件流读取数据)
相关函数:fopen,fwrite,fseek,fscanf
表头文件:#include <stdio.h>
定义函数:size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
函数说明:fread()用来从文件流中读取数据。参数stream为已打开的文件指针,参数ptr指向欲存放读取进来的数据空间,读取的字符数以参数size*nmemb来决定。Fread()会返回实际读取到的nmemb数目,如果此值比参数nmemb来得小,则代表可能读到了文件尾或有错误发生,这时必须用feof()或ferror()来决定发生什么情况。
返回值:返回实际读取到的nmemb数目。
附加说明:
范例:
#include <stdio.h>
#define nmemb 3
struct test
{
char name[20];
int size;
}
s[nmemb];
main()
{
FILE *stream;
int i;
stream = fopen("/tmp/fwrite", "r");
fread(s, sizeof(struct test), nmemb, stream);
fclose(stream);
for (i = 0; i < nmemb; i++) printf("name[%d]=%-20s:size[%d]=%d\n", i, s[i].name, i, s[i].size);
}
执行: name[0]=Linux! size[0]=6
name[1]=FreeBSD! size[1]=8
name[2]=Windows2000 size[2]=11
freopen
freopen(打开文件)
相关函数:fopen,fclose
表头文件:#include <stdio.h>
定义函数:FILE *freopen(const char *path, const char *mode, FILE *stream);
函数说明:参数path字符串包含欲打开的文件路径及文件名,参数mode请参考fopen()说明。参数stream为已打开的文件指针。Freopen()会将原stream所打开的文件流关闭,然后打开参数path的文件。
返回值:文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回NULL,并把错误代码存在errno中。
范例:
#include <stdio.h>
main()
{
FILE *fp;
fp = fopen("/etc/passwd", "r");
fp = freopen("/etc/group", "r", fp);
fclose(fp);
}
fseek
fseek(移动文件流的读写位置)
相关函数:rewind,ftell,fgetpos,fsetpos,lseek
表头文件:#include <stdio.h>
定义函数:int fseek(FILE *stream, long offset, int whence);
函数说明:fseek()用来移动文件流的读写位置。参数stream为已打开的文件指针,参数offset为根据参数whence来移动读写位置的位移数。 参数 whence为下列其中一种: SEEK_SET从距文件开头offset位移量为新的读写位置。SEEK_CUR以目前的读写位置往后增加offset个位移量。 SEEK_END将读写位置指向文件尾后再增加offset个位移量。 当whence值为SEEK_CUR或SEEK_END时,参数offset允许负值的出现。 下列是较特别的使用方式: 1. 欲将读写位置移动到文件开头时:fseek(FILE *stream,0,SEEK_SET); 2. 欲将读写位置移动到文件尾时:fseek(FILE *stream,0,SEEK_END);
返回值:当调用成功时则返回0,若有错误则返回-1,errno会存放错误代码。
附加说明:fseek()不像lseek()会返回读写位置,因此必须使用ftell()来取得目前读写的位置。
范例:
#include <stdio.h>
main()
{
FILE *stream;
long offset;
fpos_t pos;
stream = fopen("/etc/passwd", "r");
fseek(stream, 5, SEEK_SET);
printf("offset=%d\n", ftell(stream));
rewind(stream);
fgetpos(stream, &pos);
printf("offset=%d\n", pos);
pos = 10;
fsetpos(stream, &pos);
printf("offset=%d\n", ftell(stream));
fclose(stream);
}
执行: offset=5 offset=0 offset=10
ftell
ftell(取得文件流的读取位置)
相关函数:fseek,rewind,fgetpos,fsetpos
表头文件:#include <stdio.h>
定义函数:long ftell(FILE *stream);
函数说明:ftell()用来取得文件流目前的读写位置。参数stream为已打开的文件指针。
返回值:当调用成功时则返回目前的读写位置,若有错误则返回-1,errno会存放错误代码。
错误代码:EBADF 参数stream无效或可移动读写位置的文件流。
范例:参考fseek()。
fwrite
fwrite(将数据写至文件流)
相关函数:fopen,fread,fseek,fscanf
表头文件:#include <stdio.h>
定义函数:size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
函数说明:fwrite()用来将数据写入文件流中。参数stream为已打开的文件指针,参数ptr指向欲写入的数据地址,总共写入的字符数以参数size*nmemb来决定。Fwrite()会返回实际写入的nmemb数目。
返回值:返回实际写入的nmemb数目。
范例:
#include <stdio.h>
#define set_s(x, y)
{
strcpy(s[x].name, y);
s[x].size = strlen(y);
}
#define nmemb 3
struct test
{
char name[20];
int size;
}
s[nmemb];
main()
{
FILE *stream;
set_s(0, "Linux!");
set_s(1, "FreeBSD!");
set_s(2, "Windows2000.");
stream = fopen("/tmp/fwrite", "w");
fwrite(s, sizeof(struct test), nmemb, stream);
fclose(stream);
}
执行: 参考fread()。
getc
getc(由文件中读取一个字符)
相关函数:read,fopen,fread,fgetc
表头文件:#include <stdio.h>
定义函数:int getc(FILE *stream);
函数说明:getc()用来从参数stream所指的文件中读取一个字符。若读到文件尾而无数据时便返回EOF。虽然getc()与fgetc()作用相同,但getc()为宏定义,非真正的函数调用。
返回值:getc()会返回读取到的字符,若返回EOF则表示到了文件尾。
范例:参考fgetc()。
getchar
getchar(由标准输入设备内读进一字符)
相关函数:fopen,fread,fscanf,getc
表头文件:#include <stdio.h>
定义函数:int getchar(void);
函数说明:getchar()用来从标准输入设备中读取一个字符。然后将该字符从unsigned char转换成int后返回。
返回值:getchar()会返回读取到的字符,若返回EOF则表示有错误发生。
附加说明:getchar()非真正函数,而是getc(stdin)宏定义。
范例:
#include <stdio.h>
main()
{
FILE *fp;
int c, i;
for (i = 0; i < 5; i++)
{
c = getchar();
putchar(c);
}
}
执行: 1234 /输入/ 1234 /输出/
gets
gets(由标准输入设备内读进一字符串)
相关函数:fopen,fread,fscanf,fgets
表头文件:#include <stdio.h>
定义函数:char *gets(char *s);
函数说明:gets()用来从标准设备读入字符并存到参数s所指的内存空间,直到出现换行字符或读到文件尾为止,最后加上NULL作为字符串结束。
返回值:gets()若成功则返回s指针,返回NULL则表示有错误发生。
附加说明:由于gets()无法知道字符串s的大小,必须遇到换行字符或文件尾才会结束输入,因此容易造成缓冲溢出的安全性问题。建议使用fgets()取代。
范例:参考fgets()
mktemp
mktemp(产生唯一的临时文件名)
相关函数:tmpfile
表头文件:#include <stdlib.h>
定义函数:char *mktemp(char *template);
函数说明:mktemp()用来产生唯一的临时文件名。参数template所指的文件名称字符串中最后六个字符必须是XXXXXX。产生后的文件名会借字符串指针返回。
返回值:文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回NULL,并把错误代码存在errno中。
附加说明:参数template所指的文件名称字符串必须声明为数组,如: char template[] = "template-XXXXXX"; 不可用char *template = "template-XXXXXX";
范例:
#include <stdlib.h>
main()
{
char template[] = "template-XXXXXX";
mktemp(template);
printf("template=%s\n", template);
}
putc
putc(将一指定字符写入文件中)
相关函数:fopen,fwrite,fscanf,fputc
表头文件:#include <stdio.h>
定义函数:int putc(int c, FILE *stream);
函数说明:putc()会将参数c转为unsigned char后写入参数stream指定的文件中。虽然putc()与fputc()作用相同,但putc()为宏定义,非真正的函数调用。
返回值:putc()会返回写入成功的字符,即参数c。若返回EOF则代表写入失败。
范例:参考fputc()
putchar
putchar(将指定的字符写到标准输出设备)
相关函数:fopen,fwrite,fscanf,fputc
表头文件:#include <stdio.h>
定义函数:int putchar(int c);
函数说明:putchar()用来将参数c字符写到标准输出设备。
返回值:putchar()会返回输出成功的字符,即参数c。若返回EOF则代表输出失败。
附加说明:putchar()非真正函数,而是putc(c, stdout)宏定义。
范例:参考getchar()。
rewind
rewind(重设文件流的读写位置为文件开头)
相关函数:fseek,ftell,fgetpos,fsetpos
表头文件:#include <stdio.h>
定义函数:void rewind(FILE *stream);
函数说明:rewind()用来把文件流的读写位置移至文件开头。参数stream为已打开的文件指针。此函数相当于调用fseek(stream, 0, SEEK_SET)。
返回值:
范例:参考fseek()
setbuf
setbuf(设置文件流的缓冲区)
相关函数:setbuffer,setlinebuf,setvbuf
表头文件:#include <stdio.h>
定义函数:void setbuf(FILE *stream, char *buf);
函数说明:在打开文件流后,读取内容之前,调用setbuf()可以用来设置文件流的缓冲区。参数stream为指定的文件流,参数buf指向自定的缓冲区起始地址。如果参数buf为NULL指针,则为无缓冲IO。Setbuf()相当于调用:setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ)
返回值:
setbuffer
setbuffer(设置文件流的缓冲区)
相关函数:setlinebuf,setbuf,setvbuf
表头文件:#include <stdio.h>
定义函数:void setbuffer(FILE *stream, char *buf, size_t size);
函数说明:在打开文件流后,读取内容之前,调用setbuffer()可用来设置文件流的缓冲区。参数stream为指定的文件流,参数buf指向自定的缓冲区起始地址,参数size为缓冲区大小。
返回值:
setlinebuf
setlinebuf(设置文件流为线性缓冲区)
相关函数:setbuffer,setbuf,setvbuf
表头文件:#include <stdio.h>
定义函数:void setlinebuf(FILE *stream);
函数说明:setlinebuf()用来设置文件流以换行为依据的无缓冲IO。相当于调用:setvbuf(stream, (char *)NULL, _IOLBF, 0);请参考setvbuf()。
返回值:
setvbuf
setvbuf(设置文件流的缓冲区)
相关函数:setbuffer,setlinebuf,setbuf
表头文件:#include <stdio.h>
定义函数:int setvbuf(FILE *stream, char *buf, int mode, size_t size);
函数说明:在打开文件流后,读取内容之前,调用setvbuf()可以用来设置文件流的缓冲区。参数stream为指定的文件流,参数buf指向自定的缓冲区起始地址,参数size为缓冲区大小,参数mode有下列几种: _IONBF 无缓冲IO _IOLBF 以换行为依据的无缓冲IO _IOFBF 完全无缓冲IO。如果参数buf为NULL指针,则为无缓冲IO。
返回值:
ungetc
ungetc(将指定字符写回文件流中)
相关函数:fputc,getchar,getc
表头文件:#include <stdio.h>
定义函数:int ungetc(int c, FILE *stream);
函数说明:ungetc()将参数c字符写回参数stream所指定的文件流。这个写回的字符会由下一个读取文件流的函数取得。
返回值:成功则返回c字符,若有错误则返回EOF。
进程操作篇 11
TODO
atexit
atexit(设置程序正常结束前调用的函数)
相关函数:_exit, exit, on_exit
表头文件:#include <stdlib.h>
定义函数:int atexit(void (*function)(void));
函数说明:atexit()用来设置一个程序正常结束前调用的函数。当程序通过调用exit()或从main中返回时,参数function所指定的函数会先被调用,然后才真正由exit()结束程序。
返回值:如果执行成功则返回0,否则返回-1,失败原因存于errno中。
范例:
#include <stdlib.h>
void my_exit(void)
{
printf("before exit()!\n");
}
main()
{
atexit(my_exit);
exit(0);
}
执行: before exit()!
execl
execl(执行文件)
相关函数:fork,execle,execlp,execv,execve,execvp
表头文件:#include <unistd.h>
定义函数:int execl(const char *path, const char *arg, ...);
函数说明:execl()用来执行参数path字符串所代表的文件路径,接下来的参数代表执行该文件时传递过去的argv(0)、argv[1]...,最后一个参数必须用空指针(NULL)作结束。
返回值:如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno中。
范例:
#include <unistd.h>
main()
{
execl("/bin/ls", "ls", "-al", "/etc/passwd", (char *)0);
}
执行: /*
执行/bin/ls
-al
/etc/passwd
*/
-rw-r--r--
1
root
root
705
Sep
3
13:52
/etc/passwd
execlp
execlp(从PATH环境变量中查找文件并执行)
相关函数:fork,execl,execle,execv,execve,execvp
表头文件:#include <unistd.h>
定义函数:int execlp(const char *file, const char *arg, ...);
函数说明:execlp()会从PATH环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件,然后将第二个以后的参数当做该文件的argv[0]、argv[1]...,最后一个参数必须用空指针(NULL)作结束。
返回值:如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno中。
错误代码:参考execve()。
范例:
/* 执行ls -al /etc/passwd execlp()会依PATH变量中的/bin找到/bin/ls */
#include <unistd.h>
main()
{
execlp("ls", "ls", "-al", "/etc/passwd", (char *)0);
}
执行: -rw-r--r-- 1 root root 705 Sep 3 13:52 /etc/passwd
execv
execv(执行文件)
相关函数:fork,execl,execle,execlp,execve,execvp
表头文件:#include <unistd.h>
定义函数:int execv(const char *path, char *const argv[]);
函数说明:execv()用来执行参数path字符串所代表的文件路径,与execl()不同的地方在于execve()只需两个参数,第二个参数利用数组指针来传递给执行文件。
返回值:如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno中。
错误代码:请参考execve()。
范例:
/* 执行/bin/ls -al /etc/passwd */
#include <unistd.h>
main()
{
char *argv[] =
{
"ls", "-al", "/etc/passwd", (char *)0
} ; execv("/bin/ls", argv);
}
执行: -rw-r--r-- 1 root root 705 Sep 3 13:52 /etc/passwd
execve
execve(执行文件)
相关函数:fork,execl,execle,execlp,execv,execvp
表头文件:#include <unistd.h>
定义函数:int execve(const char *filename, char *const argv[], char *const envp[]);
函数说明:execve()用来执行参数filename字符串所代表的文件路径,第二个参数系利用数组指针来传递给执行文件,最后一个参数则为传递给执行文件的新环境变量数组。
返回值:如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno中。
错误代码:EACCES: 欲执行的文件不具有用户可执行的权限。
范例:
#include <unistd.h>
main()
{
char *argv[] =
{
"ls", "-al", "/etc/passwd", (char *)0
};
char *envp[] =
{
"PATH=/bin", 0
};
execve("/bin/ls", argv, envp);
}
执行: -rw-r--r-- 1 root root 705 Sep 3 13:52 /etc/passwd
execvp
execvp(执行文件)
相关函数:fork,execl,execle,execlp,execv,execve
表头文件:#include <unistd.h>
定义函数:int execvp(const char *file, char *const argv[]);
函数说明:execvp()会从PATH环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件,然后将第二个参数argv传给该欲执行的文件。
返回值:如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno中。
错误代码:请参考execve()。
范例:
/* 请与execlp()范例对照 */
#include <unistd.h>
main()
{
char *argv[] =
{
"ls", "-al", "/etc/passwd", 0
};
execvp("ls", argv);
}
执行: -rw-r--r-- 1 root root 705 Sep 3 13:52 /etc/passwd
exit
exit(正常结束进程)
相关函数:_exit,atexit,on_exit
表头文件:#include <stdlib.h>
定义函数:void exit(int status);
函数说明:exit()用来正常终结目前进程的执行,并把参数status返回给父进程,而进程所有的缓冲区数据会自动写回并关闭未关闭的文件。
返回值:
范例:参考wait()
_exit
_exit(结束进程执行)
相关函数:exit,wait,abort
表头文件:#include <unistd.h>
定义函数:void _exit(int status);
函数说明:_exit()用来立刻结束目前进程的执行,并把参数status返回给父进程,并关闭未关闭的文件。此函数调用后不会返回,并且会传递SIGCHLD信号给父进程,父进程可以由wait函数取得子进程结束状态。
返回值:
附加说明:_exit()不会处理标准I/O缓冲区,如要更新缓冲区请使用exit()。
vfork
vfork(建立一个新的进程)
相关函数:wait,execve
表头文件:#include <unistd.h>
定义函数:pid_t vfork(void);
函数说明:vfork()会产生一个新的子进程,其子进程会复制父进程的数据与堆栈空间,并继承父进程的用户代码、组代码、环境变量、已打开的文件代码、工作目录和资源限制等。Linux使用copy-on-write(COW)技术,只有当其中一进程试图修改欲复制的空间时才会做真正的复制动作,由于这些继承的信息是复制而来,并非指相同的内存空间,因此子进程对这些变量的修改和父进程并不会同步。此外,子进程不会继承父进程的文件锁定和未处理的信号。注意,Linux不保证子进程会比父进程先执行或晚执行,因此编写程序时要留意死锁或竞争条件的发生。
返回值:如果vfork()成功则在父进程会返回新建立的子进程代码(PID),而在新建立的子进程中则返回0。如果vfork失败则直接返回-1,失败原因存于errno中。
错误代码:EAGAIN 内存不足。ENOMEM 内存不足,无法配置核心所需的数据结构空间。
范例:
#include <unistd.h>
main()
{
if (vfork() == 0)
{
printf("This is the child process\n");
}
else
{
printf("This is the parent process\n");
}
}
执行: this is the parent process this is the child process
getpgid
getpgid(取得进程组识别码)
相关函数:setpgid,setpgrp,getpgrp
表头文件:#include <unistd.h>
定义函数:pid_t getpgid(pid_t pid);
函数说明:getpgid()用来取得参数pid指定进程所属的组识别码。如果参数pid为0,则会取得目前进程的组识别码。
返回值:执行成功则返回组识别码,如果有错误则返回-1,错误原因存于errno中。
错误代码:ESRCH 找不到符合参数pid指定的进程。
范例:
/* 取得init进程(pid=1)的组识别码 */
#include <unistd.h>
main()
{
printf("init gid = %d\n", getpgid(1));
}
执行: init gid = 0
getpgrp
getpgrp(取得进程组识别码)
相关函数:setpgid,getpgid,getpgrp
表头文件:#include <unistd.h>
定义函数:pid_t getpgrp(void);
函数说明:getpgrp()用来取得目前进程所属的组识别码。此函数相当于调用getpgid(0)。
返回值:返回目前进程所属的组识别码。
范例:
#include <unistd.h>
main()
{
printf("my gid =%d\n", getpgrp());
}
执行: my gid =29546
getpid
getpid(取得进程识别码)
相关函数:fork,kill,getpid
表头文件:#include <unistd.h>
定义函数:pid_t getpid(void);
函数说明:getpid()用来取得目前进程的进程识别码,许多程序利用取到的此值来建立临时文件,以避免临时文件相同带来的问题。
返回值:目前进程的进程识别码
范例:
#include <unistd.h>
main()
{
printf("pid=%d\n", getpid());
}
执行: pid=1494 /每次执行结果都不一定相同/
getppid
getppid(取得父进程的进程识别码)
相关函数:fork,kill,getpid
表头文件:#include <unistd.h>
定义函数:pid_t getppid(void);
函数说明:getppid()用来取得目前进程的父进程识别码。
返回值:目前进程的父进程识别码。
范例:
#include <unistd.h>
main()
{
printf("My parent 'pid =%d\n", getppid());
}
执行: My parent pid =463
getpriority
getpriority(取得程序进程执行优先权)
相关函数:setpriority,nice
表头文件:#include <sys/time.h> #include <sys/resource.h>
定义函数:int getpriority(int which, int who);
函数说明:getpriority()可用来取得进程、进程组和用户的进程执行优先权。 参数 which有三种数值,参数who则依which值有不同定义: PRIO_PROCESS who为进程识别码 PRIO_PGRP who为进程的组识别码 PRIO_USER who为用户识别码 此函数返回的数值介于-20至20之间,代表进程执行优先权,数值越低代表有较高的优先次序,执行会较频繁。
返回值:返回进程执行优先权,如有错误发生返回值则为-1且错误原因存于errno。
附加说明:由于返回值有可能是-1,因此要同时检查errno是否存有错误原因。最好在调用此函数前先清除errno变量。
错误代码:ESRCH 参数which或who可能有错,而找不到符合的进程。EINVAL 参数which值错误。
nice
nice(改变进程优先顺序)
相关函数:setpriority,getpriority
表头文件:#include <unistd.h>
定义函数:int nice(int inc);
函数说明:nice()用来改变进程的进程执行优先顺序。参数inc数值越大则优先顺序排在越后面,即表示进程执行会越慢。只有超级用户才能使用负的inc值,代表优先顺序排在前面,进程执行会较快。
返回值:如果执行成功则返回0,否则返回-1,失败原因存于errno中。
错误代码:EPERM 一般用户企图转用负的参数inc值改变进程优先顺序。
on_exit
on_exit(设置程序正常结束前调用的函数)
相关函数:_exit,atexit,exit
表头文件:#include <stdlib.h>
定义函数:int on_exit(void (*function)(int, void *), void *arg);
函数说明:on_exit()用来设置一个程序正常结束前调用的函数。当程序通过调用exit()或从main中返回时,参数function所指定的函数会先被调用,然后才真正由exit()结束程序。参数arg指针会传给参数function函数,详细情况请见范例。
返回值:如果执行成功则返回0,否则返回-1,失败原因存于errno中。
附加说明:
范例:
#include <stdlib.h>
void my_exit(int status, void *arg)
{
printf("before exit()!\n");
printf("exit (%d)\n", status);
printf("arg = %s\n", (char *)arg);
}
main()
{
char *str = "test";
on_exit(my_exit, (void *)str);
exit(1234);
}
执行:
before exit()!
exit (1234)
arg = test
setpgid
setpgid(设置进程组识别码)
相关函数:getpgid,setpgrp,getpgrp
表头文件:#include <unistd.h>
定义函数:int setpgid(pid_t pid, pid_t pgid);
函数说明:setpgid()将参数pid指定进程所属的组识别码设为参数pgid指定的组识别码。如果参数pid为0,则会用来设置目前进程的组识别码,如果参数pgid为0,则会以目前进程的进程识别码来取代。
返回值:执行成功则返回组识别码,如果有错误则返回-1,错误原因存于errno中。
错误代码:EINVAL 参数pgid小于0。 EPERM 进程权限不足,无法完成调用。 ESRCH 找不到符合参数pid指定的进程
setpgrp
setpgrp(设置进程组识别码)
相关函数:getpgid,setpgid,getpgrp
表头文件:#include <unistd.h>
定义函数:int setpgrp(void);
函数说明:setpgrp()将目前进程所属的组识别码设为目前进程的进程识别码。此函数相当于调用setpgid(0,0)。
返回值:执行成功则返回组识别码,如果有错误则返回-1,错误原因存于errno中。
setpriority
setpriority(设置程序进程执行优先权)
相关函数:getpriority,nice
表头文件:#include <sys/time.h> #include <sys/resource.h>
定义函数:int setpriority(int which, int who, int prio);
函数说明:setpriority()可用来设置进程、进程组和用户的进程执行优先权。参数which有三种数值,参数who则依which值有不同定义: PRIO_PROCESS who为进程识别码 PRIO_PGRP who为进程的组识别码 PRIO_USER who为用户识别码 参数prio介于-20至20之间。代表进程执行优先权,数值越低代表有较高的优先次序,执行会较频繁。此优先权默认是0,而只有超级用户(root)允许降低此值。
返回值:执行成功则返回0,如果有错误发生返回值则为-1,错误原因存于errno。 ESRCH 参数which或who可能有错,而找不到符合的进程 EINVAL 参数which值错误。 EPERM 权限不够,无法完成设置 EACCES 一般用户无法降低优先权
system
system(执行shell命令)
相关函数:fork,execve,waitpid,popen
表头文件:#include <stdlib.h>
定义函数:int system(const char *string);
函数说明:system()会调用fork()产生子进程,由子进程来调用/bin/sh -c string来执行参数string字符串所代表的命令,此命令执行完后随即返回原调用的进程。在调用system()期间SIGCHLD信号会被暂时搁置,SIGINT和SIGQUIT信号则会被忽略。
返回值:如果system()在调用/bin/sh时失败则返回127,其他失败原因返回-1。若参数string为空指针(NULL),则返回非零值。如果system()调用成功则最后会返回执行shell命令后的返回值,但是此返回值也有可能为system()调用/bin/sh失败所返回的127,因此最好能再检查errno来确认执行成功。
附加说明:在编写具有SUID/SGID权限的程序时请勿使用system(),system()会继承环境变量,通过环境变量可能会造成系统安全的问题。
范例:
#include <stdlib.h>
main()
{
system("ls -al /etc/passwd /etc/shadow");
}
执行: -rw-r--r-- 1 root root 705 Sep 3 13:52 /etc/passwd
-r--------- 1 root root 572 Sep 2 15:34 /etc/shadow
wait
wait(等待子进程中端或结束)
相关函数:waitpid,fork
表头文件:#include <sys/types.h> #include <sys/wait.h>
定义函数:pid_t wait(int *status);
函数说明:wait()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用wait()时子进程已经结束,则wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数status返回,而子进程的进程识别码也会一块返回。如果不介意结束状态值,则参数status可以设成NULL。子进程的结束状态值请参考waitpid()。
返回值:如果执行成功则返回子进程识别码(PID),如果有错误发生则返回-1。失败原因存于errno中。
范例:
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
main()
{
pid_t pid;
int status, i;
if (fork() == 0)
{
printf("This is the child process .pid =%d\n", getpid());
exit(5);
}
else
{
sleep(1);
printf("This is the parent process ,wait for child...\n");
pid = wait(&status);
i = WEXITSTATUS(status);
printf("child's pid =%d .exit status=%d\n", pid, i);
}
}
执行: This is the child process.pid=1501
This
is
the
parent
process
.wait
for
child...
child's
pid
=1501,exit
status
=5
waitpid
waitpid(等待子进程中端或结束)
相关函数:wait,fork
表头文件:#include <sys/types.h> #include <sys/wait.h>
定义函数:pid_t waitpid(pid_t pid, int *status, int options);
函数说明:waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用wait()时子进程已经结束,则wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数status返回,而子进程的进程识别码也会一块返回。如果不介意结束状态值,则参数status可以设成NULL。参数pid为欲等待的子进程识别码,其他数值意义如下: pid < -1 等待进程组识别码为pid绝对值的任何子进程。 pid = -1 等待任何子进程,相当于wait()。 pid = 0 等待进程组识别码与目前进程相同的任何子进程。 pid > 0 等待任何子进程识别码为pid的子进程。 参数option可以为0或下面的OR组合: WNOHANG 如果没有任何已经结束的子进程则马上返回,不予以等待。 WUNTRACED 如果子进程进入暂停执行情况则马上返回,但结束状态不予以理会。 子进程的结束状态返回后存于status,底下有几个宏可判别结束情况: WIFEXITED(status) 如果子进程正常结束则为非0值。 WEXITSTATUS(status) 取得子进程exit()返回的结束代码,一般会先用WIFEXITED来判断是否正常结束才能使用此宏。 WIFSIGNALED(status) 如果子进程是因为信号而结束则此宏值为真。 WTERMSIG(status) 取得子进程因信号而中止的信号代码,一般会先用WIFSIGNALED来判断后才使用此宏。 WIFSTOPPED(status) 如果子进程处于暂停执行情况则此宏值为真。一般只有使用WUNTRACED时才会有此情况。 WSTOPSIG(status) 取得引发子进程暂停的信号代码,一般会先用WIFSTOPPED来判断后才使用此宏。
返回值:如果执行成功则返回子进程识别码(PID),如果有错误发生则返回-1。失败原因存于errno中。
范例:参考wait()。
fprintf
fprintf(格式化输出数据至文件)
相关函数:printf,fscanf,vfprintf
表头文件:#include <stdio.h>
定义函数:int fprintf(FILE *stream, const char *format, ...);
函数说明:fprintf()会根据参数format字符串来转换并格式化数据,然后将结果输出到参数stream指定的文件中,直到出现字符串结束('\0')为止。 关于参数format字符串的格式请参考printf()。
返回值:成功则返回实际输出的字符数,失败则返回-1,错误原因存于errno中。
范例:
#include <stdio.h>
main()
{
int i = 150;
int j = -100;
double k = 3.14159;
fprintf(stdout, "%d %f %x\n", j, k, i);
fprintf(stdout, "%2d %*d\n", i, 2, i);
}
执行: -100 3.141590 96 150 150
fscanf
fscanf(格式化字符串输入)
相关函数:scanf,sscanf
表头文件:#include <stdio.h>
定义函数:int fscanf(FILE *stream, const char *format, ...);
函数说明:fscanf()会自参数stream的文件流中读取字符串,再根据参数format字符串来转换并格式化数据。格式转换形式请参考scanf()。转换后的结构存于对应的参数内。
返回值:成功则返回参数数目,失败则返回-1,错误原因存于errno中。
范例:
#include <stdio.h>
main()
{
int i;
unsigned int j;
char s[5];
fscanf(stdin, "%d %x %5[a-z] %*s %f", &i, &j, s, s);
printf("%d %d %s\n", i, j, s);
}
执行: 10 0x1b aaaaaaaaa bbbbbbbbbb /从键盘输入/ 10 27 aaaaa
printf
printf(格式化输出数据)
相关函数:scanf,snprintf
表头文件:#include <stdio.h>
定义函数:int printf(const char *format, ...);
函数说明:printf()会根据参数format字符串来转换并格式化数据,然后将结果写出到标准输出设备,直到出现字符串结束('\0')为止。参数format字符串可包含下列三种字符类型: 1. 一般文本,伴随直接输出。 2. ASCII控制字符,如\t、\n等。 3. 格式转换字符。 格式转换为一个百分比符号(%)及其后的格式字符所组成。一般而言,每个%符号在其后都必需有一printf()的参数与之相呼应(只有当%%转换字符出现时会直接输出%字符),而欲输出的数据类型必须与其相对应的转换字符类型相同。 printf()格式转换的一般形式如下: %(flags)(width)(.prec)type 以中括号括起来的参数为选择性参数,而%与type则是必要的。
返回值:成功则返回实际输出的字符数,失败则返回-1,错误原因存于errno中。
范例:
#include <stdio.h>
main()
{
int i = 150;
int j = -100;
double k = 3.14159;
printf("%d %f %x\n", j, k, i);
printf("%2d %*d\n", i, 2, i);
/*参数2会代入格式*中,而与%2d同意义*/
}
执行: -100 3.14159 96 150 150
sacnf
sacnf(格式化字符串输入)
相关函数:fscanf,snprintf
表头文件:#include <stdio.h>
定义函数:int scanf(const char *format, ...);
函数说明:scanf()会将输入的数据根据参数format字符串来转换并格式化数据。scanf()格式转换的一般形式如下: %[*][size][l][h]type 以中括号括起来的参数为选择性参数,而%与type则是必要的。
返回值:成功则返回参数数目,失败则返回-1,错误原因存于errno中。
范例:
#include <stdio.h>
main()
{
int i;
unsigned int j;
char s[5];
scanf("%d %x %5[a-z] %*s %f", &i, &j, s, s);
printf("%d %d %s\n", i, j, s);
}
执行: 10 0x1b aaaaaaaaaa bbbbbbbbbb 10 27 aaaaa
sprintf
sprintf(格式化字符串复制)
相关函数:printf,sprintf
表头文件:#include <stdio.h>
定义函数:int sprintf(char *str, const char *format, ...);
函数说明:sprintf()会根据参数format字符串来转换并格式化数据,然后将结果复制到参数str所指的字符串数组,直到出现字符串结束('\0')为止。关于参数format字符串的格式请参考printf()。
返回值:成功则返回参数str字符串长度,失败则返回-1,错误原因存于errno中。
附加说明:使用此函数得留意堆栈溢出,或改用snprintf()。
范例:
#include <stdio.h>
main()
{
char *a = "This is string A!";
char buf[80];
sprintf(buf, ">>> %s<<<\n", a);
printf("%s", buf);
}
执行:
This is string A!<<<
sscanf
TODO
vfprintf
TODO
vfscanf
vfscanf(格式化字符串输入)
相关函数:scanf,sscanf,fscanf
表头文件:#include <stdio.h>
定义函数:int vfscanf(FILE *stream, const char *format, va_list ap);
函数说明:vfscanf()会自参数stream的文件流中读取字符串,再根据参数format字符串来转换并格式化数据。格式转换形式请参考scanf()。转换后的结果存于对应的参数内。va_list用法请参考附录C或vprintf()。
返回值:成功则返回参数数目,失败则返回-1,错误原因存于errno中。
范例:参考fscanf()及vprintf()。
vprintf
vprintf(格式化输出数据)
相关函数:printf,vfprintf,vsprintf
表头文件:#include <stdio.h> #include <stdarg.h>
定义函数:int vprintf(const char *format, va_list ap);
函数说明:vprintf()作用和printf()相同,参数format格式也相同。va_list为不定个数的参数列,用法及范例请参考附录C。
返回值:成功则返回实际输出的字符数,失败则返回-1,错误原因存于errno中。
范例:
#include <stdio.h>
#include <stdarg.h>
int my_printf(const char *format, ...)
{
va_list ap;
int retval;
va_start(ap, format);
printf("my_printf():");
retval = vprintf(format, ap);
va_end(ap);
return retval;
}
main()
{
int i = 150, j = -100;
double k = 3.14159;
my_printf("%d %f %x\n", j, k, i);
my_printf("%2d %*d\n", i, 2, i);
}
执行: my_printf(): -100 3.14159
96my_printf(): 150 150
vscanf
vprintf(格式化输出数据)
相关函数:printf,vfprintf,vsprintf
表头文件:#include <stdio.h> #include <stdarg.h>
定义函数:int vprintf(const char *format, va_list ap);
函数说明:vprintf()作用和printf()相同,参数format格式也相同。va_list为不定个数的参数列,用法及范例请参考附录C。
返回值:成功则返回实际输出的字符数,失败则返回-1,错误原因存于errno中。
范例:
#include <stdio.h>
#include <stdarg.h>
int my_printf(const char *format, ...)
{
va_list ap;
int retval;
va_start(ap, format);
printf("my_printf():");
retval = vprintf(format, ap);
va_end(ap);
return retval;
}
main()
{
int i = 150, j = -100;
double k = 3.14159;
my_printf("%d %f %x\n", j, k, i);
my_printf("%2d %*d\n", i, 2, i);
}
执行: my_printf(): -100 3.14159
96my_printf(): 150 150
vsprintf
vsprintf(格式化字符串复制)
相关函数:vnsprintf,vprintf,snprintf
表头文件:#include <stdio.h>
定义函数:int vsprintf(char *str, const char *format, va_list ap);
函数说明:vsprintf()会根据参数format字符串来转换并格式化数据,然后将结果复制到参数str所指的字符串数组,直到出现字符串结束('\0')为止。关于参数format字符串的格式请参考printf()。va_list用法请参考附录C或vprintf()范例。
返回值:成功则返回参数str字符串长度,失败则返回-1,错误原因存于errno中。
范例:请参考vprintf()及vsprintf()。
vsscanf
vsscanf(格式化字符串输入)
相关函数:vscanf,vfscanf
表头文件:#include <stdio.h>
定义函数:int vsscanf(const char *str, const char *format, va_list ap);
函数说明:vsscanf()会将参数str的字符串根据参数format字符串来转换并格式化数据。格式转换形式请参考附录C或vprintf()范例。
返回值:成功则返回参数数目,失败则返回-1,错误原因存于errno中。
范例:请参考sscanf()及vprintf()。
文件权限控制篇 12
TODO
access
access(判断是否具有存取文件的权限)
相关函数:stat,open,chmod,chown,setuid,setgid
表头文件:#include <unistd.h>
定义函数:int access(const char *pathname, int mode);
函数说明:access()会检查是否可以读/写某一已存在的文件。参数mode有几种情况组合,R_OK,W_OK,X_OK和F_OK。R_OK,W_OK与X_OK用来检查文件是否具有读取、写入和执行的权限。F_OK则是用来判断该文件是否存在。由于access()只作权限的核查,并不理会文件形态或文件内容,因此,如果一目r录表示为"可写入",表示可以在该目录中建立新文件等操作,而非意味此目录可以被当做文件处理。例如,你会发现DOS的文件都具有"可执行"权限,但用execve()执行时则会失败。
返回值:若所有欲查核的权限都通过了检查则返回0值,表示成功,只要有一权限被禁止则返回-1。
错误代码:EACCESS 参数pathname 所指定的文件不符合所要求测试的权限。 EROFS 欲测试写入权限的文件存在于只读文件系统内。 EFAULT 参数pathname指针超出可存取内存空间。 EINVAL 参数mode 不正确。 ENAMETOOLONG 参数pathname太长。 ENOTDIR 参数pathname为一日录。 ENOMEM 核心内存不足 ELOOP 参数pathname有过多符号连接问题。 EIO I/O 存取错误。
附加说明:使用access()作用户认证方面的判断要特别小心,例如在access()后再做open()的空文件可能会造成系统安全上的问题。
范例:
/* 判断是否允许读取/etc/passwd */
#include <unistd.h>
int main()
{
if (access("/etc/passwd", R_OK)
== 0) printf("/etc/passwd can be read\n");
}
执行: /etc/passwd can be read
alphasort
alphasort(依字母顺序排序目录结构)
相关函数:scandir,qsort
表头文件:#include <dirent.h>
定义函数:int alphasort(const struct dirent **a, const struct dirent **b);
函数说明:alphasort()为scandir()最后调用qsort()函数时传给qsort()作为判断的函数,详细说明请参考scandir()及qsort()。
返回值:参考qsort()。
范例:
/* 读取/目录下所有的目录结构,并依字母顺序排列 */
main()
{
struct dirent **namelist;
int i, total;
total = scandir("/", &namelist, 0, alphasort);
if (total < 0)
perror("scandir");
else
{
for (i = 0; i < total; i++) printf("%s\n", namelist[i]->d_name);
printf("total = %d\n", total);
}
}
执行: ..
.gnome
.gnome_private
ErrorLog
Weblog
bin
boot
dev
dosc
dosd
etc
home
lib
lost+found
misc
mnt
opt
proc
root
sbin
tmp
usr
var
total = 24
chdir
chdir(改变当前的工作目录)
相关函数:getcwd,chroot
表头文件:#include <unistd.h>
定义函数:int chdir(const char *path);
函数说明:chdir()用来将当前的工作目录改变成以参数path所指的目录。
返回值:执行成功则返回0,失败返回-1,errno为错误代码。
范例:
#include <unistd.h>
main()
{
chdir("/tmp");
printf("current working directory: %s\n", getcwd(NULL, NULL));
}
执行: current working directory :/tmp
chmod
chmod(改变文件的权限)
相关函数:fchmod,stat,open,chown
表头文件:#include <sys/types.h> #include <sys/stat.h>
定义函数:int chmod(const char *path, mode_t mode);
函数说明:chmod()会依参数mode权限来更改参数path指定文件的权限。 参数 mode有下列数种组合 S_ISUID 04000 文件的(set user-id on execution)位 S_ISGID 02000 文件的(set group-id on execution)位 S_ISVTX 01000 文件的sticky位 S_IRUSR(S_IREAD) 00400 文件所有者具可读取权限 S_IWUSR(S_IWRITE)00200 文件所有者具可写入权限 S_IXUSR(S_IEXEC) 00100 文件所有者具可执行权限 S_IRGRP 00040 用户组具可读取权限 S_IWGRP 00020 用户组具可写入权限 S_IXGRP 00010 用户组具可执行权限 S_IROTH 00004 其他用户具可读取权限 S_IWOTH 00002 其他用户具可写入权限 S_IXOTH 00001 其他用户具可执行权限 只有该文件的所有者或有效用户识别码为0,才可以修改该文件权限。基于系统安全,如果欲将数据写入一执行文件,而该执行文件具有S_ISUID或S_ISGID权限,则这两个位会被清除。如果一目r录具有S_ISUID位权限,表示在此目录下只有该文件的所有者或root可以删除该文件。
返回值:权限改变成功返回0,失败返回-1,错误原因存于errno。
错误代码:EPERM 进程的有效用户识别码与欲修改权限的文件拥有者不同,而且也不具root权限。 EACCESS 参数path所指定的文件无法存取。 EROFS 欲写入权限的文件存在于只读文件系统内。 EFAULT 参数path指针超出可存取内存空间。 EINVAL 参数mode不正确 ENAMETOOLONG 参数path太长 ENOENT 指定的文件不存在 ENOTDIR 参数path路径并非一目r录 ENOMEM 核心内存不足 ELOOP 参数path有过多符号连接问题。 EIO I/O 存取错误
范例:
/* 将/etc/passwd 文件权限设成S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH */
#include <sys/types.h>
#include <sys/stat.h>
main()
{
chmod("/etc/passwd", S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
}
chown
chown(改变文件的所有者)
相关函数:fchown,lchown,chmod
表头文件:#include <sys/types.h> #include <unistd.h>
定义函数:int chown(const char *path, uid_t owner, gid_t group);
函数说明:chown()会将参数path指定文件的所有者变更为参数owner代表的用户,而将该文件的组变更为参数group组。如果参数owner或group为-1,对应的所有者或组不会有所改变。root与文件所有者皆可改变文件组,但所有者必须是参数group组的成员。当root用chown()改变文件所有者或组时,该文件若具有S_ISUID或S_ISGID权限,则会清除此权限位,此外如果具有S_ISGID权限但不具S_IXGRP位,则该文件会被强制锁定,文件模式会保留。
返回值:成功则返回0,失败返回-1,错误原因存于errno。
错误代码:参考chmod()。
范例:
/* 将/etc/passwd 的所有者和组都设为root */
#include <sys/types.h>
#include <unistd.h>
main()
{
chown("/etc/passwd", 0, 0);
}
chroot
chroot(改变根目录)
相关函数:chdir
表头文件:#include <unistd.h>
定义函数:int chroot(const char *path);
函数说明:chroot()用来改变根目录为参数path所指定的目录。只有超级用户才允许改变根目录,子进程将继承新的根目录。
返回值:调用成功则返回0,失败则返-1,错误代码存于errno。
错误代码:EPERM 权限不足,无法改变根目录。 EFAULT 参数path指针超出可存取内存空间。 ENAMETOOLONG 参数path太长。 ENOTDIR 路径中的目录存在但却非真正的目录。 EACCESS 存取目录时被拒绝 ENOMEM 核心内存不足。 ELOOP 参数path有过多符号连接问题。 EIO I/O 存取错误。
范例:
/* 将根目录改为/tmp ,并将工作目录切换至/tmp */
#include <unistd.h>
main()
{
chroot("/tmp");
chdir("/");
}
closedir
closedir(关闭目录)
相关函数:opendir
表头文件:#include <sys/types.h> #include <dirent.h>
定义函数:int closedir(DIR *dir);
函数说明:closedir()关闭参数dir所指的目录流。
返回值:关闭成功则返回0,失败返回-1,错误原因存于errno中。
错误代码:EBADF 参数dir为无效的目录流
范例:参考readir()。
fchdir
fchdir(改变当前的工作目录)
相关函数:getcwd,chroot
表头文件:#include <unistd.h>
定义函数:int fchdir(int fd);
函数说明:fchdir()用来将当前的工作目录改变成以参数fd所指的文件描述词。
返回值:执行成功则返回0,失败返回-1,errno为错误代码。
附加说明:
范例:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
main()
{
int fd;
fd = open("/tmp", O_RDONLY);
fchdir(fd);
printf("current working directory : %s\n", getcwd(NULL, NULL));
close(fd);
}
执行: current working directory : /tmp
fchmod
fchmod(改变文件的权限)
相关函数:chmod,stat,open,chown
表头文件:#include <sys/types.h> #include <sys/stat.h>
定义函数:int fchmod(int fildes, mode_t mode);
函数说明:fchmod()会依参数mode权限来更改参数fildes所指文件的权限。参数fildes为已打开文件的文件描述词。参数mode请参考chmod()。
返回值:权限改变成功则返回0,失败返回-1,错误原因存于errno。 错误原因 EBADF 参数fildes为无效的文件描述词。 EPERM 进程的有效用户识别码与欲修改权限的文件所有者不同,而且也不具root权限。 EROFS 欲写入权限的文件存在于只读文件系统内。 EIO I/O 存取错误。
范例:
#include <sys/stat.h>
#include <fcntl.h>
main()
{
int fd;
fd = open("/etc/passwd", O_RDONLY);
fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
close(fd);
}
fchown
fchown(改变文件的所有者)
相关函数:chown,lchown,chmod
表头文件:#include <sys/types.h> #include <unistd.h>
定义函数:int fchown(int fd, uid_t owner, gid_t group);
函数说明:fchown()会将参数fd指定文件的所有者变更为参数owner代表的用户,而将该文件的组变更为参数group组。如果参数owner或group为-1,映的所有者或组有所改变。参数fd为已打开的文件描述词。当root用fchown()改变文件所有者或组时,该文件若具S_ISUID或S_ISGID权限,则会清除此权限位。
返回值:成功则返回0,失败则返回-1,错误原因存于errno。
错误代码:EBADF 参数fd文件描述词为无效的或该文件已关闭。 EPERM 进程的有效用户识别码与欲修改权限的文件所有者不同,而且也不具root权限,或是参数owner、group不正确。 EROFS 欲写入的文件存在于只读文件系统内。 ENOENT 指定的文件不存在 EIO I/O存取错误
范例:
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
main()
{
int fd;
fd = open("/etc/passwd", O_RDONLY);
chown(fd, 0, 0);
close(fd);
}
fstat
fstat(由文件描述词取得文件状态)
相关函数:stat,lstat,chmod,chown,readlink,utime
表头文件:#include <sys/stat.h> #include <unistd.h>
定义函数:int fstat(int fildes, struct stat *buf);
函数说明:fstat()用来将参数fildes所指的文件状态,复制到参数buf所指的结构中(struct stat)。Fstat()与stat()作用完全相同,不同处在传入的参数为已打开的文件描述词。详细内容请参考stat()。
返回值:执行成功则返回0,失败返回-1,错误代码存于errno。
范例:
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
main()
{
struct stat buf;
int fd;
fd = open("/etc/passwd", O_RDONLY);
fstat(fd, &buf);
printf("/etc/passwd file size +%d\n ", buf.st_size);
}
执行: /etc/passwd file size = 705
ftruncate
ftruncate(改变文件大小)
相关函数:open,truncate
表头文件:#include <unistd.h>
定义函数:int ftruncate(int fd, off_t length);
函数说明:ftruncate()会将参数fd指定的文件大小改为参数length指定的大小。参数fd为已打开的文件描述词,而且必须是以写入模式打开的文件。如果原来的文件大小比参数length大,则超过的部分会被删去。
返回值:执行成功则返回0,失败返回-1,错误原因存于errno。
错误代码:EBADF 参数fd文件描述词为无效的或该文件已关闭。 EINVAL 参数fd为一socket并非文件,或是该文件并非以写入模式打开。
getcwd
getcwd(取得当前的工作目录)
相关函数:get_current_dir_name,getwd,chdir
表头文件:#include <unistd.h>
定义函数:char *getcwd(char *buf, size_t size);
函数说明:getcwd()会将当前的工作目录绝对路径复制到参数buf所指的内存空间,参数size为buf的空间大小。在调用此函数时,buf所指的内存空间要足够大,若工作目录绝对路径的字符串长度超过参数size大小,则回值NULL,errno的值则为ERANGE。倘若参数buf为NULL,getcwd()会依参数size的大小自动配置内存(使用malloc()),如果参数size也为0,则getcwd()会依工作目录绝对路径的字符串程度来决定所配置的内存大小,进程可以在使用完此字符串后利用free()来释放此空间。
返回值:执行成功则将结果复制到参数buf所指的内存空间,或是返回自动配置的字符串指针。失败返回NULL,错误代码存于errno。
范例:
#include <unistd.h>
main()
{
char buf[80];
getcwd(buf, sizeof(buf));
printf("current working directory : %s\n", buf);
}
执行: current working directory :/tmp
link
link(建立文件连接)
相关函数:symlink,unlink
表头文件:#include <unistd.h>
定义函数:int link(const char *oldpath, const char *newpath);
函数说明:link()以参数newpath指定的名称来建立一个新的连接(硬连接)到参数oldpath所指定的已存在文件。如果参数newpath指定的名称为一已存在的文件则不会建立连接。
返回值:成功则返回0,失败返回-1,错误原因存于errno。
附加说明:link()所建立的硬连接无法跨越不同文件系统,如果需要请改用symlink()。
错误代码:EXDEV 参数oldpath与newpath不是建立在同一文件系统。 EPERM 参数oldpath与newpath所指的文件系统不支持硬连接 EROFS 文件存在于只读文件系统内 EFAULT 参数oldpath或newpath指针超出可存取内存空间。 ENAMETOLLONG 参数oldpath或newpath太长 ENOMEM 核心内存不足 EEXIST 参数newpath所指的文件名已存在。 EMLINK 参数oldpath所指的文件已达最大连接数目。 ELOOP 参数pathname有过多符号连接问题 ENOSPC 文件系统的剩余空间不足。 EIO I/O 存取错误。
范例:
/* 建立/etc/passwd 的硬连接为pass */
#include <unistd.h>
main()
{
link("/etc/passwd", "pass");
}
lstat
lstat(由文件描述词取得文件状态)
相关函数:stat,fstat,chmod,chown,readlink,utime
表头文件:#include <sys/stat.h> #include <unistd.h>
定义函数:int lstat(const char *file_name, struct stat *buf);
函数说明:lstat()与stat()作用完全相同,都是取得参数file_name所指的文件状态,其差别在于,当文件为符号连接时,lstat()会返回该link本身的状态。详细内容请参考stat()。
返回值:执行成功则返回0,失败返回-1,错误代码存于errno。
范例:参考stat()。
opendir
opendir(打开目录)
相关函数:open,readdir,closedir,rewinddir,seekdir,telldir,scandir
表头文件:#include <sys/types.h> #include <dirent.h>
定义函数:DIR *opendir(const char *name);
函数说明:opendir()用来打开参数name指定的目录,并返回DIR*形态的目录流,和open()类似,接下来对目录的读取和搜索都要使用此返回值。
返回值:成功则返回DIR*型态的目录流,打开失败则返回NULL。
错误代码:EACCESS 权限不足 EMFILE 已达到进程可同时打开的文件数上限。 ENFILE 已达到系统可同时打开的文件数上限。 ENOTDIR 参数name非真正的目录 ENOENT 参数name指定的目录不存在,或是参数name为一空字符串。 ENOMEM 核心内存不足。
readdir
readdir(读取目录)
相关函数:open,opendir,closedir,rewinddir,seekdir,telldir,scandir
表头文件:#include <sys/types.h> #include <dirent.h>
定义函数:struct dirent *readdir(DIR *dir);
函数说明:readdir()返回参数dir目录流的下个目录进入点。 结构dirent定义如下 struct dirent { ino_t d_ino; ff_t d_off; signed short int d_reclen; unsigned char d_type; har d_name[256; }; d_ino 此目录进入点的inode d_off 目录文件开头至此目录进入点的位移 d_reclen _name的长度,不包含NULL字符 d_type d_name所指的文件类型 d_name 文件名
返回值:成功则返回下个目录进入点。有错误发生或读取到目录文件尾则返回NULL。
附加说明:EBADF参数dir为无效的目录流。
范例:
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
main()
{
DIR *dir;
struct dirent *ptr;
int i;
dir = opendir("/etc/rc.d");
while ((ptr = readdir(dir)) != NULL)
{
printf("d_name: %s\n", ptr->d_name);
}
closedir(dir);
}
执行: d_name:.
d_name:..
d_name:init.d
d_name:rc0.d
d_name:rc1.d
d_name:rc2.d
d_name:rc3.d
d_name:rc4.d
d_name:rc5.d
d_name:rc6.d
d_name:rc
d_name:rc.local
d_name:rc.sysinit
readlink
readlink(取得符号连接所指的文件)
相关函数:stat,lstat,symlink
表头文件:#include <unistd.h>
定义函数:int readlink(const char *path, char *buf, size_t bufsiz);
函数说明:readlink()会将参数path的符号连接内容存到参数buf所指的内存空间,返回的内容不是以NULL作字符串结尾,但会将字符串的字符数返回。若参数bufsiz小于符号连接的内容长度,过长的内容会被截断。
返回值:执行成功则传符号连接所指的文件路径字符串,失败则返回-1,错误代码存于errno。
错误代码:EACCESS 取文件时被拒绝,权限不够 EINVAL 参数bufsiz为负数 EIO I/O 存取错误。 ELOOP 欲打开的文件有过多符号连接问题。 ENAMETOOLONG 参数path的路径名称太长 ENOENT 参数path所指定的文件不存在 ENOMEM 核心内存不足 ENOTDIR 参数path路径中的目录存在但却非真正的目录。
remove
remove(删除文件)
相关函数:link,rename,unlink
表头文件:#include <stdio.h>
定义函数:int remove(const char *pathname);
函数说明:remove()会删除参数pathname指定的文件。如果参数pathname为一文件,则调用unlink()处理,若参数pathname为一日录,则调用rmdir()来处理。请参考unlink()与rmdir()。
返回值:成功则返回0,失败则返回-1,错误原因存于errno。
错误代码:EROFS 欲写入的文件存在于只读文件系统内 EFAULT 参数pathname指针超出可存取内存空间 ENAMETOOLONG 参数pathname太长 ENOMEM 核心内存不足 ELOOP 参数pathname有过多符号连接问题 EIO I/O 存取错误。
rename
rename(更改文件名称或位置)
相关函数:link,unlink,symlink
表头文件:#include <stdio.h>
定义函数:int rename(const char *oldpath, const char *newpath);
函数说明:rename()会将参数oldpath所指定的文件名称改为参数newpath所指的文件名称。若newpath所指定的文件已存在,则会被删除。
返回值:执行成功则返回0,失败返回-1,错误原因存于errno
范例:
/* 设计一个DOS下的rename指令rename 旧文件名新文件名 */
#include <stdio.h>
void main(int argc, char **argv)
{
if (argc < 3)
{
printf("Usage: %s old_name new_name\n", argv[0]);
return;
}
printf("%s=>%s", argc[1], argv[2]);
if (rename(argv[1], argv[2])
< 0) printf("error!\n");
else printf("ok!\n");
}
rewinddir
rewinddir(重设读取目录的位置为开头位置)
相关函数:open,opendir,closedir,telldir,seekdir,readdir,scandir
表头文件:#include <sys/types.h> #include <dirent.h>
定义函数:void rewinddir(DIR *dir);
函数说明:rewinddir()用来设置参数dir目录流目前的读取位置为原来开头的读取位置。
返回值:
错误代码:EBADF dir为无效的目录流
范例:
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
main()
{
DIR *dir;
struct dirent *ptr;
dir = opendir("/etc/rc.d");
while ((ptr = readdir(dir)) != NULL)
{
printf("d_name :%s\n", ptr->d_name);
}
rewinddir(dir);
printf("readdir again!\n");
while ((ptr = readdir(dir)) != NULL)
{
printf("d_name: %s\n", ptr->d_name);
}
closedir(dir);
}
执行: d_name:.
d_name:..
d_name:init.d
d_name:rc0.d
d_name:rc1.d
d_name:rc2.d
d_name:rc3.d
d_name:rc4.d
d_name:rc5.d
d_name:rc6.d
d_name:rc
d_name:rc.local
d_name:rc.sysinit readdir again!
d_name:.
d_name:..
d_name:init.d
d_name:rc0.d
d_name:rc1.d
d_name:rc2.d
d_name:rc3.d
d_name:rc4.d
d_name:rc5.d
d_name:rc6.d
d_name:rc
d_name:rc.local
d_name:rc.sysinit
seekdir
seekdir(设置下回读取目录的位置)
相关函数:open,opendir,closedir,rewinddir,telldir,readdir,scandir
表头文件:#include <dirent.h>
定义函数:void seekdir(DIR *dir, off_t offset);
函数说明:seekdir()用来设置参数dir目录流目前的读取位置,在调用readdir()时便从此新位置开始读取。参数offset代表距离目录文件开头的偏移量。
返回值:
错误代码:EBADF 参数dir为无效的目录流
范例:
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
main()
{
DIR *dir;
struct dirent *ptr;
int offset, offset_5, i = 0;
dir = opendir("/etc/rc.d");
while ((ptr = readdir(dir)) != NULL)
{
offset = telldir(dir);
if (++i == 5)
offset_5 = offset;
printf("d_name :%s offset :%d\n", ptr->d_name, offset);
}
seekdir(dir, offset_5);
printf("Readdir again!\n");
while ((ptr = readdir(dir)) != NULL)
{
offset = telldir(dir);
printf("d_name :%s offset :%d\n", ptr->d_name, offset);
}
closedir(dir);
}
执行: d_name : . offset :12 d_name : ..
o
f
f
s
e
t:24 d_name : init.d offset 40 d_name : rc0.d offset :56 d_name :rc1.d offset :72
d_name:rc2.d offset :88
d_name:rc3.d offset 104
d_name:rc4.d offset:120
d_name:rc5.d offset:136
d_name:rc6.d offset:152
d_name:rc offset 164
d_name:rc.local offset :180
d_name:rc.sysinit offset :4096 readdir again!
d_name:rc2.d offset :88
d_name:rc3.d offset 104
d_name:rc4.d offset:120
d_name:rc5.d offset:136
d_name:rc6.d offset:152
d_name:rc offset 164
d_name:rc.local offset :180
d_name:rc.sysinit offset :4096
stat
stat(取得文件状态)
相关函数:fstat,lstat,chmod,chown,readlink,utime
表头文件:#include <sys/stat.h> #include <unistd.h>
定义函数:int stat(const char *file_name, struct stat *buf);
函数说明:stat()用来将参数file_name所指的文件状态,复制到参数buf所指的结构中。 下面是struct stat内各参数的说明 struct stat { dev_t st_dev; /* device / ino_t st_ino; / inode / 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 type / off_t st_size; / total size, in bytes / unsigned long st_blksize; / blocksize for filesystem I/O / unsigned long st_blocks; / number of 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 change */ }; st_dev 文件的设备编号 st_ino 文件的i-node st_mode 文件的类型和存取的权限 st_nlink 连到该文件的硬连接数目,刚建立的文件值为1。 st_uid 文件所有者的用户识别码 st_gid 文件所有者的组识别码 st_rdev 若此文件为装置设备文件,则为其设备编号 st_size 文件大小,以字节计算 st_blksize 文件系统的I/O 缓冲区大小。 st_blcoks 占用文件区块的个数,每一区块大小为512个字节。 st_atime 文件最近一次被存取或被执行的时间,一般只有在用mknod、utime、read、write与tructate时改变。 st_mtime 文件最后一次被修改的时间,一般只有在用mknod、utime和write时才会改变 st_ctime i-node最近一次被更改的时间,此参数会在文件所有者、组、权限被更改时更新先前所描述的st_mode则定义了下列数种情况 S_IFMT 0170000 文件类型的位遮罩 S_IFSOCK 0140000 scoket S_IFLNK 0120000 符号连接 S_IFREG 0100000 一般文件 S_IFBLK 0060000 区块装置 S_IFDIR 0040000 目录 S_IFCHR 0020000 字符装置 S_IFIFO 0010000 先进先出 S_ISUID 04000 文件的(set user-id on execution)位 S_ISGID 02000 文件的(set group-id on execution)位 S_ISVTX 01000 文件的sticky位 S_IRUSR(S_IREAD) 00400 文件所有者具可读取权限 S_IWUSR(S_IWRITE)00200 文件所有者具可写入权限 S_IXUSR(S_IEXEC) 00100 文件所有者具可执行权限 S_IRGRP 00040 用户组具可读取权限 S_IWGRP 00020 用户组具可写入权限 S_IXGRP 00010 用户组具可执行权限 S_IROTH 00004 其他用户具可读取权限 S_IWOTH 00002 其他用户具可写入权限 S_IXOTH 00001 其他用户具可执行权限 上述的文件类型在POSIX中定义了检查这些类型的宏定义 S_ISLNK(st_mode) 判断是否为符号连接 S_ISREG(st_mode) 是否为一般文件 S_ISDIR(st_mode) 是否为目录 S_ISCHR(st_mode) 是否为字符装置文件 S_ISBLK(st_mode) 是否为区块装置 S_ISFIFO(st_mode) 是否为先进先出 S_ISSOCK(st_mode) 是否为socket 若一目r录具有sticky位(S_ISVTX),则表示在此目录下的文件只能被该文件所有者、此目录所有者或root来删除或改名。
返回值:执行成功则返回0,失败返回-1,错误代码存于errno
错误代码:ENOENT 参数file_name指定的文件不存在 ENOTDIR 路径中的目录存在但却非真正的目录 ELOOP 欲打开的文件有过多符号连接问题,上限为16符号连接 EFAULT 参数buf为无效指针,指向无法存在的内存空间 EACCESS 存取文件时被拒绝 ENOMEM 核心内存不足 ENAMETOOLONG 参数file_name的路径名称太长
范例:
#include <sys/stat.h>
#include <unistd.h>
main()
{
struct stat buf;
stat("/etc/passwd", &buf);
printf("/etc/passwd file size = %d\n", buf.st_size);
}
执行: /etc/passwd file size = 705
symlink
symlink(建立文件符号连接)
相关函数:link,unlink
表头文件:#include <unistd.h>
定义函数:int symlink(const char *oldpath, const char *newpath);
函数说明:symlink()以参数newpath指定的名称来建立一个新的连接(符号连接)到参数oldpath所指定的已存在文件。参数oldpath指定的文件不一定要存在,如果参数newpath指定的名称为一已存在的文件则不会建立连接。
返回值:成功则返回0,失败返回-1,错误原因存于errno。
错误代码:EPERM 参数oldpath与newpath所指的文件系统不支持符号连接 EROFS 欲测试写入权限的文件存在于只读文件系统内 EFAULT 参数oldpath或newpath指针超出可存取内存空间。 ENAMETOOLONG 参数oldpath或newpath太长 ENOMEM 核心内存不足 EEXIST 参数newpath所指的文件名已存在。 EMLINK 参数oldpath所指的文件已达到最大连接数目 ELOOP 参数pathname有过多符号连接问题 ENOSPC 文件系统的剩余空间不足 EIO I/O 存取错误
范例:
#include <unistd.h>
main()
{
symlink("/etc/passwd", "pass");
}
telldir
telldir(取得目录流的读取位置)
相关函数:open,opendir,closedir,rewinddir,seekdir,readdir,scandir
表头文件:#include <dirent.h>
定义函数:off_t telldir(DIR *dir);
函数说明:telldir()返回参数dir目录流目前的读取位置。此返回值代表距离目录文件开头的偏移量返回值返回下个读取位置,有错误发生时返回-1。
错误代码:EBADF参数dir为无效的目录流。
范例:
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
main()
{
DIR *dir;
struct dirent *ptr;
int offset;
dir = opendir("/etc/rc.d");
while ((ptr = readdir(dir)) != NULL)
{
offset = telldir(dir);
printf("d_name : %s offset :%d\n", ptr->d_name, offset);
}
closedir(dir);
}
执行: d_name : . offset :12 d_name : ..
o
f
f
s
e
t:24 d_name : init.d offset 40 d_name : rc0.d offset :56 d_name :rc1.d offset :72
d_name:rc2.d offset :88
d_name:rc3.d offset 104
d_name:rc4.d offset:120
d_name:rc5.d offset:136
d_name:rc6.d offset:152
d_name:rc offset 164
d_name:rc.local offset :180
d_name:rc.sysinit offset :4096
truncate
truncate(改变文件大小)
相关函数:open,ftruncate
表头文件:#include <unistd.h>
定义函数:int truncate(const char *path, off_t length);
函数说明:truncate()会将参数path指定的文件大小改为参数length指定的大小。如果原来的文件大小比参数length大,则超过的部分会被删去。
返回值:执行成功则返回0,失败返回-1,错误原因存于errno。
错误代码:EACCESS 参数path所指定的文件无法存取。 EROFS 欲写入的文件存在于只读文件系统内 EFAULT 参数path指针超出可存取内存空间 EINVAL 参数path包含不合法字符 ENAMETOOLONG 参数path太长 ENOTDIR 参数path路径并非一目r录 EISDIR 参数path指向一目r录 ETXTBUSY 参数path所指的文件为共享程序,而且正被执行中 ELOOP 参数path有过多符号连接问题 EIO I/O 存取错误。
umask
umask(设置建立新文件时的权限遮罩)
相关函数:creat,open
表头文件:#include <sys/types.h> #include <sys/stat.h>
定义函数:mode_t umask(mode_t mask);
函数说明:umask()会将系统umask值设成参数mask&0777后的值,然后将先前的umask值返回。在使用open()建立新文件时,该参数mode并非真正建立文件的权限,而是(mode&~umask)的权限值。例如,在建立文件时指定文件权限为0666,通常umask值默认为022,则该文件的真正权限则为0666&~022=0644,也就是rw-r--r--返回值此调用不会有错误值返回。返回值为原先系统的umask值。
unlink
unlink(删除文件)
相关函数:link,rename,remove
表头文件:#include <unistd.h>
定义函数:int unlink(const char *pathname);
函数说明:unlink()会删除参数pathname指定的文件。如果该文件名为最后连接点,但有其他进程打开了此文件,则在所有关于此文件的文件描述词皆关闭后才会删除。如果参数pathname为一符号连接,则此连接会被删除。
返回值:成功则返回0,失败返回-1,错误原因存于errno
错误代码:EROFS 文件存在于只读文件系统内 EFAULT 参数pathname指针超出可存取内存空间 ENAMETOOLONG 参数pathname太长 ENOMEM 核心内存不足 ELOOP 参数pathname有过多符号连接问题 EIO I/O 存取错误
utime
utime(修改文件的存取时间和更改时间)
相关函数:utimes,stat
表头文件:#include <sys/types.h> #include <utime.h>
定义函数:int utime(const char *filename, struct utimbuf *buf);
函数说明:utime()用来修改参数filename文件所属的inode存取时间。 结构utimbuf定义如下 struct utimbuf { time_t actime; time_t modtime; };
返回值:如果参数buf为空指针(NULL),则该文件的存取时间和更改时间全部会设为目前时间。 执行成功则返回0,失败返回-1,错误代码存于errno。
错误代码:EACCESS 存取文件时被拒绝,权限不足 ENOENT 指定的文件不存在。
utimes
utimes(修改文件的存取时间和更改时间)
相关函数:utime,stat
表头文件:#include <sys/types.h> #include <utime.h>
定义函数:int utimes(char *filename, struct timeval *tvp);
函数说明:utimes()用来修改参数filename文件所属的inode存取时间和修改时间。 结构timeval定义如下 struct timeval { long tv_sec; long tv_usec; /* 微妙 */ };
返回值:参数tvp指向两个timeval结构空间,和utime()使用的utimebuf结构比较,tvp[0].tc_sec则为utimbuf.actime,tvp[1].tv_sec为utimbuf.modtime。 执行成功则返回0。失败返回-1,错误代码存于errno。
错误代码:EACCESS 存取文件时被拒绝,权限不足 ENOENT 指定的文件不存在
信号处理篇 13
TODO
alarm
alarm(设置信号传送闹钟)
相关函数:signal,sleep
表头文件:#include <unistd.h>
定义函数:unsigned int alarm(unsigned int seconds);
函数说明:alarm()用来设置信号SIGALRM在经过参数seconds指定的秒数后传送给目前的进程。如果参数seconds为0,则之前设置的闹钟会被取消,并将剩下的时间返回。
返回值:返回之前闹钟的剩余秒数,如果之前未设闹钟则返回0。
范例:
#include <unistd.h>
#include <signal.h>
void handler()
{
printf("hello\n");
}
main()
{
int i;
signal(SIGALRM, handler);
alarm(5);
for (i = 1; i < 7; i++)
{
printf("sleep %d ...\n", i);
sleep(1);
}
}
执行: sleep
1
...
sleep
2
...
sleep
3
...
sleep
4
...
sleep
5
...
hello
sleep
6
...
kill
kill(传送信号给指定的进程)
相关函数:raise,signal
表头文件:#include <sys/types.h> #include <signal.h>
定义函数:int kill(pid_t pid, int sig);
函数说明:kill()可以用来送参数sig指定的信号给参数pid指定的进程。参数pid有几种情况: pid>0 将信号传给进程识别码为pid的进程。 pid=0 将信号传给和目前进程相同进程组的所有进程 pid=-1 将信号广播传送给系统内所有的进程 pid<0 将信号传给进程组识别码为pid绝对值的所有进程 参数sig代表的信号编号可参考附录D
返回值:执行成功则返回0,如果有错误则返回-1。
错误代码:EINVAL 参数sig不合法 ESRCH 参数pid所指定的进程或进程组不存在 EPERM 权限不够无法传送信号给指定进程
范例:
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
main()
{
pid_t pid;
int status;
if (!(pid = fork()))
{
printf("Hi I am child process!\n");
sleep(10);
return;
}
else
{
printf("send signal to child process (%d) \n", pid);
sleep(1);
kill(pid, SIGABRT);
wait(&status);
if (WIFSIGNALED(status)) printf("chile process receive signal %d\n", WTERMSIG(status));
}
}
执行: sen signal to child process(3170) Hi I am child process! child process receive signal 6
pause
pause(让进程暂停直到信号出现)
相关函数:kill,signal,sleep
表头文件:#include <unistd.h>
定义函数:int pause(void);
函数说明:pause()会令目前的进程暂停(进入睡眠状态),直到被信号(signal)所中断。
返回值:只返回-1。
错误代码:EINTR 有信号到达中断了此函数。
sigaction
sigaction(查询或设置信号处理方式)
相关函数:signal,sigprocmask,sigpending,sigsuspend
表头文件:#include <signal.h>
定义函数:int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
函数说明:sigaction()会依参数signum指定的信号编号来设置该信号的处理函数。参数signum可以指定SIGKILL和SIGSTOP以外的所有信号。 如参数结构sigaction定义如下 struct sigaction { void (*sa_handler)(int); sigset_t sa_mask; int sa_flags; void (*sa_restorer)(void); } sa_handler此参数和signal()的参数handler相同,代表新的信号处理函数,其他意义请参考signal()。 sa_mask用来设置在处理该信号时暂时将sa_mask指定的信号搁置。 sa_restorer此参数没有使用。 sa_flags用来设置信号处理的其他相关操作,下列的数值可用。 OR运算(|)组合 A_NOCLDSTOP : 如果参数signum为SIGCHLD,则当子进程暂停时并不会通知父进程 SA_ONESHOT/SA_RESETHAND:当调用新的信号处理函数前,将此信号处理方式改为系统预设的方式。 SA_RESTART:被信号中断的系统调用会自行重启 SA_NOMASK/SA_NODEFER:在处理此信号未结束前不理会此信号的再次到来。 如果参数oldact不是NULL指针,则原来的信号处理方式会由此结构sigaction返回。
返回值:执行成功则返回0,如果有错误则返回-1。
错误代码:EINVAL 参数signum不合法,或是企图拦截SIGKILL/SIGSTOPSIGKILL信号 EFAULT 参数act,oldact指针地址无法存取。 EINTR 此调用被中断
范例:
#include <unistd.h>
#include <signal.h>
void show_handler(struct sigaction *act)
{
switch (act->sa_flags)
{
case SIG_DFL:
printf("Default action\n");
break;
case SIG_IGN:
printf("Ignore the signal\n");
break;
default:
printf("0x%x\n", act->sa_handler);
}
}
main()
{
int i;
struct sigaction act, oldact;
act.sa_handler = show_handler;
act.sa_flags = SA_ONESHOT|SA_NOMASK;
sigaction(SIGUSR1, &act, &oldact);
for (i = 5; i < 15; i++)
{
printf("sa_handler of signal %2d =", i);
sigaction(i, NULL, &oldact);
}
}
执行: sa_handler of signal 5 = Default action
sa_handler of signal 6 = Default action
sa_handler of signal 7 = Default action
sa_handler of signal 8 = Default action
sa_handler of signal 9 = Default action
sa_handler of signal 10 = 0x8048400
sa_handler of signal 11 = Default action
sa_handler of signal 12 = Default action
sa_handler of signal 13 = Default action
sa_handler of signal 14 = Default action
sigaddset
sigaddset(增加一个信号至信号集)
相关函数:sigemptyset,sigfillset,sigdelset,sigismember
表头文件:#include <signal.h>
定义函数:int sigaddset(sigset_t *set, int signum);
函数说明:sigaddset()用来将参数signum代表的信号加入至参数set信号集里。
返回值:执行成功则返回0,如果有错误则返回-1。
错误代码:EFAULT 参数set指针地址无法存取 EINVAL 参数signum非合法的信号编号
sigdelset
sigdelset(从信号集里删除一个信号)
相关函数:sigemptyset,sigfillset,sigaddset,sigismember
表头文件:#include <signal.h>
定义函数:int sigdelset(sigset_t *set, int signum);
函数说明:sigdelset()用来将参数signum代表的信号从参数set信号集里删除。
返回值:执行成功则返回0,如果有错误则返回-1。
错误代码:EFAULT 参数set指针地址无法存取 EINVAL 参数signum非合法的信号编号
sigemptyset
sigemptyset(初始化信号集)
相关函数:sigaddset,sigfillset,sigdelset,sigismember
表头文件:#include <signal.h>
定义函数:int sigemptyset(sigset_t *set);
函数说明:sigemptyset()用来将参数set信号集初始化并清空。
返回值:执行成功则返回0,如果有错误则返回-1。
错误代码:EFAULT 参数set指针地址无法存取
sigfillset
sigfillset(将所有信号加入至信号集)
相关函数:sigempty,sigaddset,sigdelset,sigismember
表头文件:#include <signal.h>
定义函数:int sigfillset(sigset_t *set);
函数说明:sigfillset()用来将参数set信号集初始化,然后把所有的信号加入到此信号集里。
返回值:执行成功则返回0,如果有错误则返回-1。
附加说明:EFAULT 参数set指针地址无法存取
sigismember
sigismember(测试某个信号是否已加入至信号集里)
相关函数:sigemptyset,sigfillset,sigaddset,sigdelset
表头文件:#include <signal.h>
定义函数:int sigismember(const sigset_t *set, int signum);
函数说明:sigismember()用来测试参数signum代表的信号是否已加入至参数set信号集里。如果信号集里已有该信号则返回1,否则返回0。
返回值:信号集已有该信号则返回1,没有则返回0。如果有错误则返回-1。
错误代码:EFAULT 参数set指针地址无法存取 EINVAL 参数signum非合法的信号编号
signal
signal(设置信号处理方式)
相关函数:sigaction,kill,raise
表头文件:#include <signal.h>
定义函数:void (*signal(int signum, void(*handler)(int)))(int);
函数说明:signal()会依参数signum指定的信号编号来设置该信号的处理函数。当指定的信号到达时就会跳转到参数handler指定的函数执行。如果参数handler不是函数指针,则必须是下列两个常数之一: SIG_IGN 忽略参数signum指定的信号。 SIG_DFL 将参数signum指定的信号重设为核心预设的信号处理方式。 关于信号的编号和说明,请参考附录D
返回值:返回先前的信号处理函数指针,如果有错误则返回SIG_ERR(-1)。
附加说明:在信号发生跳转到自定的handler处理函数执行后,系统会自动将此处理函数换回原来系统预设的处理方式,如果要改变此操作请改用sigaction()。
范例:参考alarm()或raise()。
sigpending
sigpending(查询被搁置的信号)
相关函数:signal,sigaction,sigprocmask,sigsuspend
表头文件:#include <signal.h>
定义函数:int sigpending(sigset_t *set);
函数说明:sigpending()会将被搁置的信号集合由参数set指针返回。
返回值:执行成功则返回0,如果有错误则返回-1。
错误代码:EFAULT 参数set指针地址无法存取 EINTR 此调用被中断。
sigprocmask
sigprocmask(查询或设置信号遮罩)
相关函数:signal,sigaction,sigpending,sigsuspend
表头文件:#include <signal.h>
定义函数:int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
函数说明:sigprocmask()可以用来改变目前的信号遮罩,其操作依参数how来决定 SIG_BLOCK 新的信号遮罩由目前的信号遮罩和参数set指定的信号遮罩作联集 SIG_UNBLOCK 将目前的信号遮罩删除掉参数set指定的信号遮罩 SIG_SETMASK 将目前的信号遮罩设成参数set指定的信号遮罩。 如果参数oldset不是NULL指针,那么目前的信号遮罩会由此指针返回。
返回值:执行成功则返回0,如果有错误则返回-1。
错误代码:EFAULT 参数set,oldset指针地址无法存取。 EINTR 此调用被中断
sleep
sleep(让进程暂停执行一段时间)
相关函数:signal,alarm
表头文件:#include <unistd.h>
定义函数:unsigned int sleep(unsigned int seconds);
函数说明:sleep()会令目前的进程暂停,直到达到参数seconds所指定的时间,或是被信号所中断。
返回值:若进程暂停到参数seconds所指定的时间则返回0,若有信号中断则返回剩余秒数。
ferror
ferror(检查文件流是否有错误发生)
相关函数:clearerr,perror
表头文件:#include <stdio.h>
定义函数:int ferror(FILE *stream);
函数说明:ferror()用来检查参数stream所指定的文件流是否发生了错误情况,如有错误发生则返回非0值。
返回值:如果文件流有错误发生则返回非0值。
perror
perror(打印出错误原因信息字符串)
相关函数:strerror
表头文件:#include <stdio.h>
定义函数:void perror(const char *s);
函数说明:perror()用来将上一个函数发生错误的原因输出到标准错误(stderr)。参数s所指的字符串会先打印出,后面再加上错误原因字符串。此错误原因依照全局变量errno的值来决定要输出的字符串。
返回值:
范例:
#include <stdio.h>
main()
{
FILE *fp;
fp = fopen("/tmp/noexist", "r+");
if (fp == NULL)
perror("fopen");
}
执行: $ ./perror fopen : No such file or diretory
strerror
strerror(返回错误原因的描述字符串)
相关函数:perror
表头文件:#include <string.h>
定义函数:char *strerror(int errnum);
函数说明:strerror()用来依参数errnum的错误代码来查询其错误原因的描述字符串,然后将该字符串指针返回。
返回值:返回描述错误原因的字符串指针。
范例:
/* 显示错误代码0至9的错误原因描述 */
#include <string.h>
main()
{
int i;
for (i = 0; i < 10; i++) printf("%d : %s\n", i, strerror(i));
}
执行: 0 : Success
1 : Operation not permitted
2 : No such file or directory
3 : No such process
4 : Interrupted system call
5 : Input/output error
6 : Device not configured
7 : Argument list too long
8 : Exec format error
9 : Bad file descriptor
mkfifo
mkfifo(建立具名管道)
相关函数:pipe,popen,open,umask
表头文件:#include <sys/types.h> #include <sys/stat.h>
定义函数:int mkfifo(const char *pathname, mode_t mode);
函数说明:mkfifo()会依参数pathname建立特殊的FIFO文件,该文件必须不存在,而参数mode为该文件的权限(mode%~umask),因此umask值也会影响到FIFO文件的权限。Mkfifo()建立的FIFO文件其他进程都可以用读写一般文件的方式存取。当使用open()来打开FIFO文件时,O_NONBLOCK旗标会有影响 1、当使用O_NONBLOCK旗标时,打开FIFO文件来读取的操作会立刻返回,但是若还没有其他进程打开FIFO文件来读取,则写入的操作会返回ENXIO错误代码。 2、没有使用O_NONBLOCK旗标时,打开FIFO来读取的操作会等到其他进程打开FIFO文件来写入才正常返回。同样地,打开FIFO文件来写入的操作会等到其他进程打开FIFO文件来读取后才正常返回。
返回值:若成功则返回0,否则返回-1,错误原因存于errno中。
错误代码:EACCESS 参数pathname所指定的目录路径无可执行的权限 EEXIST 参数pathname所指定的文件已存在。 ENAMETOOLONG 参数pathname的路径名称太长。 ENOENT 参数pathname包含的目录不存在 ENOSPC 文件系统的剩余空间不足 ENOTDIR 参数pathname路径中的目录存在但却非真正的目录。 EROFS 参数pathname指定的文件存在于只读文件系统内。
范例:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
main()
{
char buffer[80];
int fd;
unlink(FIFO);
mkfifo(FIFO, 0666);
if (fork() > 0)
{
char s[] = "hello!\n";
fd = open(FIFO, O_WRONLY);
write(fd, s, sizeof(s));
close(fd);
}
else
{
fd = open(FIFO, O_RDONLY);
read(fd, buffer, 80);
printf("%s", buffer);
close(fd);
}
}
执行: hello!
pclose
pclose(关闭管道I/O)
相关函数:popen
表头文件:#include <stdio.h>
定义函数:int pclose(FILE *stream);
函数说明:pclose()用来关闭由popen所建立的管道及文件指针。参数stream为先前由popen()所返回的文件指针。
返回值:返回子进程的结束状态。如果有错误则返回-1,错误原因存于errno中。
错误代码:ECHILD pclose()无法取得子进程的结束状态。
范例:参考popen()。
pipe
pipe(建立管道)
相关函数:mkfifo,popen,read,write,fork
表头文件:#include <unistd.h>
定义函数:int pipe(int filedes[2]);
函数说明:pipe()会建立管道,并将文件描述词由参数filedes数组返回。filedes[0]为管道里的读取端,filedes[1]则为管道的写入端。
返回值:若成功则返回零,否则返回-1,错误原因存于errno中。
错误代码:EMFILE 进程已用完文件描述词最大量。 ENFILE 系统已无文件描述词可用。 EFAULT 参数filedes数组地址不合法。
范例:
/* 父进程借管道将字符串"hello!\n"传给子进程并显示 */
#include <unistd.h>
main()
{
int filedes[2];
char buffer[80];
pipe(filedes);
if (fork() > 0)
{
/* 父进程 */
char s[] = "hello!\n";
write(filedes[1], s, sizeof(s));
}
else
{
/* 子进程 */
read(filedes[0], buffer, 80);
printf("%s", buffer);
}
}
执行: hello!
popen
popen(建立管道I/O)
相关函数:pipe,mkfifo,pclose,fork,system,fopen
表头文件:#include <stdio.h>
定义函数:FILE *popen(const char *command, const char *type);
函数说明:popen()会调用fork()产生子进程,然后从子进程中调用/bin/sh -c来执行参数command的指令。参数type可使用"r"代表读取,"w"代表写入。依照此type值,popen()会建立管道连到子进程的标准输出设备或标准输入设备,然后返回一个文件指针。随后进程便可利用此文件指针来读取子进程的输出设备或是写入到子进程的标准输入设备中。此外,所有使用文件指针(FILE *)操作的函数也都可以使用,除了fclose()以外。
返回值:若成功则返回文件指针,否则返回NULL,错误原因存于errno中。
错误代码:EINVAL参数type不合法。 注意事项 在编写具SUID/SGID权限的程序时请尽量避免使用popen(),popen()会继承环境变量,通过环境变量可能会造成系统安全的问题。
范例:
#include <stdio.h>
main()
{
FILE *fp;
char buffer[80];
fp = popen("cat /etc/passwd", "r");
fgets(buffer, sizeof(buffer), fp);
printf("%s", buffer);
pclose(fp);
}
执行: root :
x:0 0: root: /root: /bin/bash
接口处理篇 14
TODO
accept
accept(接受socket连线)
相关函数:socket,bind,listen,connect
表头文件:#include <sys/types.h> #include <sys/socket.h>
定义函数:int accept(int s, struct sockaddr *addr, int *addrlen);
函数说明:accept()用来接受参数s的socket连线。参数s的socket必需先经bind()、listen()函数处理过,当有连线进来时accept()会返回一个新的socket处理代码,往后的数据传送与读取就是经由新的socket处理,而原来参数s的socket能继续使用accept()来接受新的连线要求。连线成功时,参数addr所指的结构会被系统填入远程主机的地址数据,参数addrlen为scokaddr的结构长度。关于结构sockaddr的定义请参考bind()。
返回值:成功则返回新的socket处理代码,失败返回-1,错误原因存于errno中。
错误代码:EBADF 参数s非合法socket处理代码。 EFAULT 参数addr指针指向无法存取的内存空间。 ENOTSOCK 参数s为一文件描述词,非socket。 EOPNOTSUPP 指定的socket并非SOCK_STREAM。 EPERM 防火墙拒绝此连线。 ENOBUFS 系统的缓冲内存不足。 ENOMEM 核心内存不足。
范例:参考listen()。
bind
bind(对socket定位)
相关函数:socket,accept,connect,listen
表头文件:#include <sys/types.h> #include <sys/socket.h>
定义函数:int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
函数说明:bind()用来设置给参数sockfd的socket一个名称。此名称由参数my_addr指向一sockaddr结构,对于不同的socket domain定义了一个通用的数据结构 struct sockaddr { unsigned short int sa_family; char sa_data[14]; }; sa_family为调用socket()时的domain参数,即AF_xxxx值。 sa_data最多使用14个字符长度。 此sockaddr结构会因使用不同的socket domain而有不同结构定义,例如使用AF_INET domain,其socketaddr结构定义便为 struct socketaddr_in { unsigned short int sin_family; uint16_t sin_port; struct in_addr sin_addr; unsigned char sin_zero[8]; }; struct in_addr { uint32_t s_addr; }; sin_family即为sa_family sin_port为使用的port编号 sin_addr.s_addr为IP地址 sin_zero未使用。 参数 addrlen为sockaddr的结构长度。
返回值:成功则返回0,失败返回-1,错误原因存于errno中。
错误代码:EBADF 参数sockfd非合法socket处理代码。 EACCESS 权限不足 ENOTSOCK 参数sockfd为一文件描述词,非socket。
范例:参考listen()
connect
connect(建立socket连线)
相关函数:socket,bind,listen
表头文件:#include <sys/types.h> #include <sys/socket.h>
定义函数:int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
函数说明:connect()用来将参数sockfd的socket连至参数serv_addr指定的网络地址。结构sockaddr请参考bind()。参数addrlen为sockaddr的结构长度。
返回值:成功则返回0,失败返回-1,错误原因存于errno中。
错误代码:EBADF 参数sockfd非合法socket处理代码 EFAULT 参数serv_addr指针指向无法存取的内存空间 ENOTSOCK 参数sockfd为一文件描述词,非socket。 EISCONN 参数sockfd的socket已是连线状态 ECONNREFUSED 连线要求被server端拒绝。 ETIMEDOUT 企图连线的操作超过限定时间仍未有响应。 ENETUNREACH 无法传送数据包至指定的主机。 EAFNOSUPPORT sockaddr结构的sa_family不正确。 EALREADY socket为不可阻断且先前的连线操作还未完成。
范例:
/* 利用socket的TCP client 此程序会连线TCP server,并将键盘输入的字符串传送给server。 TCP server范例请参考listen()。 */
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 1234 #define SERVER_IP "127.0.0.1"
main()
{
int s;
struct sockaddr_in addr;
char buffer[256];
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket");
exit(1);
}
/* 填写sockaddr_in结构 */
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = inet_addr(SERVER_IP);
/* 尝试连线 */
if (connect(s, &addr, sizeof(addr)) < 0)
{
perror("connect");
exit(1);
}
/* 接收由server端传来的信息 */
recv(s, buffer, sizeof(buffer), 0);
printf("%s\n", buffer);
while (1)
{
bzero(buffer, sizeof(buffer));
/* 从标准输入设备取得字符串 */
read(STDIN_FILENO, buffer, sizeof(buffer));
/* 将字符串传给server端 */
if (send(s, buffer, sizeof(buffer), 0) < 0)
{
perror("send");
exit(1);
}
}
}
执行: $./connect
Welcome to server!
hi I am client!
/* 键盘输入 */
/* <Ctrl+C> 中断程序 */
endprotoent
endprotoent(结束网络协议数据的读取)
相关函数:getprotoent,getprotobyname,getprotobynumber,setprotoent
表头文件:#include <netdb.h>
定义函数:void endprotoent(void);
函数说明:endprotoent()用来关闭由getprotoent()打开的文件。
返回值:
范例:参考getprotoent()
endservent
endservent(结束网络服务数据的读取)
相关函数:getservent,getservbyname,getservbyport,setservent
表头文件:#include <netdb.h>
定义函数:void endservent(void);
函数说明:endservent()用来关闭由getservent()所打开的文件。
返回值:
范例:参考getservent()。
getsockopt
getsockopt(取得socket状态)
相关函数:setsockopt
表头文件:#include <sys/types.h> #include <sys/socket.h>
定义函数:int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen);
函数说明:getsockopt()会将参数s所指定的socket状态返回。参数optname代表欲取得何种选项状态,而参数optval则指向欲保存结果的内存地址,参数optlen则为该空间的大小。参数level、optname请参考setsockopt()。
返回值:成功则返回0,若有错误则返回-1,错误原因存于errno
错误代码:EBADF 参数s并非合法的socket处理代码 ENOTSOCK 参数s为一文件描述词,非socket ENOPROTOOPT 参数optname指定的选项不正确 EFAULT 参数optval指针指向无法存取的内存空间
范例:
#include <sys/types.h>
#include <sys/socket.h>
main()
{
int s, optval, optlen = sizeof(int);
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) perror("socket");
getsockopt(s, SOL_SOCKET, SO_TYPE, &optval, &optlen);
printf("optval = %d\n", optval);
close(s);
}
执行: optval = 1 /SOCK_STREAM的定义正是此值/
htonl
htonl(将32位主机字符顺序转换成网络字符顺序)
相关函数:htons,ntohl,ntohs
表头文件:#include <netinet/in.h>
定义函数:unsigned long int htonl(unsigned long int hostlong);
函数说明:htonl()用来将参数指定的32位hostlong转换成网络字符顺序。
返回值:返回对应的网络字符顺序。
范例:参考getservbyport()或connect()。
htons
htons(将16位主机字符顺序转换成网络字符顺序)
相关函数:htonl,ntohl,ntohs
表头文件:#include <netinet/in.h>
定义函数:unsigned short int htons(unsigned short int hostshort);
函数说明:htons()用来将参数指定的16位hostshort转换成网络字符顺序。
返回值:返回对应的网络字符顺序。
范例:参考connect()。
inet_addr
inet_addr(将网络地址转成二进制的数字)
相关函数:inet_aton,inet_ntoa
表头文件:#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>
定义函数:unsigned long int inet_addr(const char *cp);
函数说明:inet_addr()用来将参数cp所指的网络地址字符串转换成网络所使用的二进制数字。网络地址字符串是以数字和点组成的字符串,例如:"163.13.132.68"。
返回值:成功则返回对应的网络二进制的数字,失败返回-1。
inet_aton
inet_aton(将网络地址转成网络二进制的数字)
相关函数:inet_addr,inet_ntoa
表头文件:#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>
定义函数:int inet_aton(const char *cp, struct in_addr *inp);
函数说明:inet_aton()用来将参数cp所指的网络地址字符串转换成网络使用的二进制的数字,然后存于参数inp所指的in_addr结构中。 结构in_addr定义如下 struct in_addr { unsigned long int s_addr; };
返回值:成功则返回非0值,失败则返回0。
inet_ntoa
inet_ntoa(将网络二进制的数字转换成网络地址)
相关函数:inet_addr,inet_aton
表头文件:#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>
定义函数:char *inet_ntoa(struct in_addr in);
函数说明:inet_ntoa()用来将参数in所指的网络二进制的数字转换成网络地址,然后将指向此网络地址字符串的指针返回。
返回值:成功则返回字符串指针,失败则返回NULL。
listen
listen(等待连接)
相关函数:socket,bind,accept,connect
表头文件:#include <sys/socket.h>
定义函数:int listen(int s, int backlog);
函数说明:listen()用来等待参数s的socket连线。参数backlog指定同时能处理的最大连接要求,如果连接数目达此上限则client端将收到ECONNREFUSED的错误。Listen()并未开始接收连线,只是设置socket为listen模式,真正接收client端连线的是accept()。通常listen()会在socket(),bind()之后调用,接着才调用accept()。
返回值:成功则返回0,失败返回-1,错误原因存于errno
附加说明:listen()只适用SOCK_STREAM或SOCK_SEQPACKET的socket类型。如果socket为AF_INET则参数backlog最大值可设至128。
错误代码:EBADF 参数sockfd非合法socket处理代码 EACCESS 权限不足 EOPNOTSUPP 指定的socket并未支援listen模式。
范例:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define PORT 1234 #define MAXSOCKFD 10
main()
{
int sockfd, newsockfd, is_connected[MAXSOCKFD], fd;
struct sockaddr_in addr;
int addr_len = sizeof(
struct sockaddr_in); fd_set readfds; char buffer[256]; char msg[] = "Welcome to server!"; if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket");
exit(1);
}
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sockfd, &addr, sizeof(addr)) < 0)
{
perror("connect");
exit(1);
}
if (listen(sockfd, 3) < 0)
{
perror("listen");
exit(1);
}
for (fd = 0; fd < MAXSOCKFD; fd++) is_connected[fd] = 0; while (1)
{
FD_ZERO(&readfds);
FD_SET(sockfd, &readfds);
for (fd = 0; fd < MAXSOCKFD; fd++) if (is_connected[fd]) FD_SET(fd, &readfds); if (!select(MAXSOCKFD, &readfds, NULL, NULL, NULL)) continue; for (fd = 0; fd < MAXSOCKFD; fd++) if (FD_ISSET(fd, &readfds))
{
if (sockfd == fd)
{
if ((newsockfd = accept(sockfd, &addr, &addr_len)) < 0) perror("accept");
write(newsockfd, msg, sizeof(msg));
is_connected[newsockfd] = 1;
printf("cnnect from %s\n", inet_ntoa(addr.sin_addr));
}
else
{
bzero(buffer, sizeof(buffer));
if (read(fd, buffer, sizeof(buffer)) <= 0)
{
printf("connect closed.\n");
is_connected[fd] = 0;
close(fd);
}
else printf("%s", buffer);
}
}
}
}
执行: $
./listen
connect
from
127.0.0.1
hi
I
am
client
connected
closed.
ntohl
ntohl(将32位网络字符顺序转换为主机字符顺序)
相关函数:htonl,htons,ntohs
表头文件:#include <netinet/in.h>
定义函数:unsigned long int ntohl(unsigned long int netlong);
函数说明:ntohl()用来将参数指定的32位netlong转换为主机字符顺序。
返回值:返回对应的主机字符顺序。
范例:参考getservent()。
ntohs
ntohs(将16位网络字符顺序转换为主机字符顺序)
相关函数:htonl,htons,ntohl
表头文件:#include <netinet/in.h>
定义函数:unsigned short int ntohs(unsigned short int netshort);
函数说明:ntohs()用来将参数指定的16位netshort转换为主机字符顺序。
返回值:返回对应的主机顺序。
范例:参考getservent()。
recv
recv(经socket接收数据)
相关函数:recvfrom,recvmsg,send,sendto,socket
表头文件:#include <sys/types.h> #include <sys/socket.h>
定义函数:int recv(int s, void *buf, int len, unsigned int flags);
函数说明:recv()用来接收远程主机经指定的socket传来的数据,并把数据存到由参数buf指向的内存空间,参数len为可接收数据的最大长度。 参数 flags一般设0。其他数值定义如下: MSG_OOB 接收以out-of-band送出的数据。 MSG_PEEK 返回来的数据并不会在系统内删除,如果再调用recv()会返回相同的数据内容。 MSG_WAITALL 强迫接收到len大小的数据后才能返回,除非有错误或信号产生。 MSG_NOSIGNAL 此操作不愿被SIGPIPE信号中断返回值成功则返回接收到的字符数,失败返回-1,错误原因存于errno中。
错误代码:EBADF 参数s非合法的socket处理代码 EFAULT 参数中有一指针指向无法存取的内存空间 ENOTSOCK 参数s为一文件描述词,非socket。 EINTR 被信号所中断 EAGAIN 此动作会令进程阻断,但参数s的socket为不可阻断 ENOBUFS 系统的缓冲内存不足。 ENOMEM 核心内存不足 EINVAL 传给系统调用的参数不正确。
范例:参考listen()。
recvfrom
recvfrom(经socket接收数据)
相关函数:recv,recvmsg,send,sendto,socket
表头文件:#include <sys/types.h> #include <sys/socket.h>
定义函数:int recvfrom(int s, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen);
函数说明:recv()用来接收远程主机经指定的socket传来的数据,并把数据存到由参数buf指向的内存空间,参数len为可接收数据的最大长度。参数flags一般设0,其他数值定义请参考recv()。参数from用来指定欲传送的网络地址,结构sockaddr请参考bind()。参数fromlen为sockaddr的结构长度。
返回值:成功则返回接收到的字符数,失败则返回-1,错误原因存于errno中。
错误代码:EBADF 参数s非合法的socket处理代码 EFAULT 参数中有一指针指向无法存取的内存空间。 ENOTSOCK 参数s为一文件描述词,非socket。 EINTR 被信号所中断。 EAGAIN 此动作会令进程阻断,但参数s的socket为不可阻断。 ENOBUFS 系统的缓冲内存不足 ENOMEM 核心内存不足 EINVAL 传给系统调用的参数不正确。
范例:
/* 利用socket的UDP client 此程序会连线UDP server,并将键盘输入的字符串传给server。 UDP server范例请参考sendto()。 */
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/typs.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define PORT 2345 #define SERVER_IP "127.0.0.1"
main()
{
int s, len;
struct sockaddr_in addr;
int addr_len = sizeof(
struct sockaddr_in); char buffer[256];
/* 建立socket */
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
exit(1);
}
/* 填写sockaddr_in */
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = inet_addr(SERVER_IP);
while (1)
{
bzero(buffer, sizeof(buffer));
/* 从标准输入设备取得字符串 */
len = read(STDIN_FILENO, buffer, sizeof(buffer));
/* 将字符串传送给server端 */
sendto(s, buffer, len, 0, &addr, addr_len);
/* 接收server端返回的字符串 */
len = recvfrom(s, buffer, sizeof(buffer), 0, &addr, &addr_len);
printf("receive: %s", buffer);
}
}
执行: (先执行udp server再执行udp client) hello /从键盘输入字符串/ receive: hello /server端返回来的字符串/
recvmsg
recvmsg(经socket接收数据)
相关函数:recv,recvfrom,send,sendto,sendmsg,socket
表头文件:#include <sys/types.h> #include <sys/socket.h>
定义函数:int recvmsg(int s, struct msghdr *msg, unsigned int flags);
函数说明:recvmsg()用来接收远程主机经指定的socket传来的数据。参数s为已建立好连线的socket,如果利用UDP协议则不需经过连线操作。参数msg指向欲连线的数据结构内容,参数flags一般设0,详细描述请参考send()。关于结构msghdr的定义请参考sendmsg()。
返回值:成功则返回接收到的字符数,失败则返回-1,错误原因存于errno中。
错误代码:EBADF 参数s非合法的socket处理代码。 EFAULT 参数中有一指针指向无法存取的内存空间 ENOTSOCK 参数s为一文件描述词,非socket。 EINTR 被信号所中断。 EAGAIN 此操作会令进程阻断,但参数s的socket为不可阻断。 ENOBUFS 系统的缓冲内存不足 ENOMEM 核心内存不足 EINVAL 传给系统调用的参数不正确。
范例:参考recvfrom()。
send
send(经socket传送数据)
相关函数:sendto,sendmsg,recv,recvfrom,socket
表头文件:#include <sys/types.h> #include <sys/socket.h>
定义函数:int send(int s, const void *msg, int len, unsigned int falgs);
函数说明:send()用来将数据由指定的socket传给对方主机。参数s为已建立好连接的socket。参数msg指向欲连线的数据内容,参数len则为数据长度。参数flags一般设0,其他数值定义如下 MSG_OOB 传送的数据以out-of-band送出。 MSG_DONTROUTE 取消路由表查询 MSG_DONTWAIT 设置为不可阻断运作 MSG_NOSIGNAL 此动作不愿被SIGPIPE信号中断。
返回值:成功则返回实际传送出去的字符数,失败返回-1。错误原因存于errno
错误代码:EBADF 参数s非合法的socket处理代码。 EFAULT 参数中有一指针指向无法存取的内存空间 ENOTSOCK 参数s为一文件描述词,非socket。 EINTR 被信号所中断。 EAGAIN 此操作会令进程阻断,但参数s的socket为不可阻断。 ENOBUFS 系统的缓冲内存不足 ENOMEM 核心内存不足 EINVAL 传给系统调用的参数不正确。
范例:参考connect()
sendmsg
sendmsg(经socket传送数据)
相关函数:send,sendto,recv,recvfrom,recvmsg,socket
表头文件:#include <sys/types.h> #include <sys/socket.h>
定义函数:int sendmsg(int s, const struct msghdr *msg, unsigned int flags);
函数说明:sendmsg()用来将数据由指定的socket传给对方主机。参数s为已建立好连线的socket,如果利用UDP协议则不需经过连线操作。参数msg指向欲连线的数据结构内容,参数flags一般默认为0,详细描述请参考send()。 结构msghdr定义如下 struct msghdr { void msg_name; / Address to send to / receive from. / socklen_t msg_namelen; / Length of addres data */ struct iovec msg_iov; / Vector of data to send/receive into / size_t msg_iovlen; / Number of elements in the vector */ void msg_control; / Ancillary dat / size_t msg_controllen; / Ancillary data buffer length / int msg_flags; / Flags on received message */ };
返回值:成功则返回实际传送出去的字符数,失败返回-1,错误原因存于errno
错误代码:EBADF 参数s非合法的socket处理代码。 EFAULT 参数中有一指针指向无法存取的内存空间 ENOTSOCK 参数s为一文件描述词,非socket。 EINTR 被信号所中断。 EAGAIN 此操作会令进程阻断,但参数s的socket为不可阻断。 ENOBUFS 系统的缓冲内存不足 ENOMEM 核心内存不足 EINVAL 传给系统调用的参数不正确。
范例:参考sendto()。
sendto
sendto(经socket传送数据)
相关函数:send, sendmsg, recv, recvfrom, socket
表头文件:#include <sys/types.h> #include <sys/socket.h>
定义函数:int sendto(int s, const void *msg, int len, unsigned int flags, const struct sockaddr *to, int tolen);
函数说明:sendto()用来将数据由指定的socket传给对方主机。参数s为已建好连线的socket,如果利用UDP协议则不需经过连线操作。参数msg指向欲连线的数据内容,参数flags一般设0,详细描述请参考send()。参数to用来指定欲传送的网络地址,结构sockaddr请参考bind()。参数tolen为sockaddr的结果长度。
返回值:成功则返回实际传送出去的字符数,失败返回-1,错误原因存于errno中。
错误代码:EBADF 参数s非法的socket处理代码。 EFAULT 参数中有一指针指向无法存取的内存空间。 ENOTSOCK 参数s为一文件描述词,非socket。 EINTR 被信号所中断。 EAGAIN 此动作会令进程阻断,但参数s的socket为不可阻断。 ENOBUFS 系统的缓冲内存不足。 EINVAL 传给系统调用的参数不正确。
范例:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet.in.h>
#include <arpa.inet.h>
#define PORT 2345
/*使用的port*/
main()
{
int sockfd, len;
struct sockaddr_in addr;
char buffer[256];
/* 建立socket */
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
exit(1);
}
/* 填写sockaddr_in结构 */
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr = htonl(INADDR_ANY);
if (bind(sockfd, &addr, sizeof(addr)) < 0)
{
perror("connect");
exit(1);
}
while (1)
{
bzero(buffer, sizeof(buffer));
len = recvfrom(sockfd, buffer, sizeof(buffer), 0, &addr, &addr_len);
/* 显示client端的网络地址 */
printf("receive from %s\n", inet_ntoa(addr.sin_addr));
/* 将字串返回给client端 */
sendto(sockfd, buffer, len, 0, &addr, addr_len);
}
}
执行: 请参考recvfrom()
setprotoent
setprotoent(打开网络协议的数据文件)
相关函数:getprotobyname, getprotobynumber, endprotoent
表头文件:#include <netdb.h>
定义函数:void setprotoent(int stayopen);
函数说明:setprotoent()用来打开/etc/protocols,如果参数stayopen值为1,则接下来的getprotobyname()或getprotobynumber()将不会自动关闭此文件。
setservent
setservent(打开主机网络服务的数据文件)
相关函数:getservent, getservbyname, getservbyport, endservent
表头文件:#include <netdb.h>
定义函数:void setservent(int stayopen);
函数说明:setservent()用来打开/etc/services,如果参数stayopen值为1,则接下来的getservbyname()或getservbyport()将不会自动关闭文件。
setsockopt
setsockopt(设置socket状态)
相关函数:getsockopt
表头文件:#include <sys/types.h> #include <sys/socket.h>
定义函数:int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
函数说明:setsockopt()用来设置参数s所指定的socket状态。参数level代表欲设置的网络层,一般设成SOL_SOCKET以存取socket层。参数optname代表欲设置的选项,有下列几种数值: SO_DEBUG 打开或关闭排错模式 SO_REUSEADDR 允许在bind()过程中本地地址可重复使用 SO_TYPE 返回socket形态。 SO_ERROR 返回socket已发生的错误原因 SO_DONTROUTE 送出的数据包不要利用路由设备来传输。 SO_BROADCAST 使用广播方式传送 SO_SNDBUF 设置送出的暂存区大小 SO_RCVBUF 设置接收的暂存区大小 SO_KEEPALIVE 定期确定连线是否已终止。 SO_OOBINLINE 当接收到OOB数据时会马上送至标准输入设备 SO_LINGER 确保数据安全且可靠的传送出去。 参数 optval代表欲设置的值,参数optlen则为optval的长度。
返回值:成功则返回0,若有错误则返回-1,错误原因存于errno。
附加说明:EBADF 参数s并非合法的socket处理代码 ENOTSOCK 参数s为一文件描述词,非socket ENOPROTOOPT 参数optname指定的选项不正确。 EFAULT 参数optval指针指向无法存取的内存空间。
范例:参考getsockopt()。
shutdown
shutdown(终止socket通信)
相关函数:socket,connect
表头文件:#include <sys/socket.h>
定义函数:int shutdown(int s, int how);
函数说明:shutdown()用来终止参数s所指定的socket连线。参数s是连线中的socket处理代码,参数how有下列几种情况: how=0 终止读取操作。 how=1 终止传送操作 how=2 终止读取及传送操作
返回值:成功则返回0,失败返回-1,错误原因存于errno。
错误代码:EBADF 参数s不是有效的socket处理代码 ENOTSOCK 参数s为一文件描述词,非socket ENOTCONN 参数s指定的socket并未连线
socket
socket(建立一个socket通信)
相关函数:accept,bind,connect,listen
表头文件:#include <sys/types.h> #include <sys/socket.h>
定义函数:int socket(int domain, int type, int protocol);
函数说明:socket()用来建立一个新的socket,也就是向系统注册,通知系统建立一通信端口。参数domain指定使用何种的地址类型,完整的定义在/usr/include/bits/socket.h内,底下是常见的协议: PF_UNIX/PF_LOCAL/AF_UNIX/AF_LOCAL UNIX进程通信协议 PF_INET/AF_INET Ipv4网络协议 PF_INET6/AF_INET6 Ipv6网络协议 PF_IPX/AF_IPX IPX-Novell协议 PF_NETLINK/AF_NETLINK 核心用户接口装置 PF_X25/AF_X25 ITU-T X.25/ISO-8208协议 PF_AX25/AF_AX25 业余无线AX.25协议 PF_ATMPVC/AF_ATMPVC 存取原始ATM PVCs PF_APPLETALK/AF_APPLETALK appletalk(DDP)协议 PF_PACKET/AF_PACKET 初级封包接口 参数 type有下列几种数值: SOCK_STREAM 提供双向连续且可信赖的数据流,即TCP。支持 OOB机制,在所有数据传送前必须使用connect()来建立连线状态。 SOCK_DGRAM 使用不连续不可信赖的数据包连接 SOCK_SEQPACKET 提供连续可信赖的数据包连接 SOCK_RAW 提供原始网络协议存取 SOCK_RDM 提供可信赖的数据包连接 SOCK_PACKET 提供和网络驱动程序直接通信。 protocol用来指定socket所使用的传输协议编号,通常此参考不用管它,设为0即可。
返回值:成功则返回socket处理代码,失败返回-1。
错误代码:EPROTONOSUPPORT 参数domain指定的类型不支持参数type或protocol指定的协议 ENFILE 核心内存不足,无法建立新的socket结构 EMFILE 进程文件表溢出,无法再建立新的socket EACCESS 权限不足,无法建立type或protocol指定的协议 ENOBUFS/ENOMEM 内存不足 EINVAL 参数domain/type/protocol不合法
范例:参考connect()。
环境变量篇 15
TODO
getenv
getenv(取得环境变量内容)
相关函数:putenv,setenv,unsetenv
表头文件:#include <stdlib.h>
定义函数:char *getenv(const char *name);
函数说明:getenv()用来取得参数name环境变量的内容。参数name为环境变量的名称,如果该变量存在则会返回指向该内容的指针。环境变量的格式为name=value。
返回值:执行成功则返回指向该内容的指针,找不到符合的环境变量名称则返回NULL。
范例:
#include <stdlib.h>
mian()
{
char *p;
if ((p = getenv("USER"))) printf("USER=%s\n", p);
}
执行: USER = root
putenv
putenv(改变或增加环境变量)
相关函数:getenv,setenv,unsetenv
表头文件:#include <stdlib.h>
定义函数:int putenv(const char *string);
函数说明:putenv()用来改变或增加环境变量的内容。参数string的格式为name=value,如果该环境变量原先存在,则变量内容会依参数string改变,否则此参数内容会成为新的环境变量。
返回值:执行成功则返回0,有错误发生则返回-1。
错误代码:ENOMEM 内存不足,无法配置新的环境变量空间。
范例:
#include <stdlib.h>
main()
{
char *p;
if ((p = getenv("USER"))) printf("USER =%s\n", p);
putenv("USER=test");
printf("USER=%s\n", getenv("USER"));
}
执行: USER=root USER=root
setenv
setenv(改变或增加环境变量)
相关函数:getenv,putenv,unsetenv
表头文件:#include <stdlib.h>
定义函数:int setenv(const char *name, const char *value, int overwrite);
函数说明:setenv()用来改变或增加环境变量的内容。参数name为环境变量名称字符串。 参数 value则为变量内容,参数overwrite用来决定是否要改变已存在的环境变量。如果overwrite不为0,而该环境变量原已有内容,则原内容会被改为参数value所指的变量内容。如果overwrite为0,且该环境变量已有内容,则参数value会被忽略。
返回值:执行成功则返回0,有错误发生时返回-1。
错误代码:ENOMEM 内存不足,无法配置新的环境变量空间
范例:
#include <stdlib.h>
main()
{
char *p;
if ((p = getenv("USER"))) printf("USER =%s\n", p);
setenv("USER", "test", 1);
printf("USER=%s\n", getenv("USEr"));
unsetenv("USER");
printf("USER=%s\n", getenv("USER"));
}
执行: USER = root USER = test USER = (null)
终端控制篇 16
TODO
getopt
getopt(分析命令行参数)
相关函数:
表头文件:#include <unistd.h>
定义函数:int getopt(int argc, char *const argv[], const char *optstring);
函数说明:getopt()用来分析命令行参数。参数argc和argv是由main()传递的参数个数和内容。参数optstring则代表欲处理的选项字符串。此函数会返回在argv中下一个的选项字母,此字母会对应参数optstring中的字母。如果选项字符串里的字母后接着冒号":",则表示还有相关的参数,全局变量optarg即会指向此额外参数。如果getopt()找不到符合的参数则会印出错信息,并将全局变量optopt设为"?"字符,如果不希望getopt()印出错信息,则只要将全局变量opterr设为0即可。
返回值:如果找到符合的参数则返回此参数字母,如果参数不包含在参数optstring的选项字母则返回"?"字符,分析结束则返回-1。
范例:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
int ch;
opterr = 0;
while ((ch = getopt(argc, argv, "a:bcde")) != -1)
{
switch (ch)
{
case 'a':
printf("option a:'%s'\n", optarg);
break;
case 'b':
printf("option b :b\n");
break;
default:
printf("other option :%c\n", ch);
}
}
printf("optopt +%c\n", optopt);
}
执行: $./getopt -b option b:b
$./getopt -c other option:c
$./getopt -a other option :?
$./getopt -a12345 option a:'12345'
isatty
isatty(判断文件描述词是否是伪终端机)
相关函数:ttyname
表头文件:#include <unistd.h>
定义函数:int isatty(int desc);
函数说明:如果参数desc所代表的文件描述词为一终端机则返回1,否则返回0。
返回值:如果文件为终端机则返回1,否则返回0。
范例:参考ttyname()。
select
select(I/O多工机制)
表头文件:#include <sys/time.h> #include <sys/types.h> #include <unistd.h>
定义函数:int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
函数说明:select()用来等待文件描述词状态的改变。参数n代表最大的文件描述词加1,参数readfds、writefds和exceptfds称为描述词组,是用来回传该描述词的读,写或例外的状况。底下的宏提供了处理这三种描述词组的方式: FD_CLR(inr fd, fd_set* set);用来清除描述词组set中相关fd的位 FD_ISSET(int fd, fd_set set);用来测试描述词组set中相关fd的位是否为真 FD_SET(int fd, fd_setset);用来设置描述词组set中相关fd的位 FD_ZERO(fd_set *set);用来清除描述词组set的全部位 参数 timeout为结构timeval,用来设置select()的等待时间,其结构定义如下 struct timeval { time_t tv_sec; time_t tv_usec; };
返回值:如果参数timeout设为NULL则表示select()没有timeout。
错误代码:执行成功则返回文件描述词状态已改变的个数,如果返回0代表在描述词状态改变前已超过timeout时间,当有错误发生时则返回-1,错误原因存于errno,此时参数readfds,writefds,exceptfds和timeout的值变成不可预测。 EBADF 文件描述词为无效的或该文件已关闭 EINTR 此调用被信号所中断 EINVAL 参数n为负值。 ENOMEM 核心内存不足
范例:常见的程序片段:fs_set readset; FD_ZERO(&readset); FD_SET(fd, &readset); select(fd+1, &readset, NULL, NULL, NULL); if (FD_ISSET(fd, readset)) { ... }
ttyname
ttyname(返回一终端机名称)
相关函数:Isatty
表头文件:#include <unistd.h>
定义函数:char *ttyname(int desc);
函数说明:如果参数desc所代表的文件描述词为一终端机,则会将此终端机名称由一字符串指针返回,否则返回NULL。
返回值:如果成功则返回指向终端机名称的字符串指针,有错误情况发生时则返回NULL。
范例:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
main()
{
int fd;
char *file = "/dev/tty";
fd = open(file, O_RDONLY);
printf("%s", file);
if (isatty(fd))
{
printf("is a tty.\n");
printf("ttyname = %s\n", ttyname(fd));
}
else printf(" is not a tty\n");
close(fd);
}
执行: /dev/tty is a tty ttyname = /dev/tty