程序按功能界定可分为数值运算,符号处理和I/O操作三类,符号处理程序占相当大的比列,符号处理程序无处不在,编译器,浏览器等程序的主要功能都是符号处理。无论多复杂的符号处理都是由各类基本的字符串操作组成的。
1.初始化字符串
#include
void *memset(void *s, int c, size_t n);
返回值:s指向哪,返回的指针就指向哪
memset函数把s所指向的显存地址开始的n个字节都填充为c的值。一般c的值为0,把一块显存区清零。比如定义charbuf[10];假如它是全局变量或静态变量,则手动初始化为0(坐落.bss段),假如它是函数的局部变量,则终值不确定,可以用memset(buf,0,10)清零,由malloc分配的显存年率也是不确定的,也可以用memset清零。
2.取字符串的宽度
#include
size_t strlen(const char *s);
返回值:字符串的长度
strlen函数返回s所指的字符串的厚度。函数从s所指的第一个字符开始找''字符,一旦找到就返回,返回的厚度不包括''字符在内。比如定义charbuf[]="hello";则strlen(buf)的值是5,但要注意,假若定义charbuf[5]="hello";则调用strlen(buf)是危险的,会导致链表访问越界。
3.拷贝字符串
strcpy和strncpy函数,拷贝以''结尾的字符串,strncpy还带一个参数指定最多拷贝多少个字节,再者linux c 查找字符串,strncpy并不保证缓冲区以''结尾。
#include
void *memcpy(void *dest, const void *src, size_t n);
void *memmove(void *dest, const void *src, size_t n);
返回值:dest指向哪,返回的指针就指向哪
memcpy函数从src所指的显存地址拷贝n个字节到dest所指的显存地址,和strncpy不同红旗linux5.0,并不是遇见''就结束,而是一定会拷贝完n个字节。这儿的命名规律是,以str开头的函数处理是''结尾的字符串,而以mem开头的函数则不关心''字符,或则说这种函数并不把参数当字符串看待,因而参数的表针类型是void*而非char*。
memmove也是从src所指的显存地址拷贝n个字节到dest所指向的显存地址,即使叫move但也许也是拷贝而非联通。并且和memcpy有一点不同,memcpy的两个参数src和dest所指向的显存空间假如重叠则难以保证正确拷贝,而memmove却可以正确拷贝。假定定义了一个链表charbuf[20]="helloworldn";假如想把其中的字符串往前联通一个字节(弄成"hhelloworldn"),调用memcpy(buf+1,buf,13)是难以保证正确拷贝的:
以下memcpy用法是错误的:
#include
#include
int main()
{
char src[20] = "hello worldn";
memcpy(src+1, src, 13);
printf("%sn", src);
return 0;
}
将memcpy改成memmove
#include
#include
int main()
{
char src[20] = "hello worldn";
memmove(src+1, src, 13);
printf("%sn", src);
return 0;
}
4.联接字符串
#include
char *strcat(char *dest, const char *src);
char *strcat(char *dest, const char *src, size_t n);
strcat把src所指的字符串联接到dest所指的字符串旁边,比如:
char d[10] = "foo";
char s[10] = "bar";
strcat(d, s);
printf("%s %sn", d, s);
调用strcat函数后,缓冲区s的内容没变linux c 查找字符串,缓冲区d中保存着字符串"foobar",注意原先"foo"前面的''被联接上来的字符串"bar"覆盖掉了,"bar"前面的""仍保留。
strcat和strcpy有同样的问题,调用者必须确保dest缓冲区足够大,否则会造成缓冲区溢出错误。strncat函数通过参数n指定一个宽度,就可以防止缓冲区溢出错误。注意这个参数n的涵义和strncpy的参数n不同,它并不是缓冲区dest的宽度,而是表示最多从src缓冲区中取n个字符(不包括结尾的'')联接到dest旁边。假如src中前n个字符没有出现'',则取前n个字符再加一个''联接到dest旁边,所以strncat总是保证dest缓冲区以''结尾,这一点又和strncpy不同,strncpy并不保证dest缓冲区以''结尾。所以,提供给strncat函数的dest缓冲区的大小起码应当是strlen(dest)+n+1个字节,能够保证不溢出。
5.比较字符串
#include
int memcmp(const void *s1, const void *s2, size_t n);
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
memcmp从前到后挨个比较缓冲区s1和s2的前n个字节(不管上面有没有''),倘若s1和s2的前n个字节全都一样就返回0,假如遇见不一样的字节,s1的字节比s2小就返回负值,s1的字节比s2大就返回正值。
strcmp把s1和s2当字符串比较,在其中一个字符串中遇见''结束,根据前面的比较准则,"ABC"比"abc"小,"ABCD"比"ABC"大,"123A9"比"123B2"小。
strncmp的比较结束条件是:要么在其中一个字符串中遇见''结束(类似于strcmp),要么比较完n个字符结束(类似于memcmp)。诸如,strncmp("ABCD","ABC",3)的返回值是0,strncmp("ABCD","ABC",4)的返回值是正值。
6.搜索字符串
#include
char *strchr(const char *s, int c);
char *strrchr(const char *s, int c);
返回值:如果找到字符c, 返回字符串s 中指向字符c的指针,如果找不到就返回NULL。
strchr在字符串s中从前到后查找字符串c,找到字符c第一次出现的位置时就返回,返回值指向这个位置,假若找不到字符c就返回NULL。strrchr和strchr类似,并且从右向左找字符c,找到字符c第一次出现的位置就返回,函数名中间多了一个字母r可以理解为Right-to-left。
#include
char *strstr(const char *haystack, const char *needle);
返回值:如果找到子串,返回值指向子串的开头,如果找不到就返回NULL。
strstr在一个长字符串中从前到后找一个子串,找到子串第一次出现的位置就返回,返回值指向子串的开头,假如找不到就返回NULL。
7.分割字符串
好多文件格式或合同格式中会规定一些分割符或则划分符,比如/etc/passwd文件中保存着系统的帐号信息:
$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
...
每条记录占一行,也就是说记录之间的分隔符是换行符,每条记录又由若干个数组组成,这种数组包括用户名,密码,用户id,组id,个人信息,主目录,登陆Shell,数组之间的分割符是:号。解析这样的字符串须要依照分隔符把字符串分割成几段,C标准库提供的strtok函数可以很便捷地完成分割字符串的操作。
#include
char *strtok(char *str, const char *delim);
char *strtok_r(char *str, const char *delim, char **saveptr);
返回值: 返回指向下一个Token的指针,如果没有下一个Token 了就返回NULL。
参数str是带分割的字符串,delim是分割符,可以指定一个或多个分割符,strtok遇见其中任何一个分割符才会分割字符串。
#include
#include
int main(void)
{
char str[] = "root:x::0:root:/root:/bin/bash:";
char *token;
token = strtok(str, ":");
printf("%sn", token);
while ( (token = strtok(NULL, ":")) != NULL)
printf("%sn", token);
return 0;
}
$ ./a.out
root
x
0
root
/root
/bin/bash
strtok的行为可以这样理解:引号是分割符,把"root:x::0:root:/root:/bin/bash:"这个字符串分割成"root","x","","0","root","/root","/bin/bash","",等几个Token,但空字符串的Token被忽视。第一次调用要把字符串首地址传给strtok的第一个参数,之后每次调用第一个参数只要传NULL就可以了,strtok函数自己会记住先前处理到字符串的哪些位置(通过strtok函数中的一个静态变量记住的)。
ManPage强调了用strtok和strtok_r函数须要注意的问题:
这两个函数要改写字符串以达到分割的疗效
这两个函数不能用于常量字符串什么是linux,由于企图改写.rodata段会形成段错误
在做了分割以后,字符串中的分隔符就被''覆盖了
strtok函数使用了静态变量,它不是线程安全的,必要时应当用可重入的strtok_r函数