详见CPrimerPlus P343
C库提供了多个处理字符串的函数。
ASCII C把这些函数原型放在string.h头文件中,其中最常用的有strlen()、strcat()、strcmp()、strncmp()、strcpy()、strncpy()
和放在stdio.h中的springf()
头文件:#include<string.h>
作用:用于统计字符串的长度。
案例:检测并缩短字符串到规定长度。
void fit(char *string,unsigned int size)
{
if(strlen(string) > size)
string[size] = '\0';
}
PS:(优化技巧)函数要改变字符串,所以函数头在声明形式参数string时没有使用const限定符。通常情况若不改变函数参数所指向内容时在参数列表都加上const限定符防止误操作改变了。
fit函数使用案例:
#include<stdio.h>
#include<string.h>
void fit(char *,unsigned int);
int main(void)
{
//字符串的优化式写法
char mesg[] = "Things should be as simple as possible,"
" but not simpler";
//修改前
puts(mesg);
//修改后
fit(mesg,38);
puts(mesg);
puts(mesg+39);
}
void fit(char *string,unsigned int size)
{
if(strlen(string) > size)
string[size] = '\0';
}
输出结果:
Things should be as simple as possible,but not simpler
Things should be as simple as possible
but not simpler
分析:
fit函数把第39个元素的逗号换成了’\0‘字符,puts函数在空字符处停止输出,并忽略其余字符,然而字符还在缓冲区中,下面的函数调用就把这些字符打印了出来。
表达式mesg + 39是mesg[39]的地址,该地址所指向的字符是空格,其前面的那个字符是原来的逗号(,)被替换成了空字符(’\0‘)。
头文件:#include<string.h>
作用:用于拼接两个字符串:该函数把第二个字符串的备份附加在第一个字符串的末尾,并把拼接后形成的新字符串作为第一个字符串,第二个字符串不变。
案例:
#include<stdio.h>
#include<string.h>
#define SIZE 80;
char *s_gets(char*st,int n);
int main(void)
{
char flower[SIZE];
char addon [] = "s smell like old shoes.";
puts("What is your favourite flower?");
if(s_gets(flower,SIZE))//使用s_gets函数检测
{
strcat(flower,addon);
puts(flower);
puts(addon);
}
else
puts("End of file encountered");
puts("bye");
return 0;
}
char *s_gets(char * st,int n)//典型的 处理字符出 的函数
{
char * ret_val;
int i = 0;
ret_val = fgets(st,n,stdin);
if(ret_val)
{
while(st[i] != '\n' && st[i] != '\0')
i++;
if(st[i] == '\n')
st[i] = '\0';
else
while(getchar() != '\n')
continue;
}
return ret_val;
}
PS:
fgets(buf,STLEN,fp);
详见CPrimerPlus P422
buf是char类型数组的名称,STLEN是字符串的大小,fp是指向FILE的指针。
fgets()的第一个参数跟gets函数一样,也是表示储存输入位置的地址(char*类型),第二个参数是一个整数,表示待输入字符串的大小,最后一个参数是文件指针,指定读取的文件。
注意字符串的大小和字符串的长度不同。前者指改字符串占了多大内存,后者指该字符串字符的个数。特别注意fgets函数的第二个参数。
输出结果:
what is your favourite flower?
wonderflower
wonderflowers smell like old shoes.
s smell like old shoes.
bye
分析:
flower变了,而addon没变。
PS:关于两个截断字符串函数的对比分析
1.(适用于截断已经定义过的字符串)通过更换字符为’\0‘提前结束字符串,但是字符串占用的内存未发生变化。
无返回值
void fit(char *string,unsigned int size)
{
if(strlen(string) > size)
string[size] = '\0';
}
2.(适用于截断正在从缓存区读取中的字符串)通过fgets获取所需长度的字符串,之后通过getchar函数释放缓存区。
返回值是s_gets函数中fgets函数的返回值,判断输入是否成功。
char *s_gets(char * st,int n)//典型的 处理字符出 的函数
{
char * ret_val;
int i = 0;
ret_val = fgets(st,n,stdin);
if(ret_val)
{
while(st[i] != '\n' && st[i] != '\0')//直到遇到’\n‘或者’\0‘时停止,得到空字符的下标。
i++;
if(st[i] == '\n')//将回车转换成’\0‘标志着字符串的合成,因为按下回车一般默认字符串已经输入完成
st[i] = '\0';
else
while(getchar() != '\n')//释放缓存区中未读取完的字符
continue;
}
return ret_val;
}
PS:
fgets函数在遇到EOF时返回NULL值,可以利用这一机制检测是否到达文件末尾,如果未遇到EOF则返回之前传递给它的第一个参数地址。 fgets函数地区输入一直到第一个换行符的后面(’\n‘),或读到文件结尾,或者读取SYTLEN-1个字符,然后fgets函数在末尾添加一个空字符(’\0‘)使之成为一个字符串,因此循环判断
while(st[i] != '\n' && st[i] != '\0')
中只有这两种情况。 字符串的大小是字符数加上一个空字符 如果fgets函数在读到字符串上限之前就已经读完一行,它会把表示结尾的换行符放在空字符(’\0‘)前面。 fgets函数保留了换行符,不同于gets函数,因此使用fputs函数打印字符串时也不会在其末尾添加换行符。
头文件:#include<string.h>
优化:strcat()无法检查第一个数组能否容纳第二个字符串。如果分配给第一个数组的空间不够大,多出来的字符一处到相邻存储单元时就会出问题。
当然可以利用上面的strlen()函数案例查看第一个数组的长度并且使用其案例中的截断字符串函数截断。
注意:要给拼接后的字符串长度加一才能够空间存放末尾的空字符。或者,用strncat()函数的第三个参数指定了最大添加字符数。
例如:strncat(bugs,addon,13)将把addon字符串的内容附加给bugs,在加到第13个字符或遇到空字符时停止。
案例:
#include<stdio.h>
#include<string.h>
#define SIZE 30;
#define BUGSIZE 13;
char *s_gets(char*st,int n);
int main(void)
{
char flower[SIZE];
char addon [] = "s smell like old shoes.";
char bug[BUGSIZE];
int available;
puts("What is your favourite flower?");
s_gets(flower,SIZE);
return 0;
}
char *s_gets(char * st,int n)//典型的 处理字符出 的函数
{
char * ret_val;
int i = 0;
ret_val = fgets(st,n,stdin);
if(ret_val)
{
while(st[i] != '\n' && st[i] != '\0')
i++;
if(st[i] == '\n')
st[i] = '\0';
else
while(getchar() != '\n')
continue;
}
return ret_val;
}
strcmp()是C语言中的字符串比较函数。它接受两个字符串作为参数,并比较它们的内容。
strcmp()函数返回0,如果两个字符串完全相同;
返回一个小于0的值,如果第一个字符串比第二个字符串小;
返回一个大于0的值,如果第一个字符串比第二个字符串大。
语法: int strcmp(const char *str1, const char *str2);
参数:
返回值:
示例:
#include <stdio.h>
#include <string.h>
int main()
{
char str1[15];
char str2[15];
int ret;
strcpy(str1, "abc");
strcpy(str2, "abc");
ret = strcmp(str1, str2);
if(ret < 0)
{
printf("str1 is less than str2");
}
else if(ret > 0)
{
printf("str2 is less than str1");
}
else
{
printf("str1 is equal to str2");
}
return(0);
}
//输出:str1 is equal to str2
strncmp()是C语言中的字符串比较函数。与strcmp()类似,它也比较两个字符串的内容,但它只比较前n个字符。如果前n个字符完全相同,则返回0;如果第一个字符串比第二个字符串小,则返回一个小于0的值;如果第一个字符串比第二个字符串大,则返回一个大于0的值。
语法: int strncmp(const char *str1, const char *str2, size_t n);
参数:
返回值:
示例:
#include <stdio.h>
#include <string.h>
int main()
{
char str1[15];
char str2[15];
int ret;
strcpy(str1, "abcdef");
strcpy(str2, "abcdef");
ret = strncmp(str1, str2, 4);
if(ret < 0)
{
printf("str1 is less than str2");
}
else if(ret > 0)
{
printf("str2 is less than str1");
}
else
{
printf("str1 is equal to str2");
}
return(0);
}
//输出:str1 is equal to str2
strcpy()是C语言中的字符串复制函数。它的功能是从源字符串复制字符到目标字符串,直到遇到字符串结束符’\0’为止。
语法: char *strcpy(char *dest, const char *src);
参数:
返回值:
示例:
#include <stdio.h>
#include <string.h>
int main ()
{
char source[50], target[50];
strcpy(source, "This is source");
strcpy(target, "This is target");
strcpy(target, source);
printf("Source string: %s\n", source);
printf("Target string: %s\n", target);
return 0;
}
//输出:
Source string: This is source
Target string: This is source
strncpy()是C语言中的字符串复制函数。它的功能与strcpy()相似,不同的是strncpy()可以限制复制字符的数量。
语法:char *strncpy(char *dest, const char *src, size_t n);
参数:
返回值:
示例:
#include <stdio.h>
#include <string.h>
int main ()
{
char source[50], target[50];
strcpy(source, "This is source");
strncpy(target, source, 5);
target[5] = '\0';
printf("Source string: %s\n", source);
printf("Target string: %s\n", target);
return 0;
}
//输出
Source string: This is source
Target string: This
strchr()是C语言中的字符串查找函数。它的作用是在一个字符串中查找给定字符的首次出现位置。
语法:char *strchr(const char *str, int c);
参数:
返回值:
示例:
#include <stdio.h>
#include <string.h>
int main ()
{
char str[50];
char *p;
strcpy(str, "This is a sample string");
p = strchr(str, 's');
while (p != NULL)
{
printf("Found at %d\n", p - str + 1);
p = strchr(p + 1, 's');
}
return 0;
}
//输出
Found at 5
Found at 7
Found at 15
strpbrk()是C语言中的字符串函数,用于在一个字符串中查找第一个在另一个字符串中出现的字符。
检索字符串 str1 中第一个匹配字符串 str2 中字符的字符,不包含空结束字符。也就是说,依次检验字符串 str1 中的字符,当被检验字符在字符串 str2 中也包含时,则停止检验,并返回该字符位置。
语法:char *strpbrk(const char *str1, const char *str2);
参数:
返回值:
示例:
#include <stdio.h>
#include <string.h>
int main ()
{
const char str1[] = "abcde2fghi3jk4l";
const char str2[] = "34";
char *ret;
ret = strpbrk(str1, str2);
if(ret)
{
printf("第一个匹配的字符是: %c\n", *ret);
}
else
{
printf("未找到字符");
}
return(0);
}
//输出
第一个匹配的字符是: 3
例二:
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "This is a sample string";
char keys[] = "aeiou";
char *p;
p = strpbrk(str, keys);
while (p != NULL)
{
printf("Found %c at %d\n", *p, p - str + 1);
p = strpbrk(p + 1, keys);
}
return 0;
}
//输出
Found i at 3
Found i at 6
Found a at 9
Found a at 12
Found e at 16
Found i at 21
代码的主要部分包括:
p - str
是指 p
指针所指向的字符在字符串 str
中的位置与字符串 str
的首地址的距离, 这里算出的是字符的位置编号. 由于 C 语言中数组的第一个元素的位置编号是 0, 所以最终的输出加上 1, 即为字符的位置编号.其中p是一个字符指针,指向包含元音字母的位置;str是一个字符数组,代表要搜索的字符串。p - str的结果就是字符的偏移量,即该字符的位置在字符串中的索引。
最终,程序会输出每个字符在str中的位置。
PS:字符串中字符的地址相减返回什么?
字符串中字符的地址相减返回两个字符在字符串中的位置的差值,以字符大小计算(一般是1字节)。
数组元素是连续存储在内存中的,所以它们的地址相减的结果就等于元素的坐标差值,与数据类型无关。
int a[] = {1,2,3,4,5,};
int *p = a;
int *q = &a[5];
printf("%d",q-p);
//输出结果?5
因为数组名代表整个数组的地址,数组的首元素的地址就是数组的地址,数组名代表的是数组的首元素的地址。因此,int *p = a; 将p指向了a数组的首元素的地址,int *q = &a[5]; 将q指向了a数组的第6个元素的地址。q-p等于第6个元素的地址减去第一个元素的地址,也就是第6个元素在数组中的下标减去第一个元素在数组中的下标,得到的结果是5,因此输出结果为5。
strrchr()是C语言中的字符串函数,用于在一个字符串中查找最后一次出现的指定字符。
语法:char *strrchr(const char *str, int c);
参数:
返回值:
示例:
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "This is a sample string";
char *p;
p = strrchr(str, 's');
printf("Last occurrence of 's' found at %d\n", p - str + 1);
return 0;
}
//输出
Last occurrence of 's' found at 19
strstr()是C语言中的字符串函数,用于在一个字符串中查找第一次出现的另一个字符串。
语法:char *strstr(const char *haystack, const char *needle);
参数:
返回值:
示例:
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] = "This is a sample string";
char *p;
p = strstr(str, "sample");
printf("String after |%s| is: |%s|\n", "sample", p);
return 0;
}
//输出
String after |sample| is: | sample string|