提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- @[TOC](文章目录)
- 前言
- 一、针对单个字符的C语言库中的函数
- (一)、字符分类函数
- (二)、字符转换函数
- 二、针对字符串的C语言库中的函数
- (一)、strlen函数
- (二)、strcpy函数
- (三)、strcat函数
- (四)、strcmp函数
- (五)、strncpy函数
- (六)、strncat函数
- (七)、strncmp函数
- (八)、strstr函数
- (九)、strtok函数
- (十)、strerror函数
- 总结
文章目录
- @[TOC](文章目录)
- 前言
- 一、针对单个字符的C语言库中的函数
- (一)、字符分类函数
- (二)、字符转换函数
- 二、针对字符串的C语言库中的函数
- (一)、strlen函数
- (二)、strcpy函数
- (三)、strcat函数
- (四)、strcmp函数
- (五)、strncpy函数
- (六)、strncat函数
- (七)、strncmp函数
- (八)、strstr函数
- (九)、strtok函数
- (十)、strerror函数
- 总结
前言
本文主要介绍C语言库中针对单个字符的函数以及针对字符串的函数的使用细则以及模拟实现。
一、针对单个字符的C语言库中的函数
引用头文件<ctype.h>
(一)、字符分类函数
- C语言中有一系列的函数是专门用来做字符分类的,也就是判断一个字符是属于什么类型的字符的。
- 常用的<ctype.h>头文件中常用字符分类函数为:
以上函数的使用方法类型,我们以调用判断一个字符是否为小写字符为例来看一下代码:
写一段代码将字符串中的小写字母转为大写,其他字符不变.在其中我们利用字符分类函数先判断是否为小写字母,如果是利用ASCII
#include<stdio.h>
#include<ctype.h>//引用单个字符分类函数的头文件
int main()
{
int i = 0;
char str[] = "Test String.\n";
char c;
while (str[i])
{
c = str[i];
if (islower(c))
c -= 32;
putchar(c);
i++;
}
return 0;
}
在这里我们先用字符分类函数islower来判断是否为小写字母,然后利用大写字符与小写字符的关系:大写字符=小写字符-32,来将小写字符转换成大写字符,已完成题目要求。
(二)、字符转换函数
- 这里C语言库提供了两个字符转换函数:
int tolower ( int c ); //将参数传进去的⼤写字⺟转⼩写
int toupper ( int c ); //将参数传进去的⼩写字⺟转⼤写
- 就这上面的题目将字符串中的小写字母改成大写字母,我们还可以调用toupper函数来实现,代码如下:
#include <stdio.h>
#include <ctype.h>
int main (){
int i = 0;
char str[] = "Test String.\n";
char c;while (str[i]){c = str[i];
if (islower(c))
c = toupper(c);
putchar(c);
i++;}
return 0;}
二、针对字符串的C语言库中的函数
在使用这些函数前要引用头文件<string.h>!
(一)、strlen函数
- strlen函数的函数原型为:
size_t strlen ( const char * str );
- strlen函数是统计字符串中’\0’前面出现的字符个数(不包括’\0’)
- 关于strlen函数注意以下几点:
参数指向的字符串必须要有’\0’为结束;
注意函数的返回值为size_t,是无符号的;
strlen的使用需要包含头文件<string.h>; - strlen函数的使用:
#include <stdio.h>
#include <string.h>
int main(){const char* str1 = "abcdef";const char* str2 = "bbb";if(strlen(str2)-strlen(str1)>0){printf("str2>str1\n");}
else{printf("srt1>str2\n");}return 0;}
显然结果是
这里我们通过比较str1和str2字符串字符的字符个数来决定输出的是什么。
- strlen函数的三种模拟实现:
第一种:计数器的方法。
#include <stdio.h>
#include<assert.h>
size_t my_strlen(counst char*str)
{
size_t count=0;
assert(str);//判断一下传入的是否为空指针。
while(*str)
{
count++;
str++;
}
return count;
}
int main(){const char* str1 = "abcdef";const char* str2 = "bbb";if(my_strlen(str2)-my_strlen(str1)>0){printf("str2>str1\n");}
else{printf("srt1>str2\n");}return 0;}
我们通过定义一个count变量,当str指针没有遇到’\0’的时候,每count++,就有str++,来记录跳过的字符个数。
第二种:不临时创建变量计数器,利用递归的方法
#include <stdio.h>
#include<assert.h>
size_t my_strlen(counst char*str)
{
assert(str);
if(*str=='\0')
{
return 0;
}
else
{
return 1+my_strlen(str+1);
}
}
int main(){const char* str1 = "abcdef";const char* str2 = "bbb";if(my_strlen(str2)-my_strlen(str1)>0){printf("str2>str1\n");}
else{printf("srt1>str2\n");}return 0;}
在这里利用函数递归的方法,将str=='\0’为递归结束的条件,str+1为不断逼近成递归结束的方式。
(二)、strcpy函数
- strcpy函数的函数原型:
char* strcpy(char * destination, const char * source );
- strcpy函数就是将source字符串中的内容完全拷贝到destination字符串中(包括source字符串中的终止字符’\0’,并以终止字符为拷贝结束的标志)
- 关于strcpy函数注意以下几点:
源(source)字符串中必须以’\0’结束;
拷贝的时候会将源字符串(source)中’\0’也拷贝到目标空间中(destination);
目标空间必须足够大,确保能存放下源字符串;
目标空间必须可以修改,不然拷贝不会成功; - strcpy函数的使用:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[]="abcedef";
char arr2[20]="0";//注意这个字符串必须足够大
strcpy(arr2,arr1);
printf("%s",arr2);
return 0;
}
这里我们将arr1的内容拷贝到arr2中去,注意这里arr2数组必须要足够大,能够接收arr1数组中的内容。
- strcpy函数的模拟实现:
#include<stdio.h>
#include<assert.h>
char*my_strcpy(char*dest,const char*src)
{assert(dest && src);//加上一个断言避免空指针问题char* ret = dest;//记录起始地址while (*src != '\0'){*dest = *src;src++;dest++;}*dest = *src;//将\0赋过去return ret;
}
int main()
{
char arr1[]="abcedef";
char arr2[20]="0";//注意这个字符串必须足够大
my_strcpy(arr2,arr1);
printf("%s",arr2);
return 0;
}
这里我们只需要利用指针遍历字符串,将src的字符一个一个的赋给dest即可,最后再将’\0’复制过去。
对于以上代码可以化为间接版本:
#include<stdio.h>
#include<assert.h>
char*my_strcpy(char*dest,const char*src)
{assert(dest && src);//加上一个断言避免空指针问题char* ret = dest;//记录起始地址while (*dest++=*src++)//虽然++的优先级高于*,但是为后置++、现解引用再++,赋值过后判断表达式的值,同时解决了直接\0直接拷贝到目标空间里{;}return ret;
}
int main()
{
char arr1[]="abcedef";
char arr2[20]="0";//注意这个字符串必须足够大
my_strcpy(arr2,arr1);
printf("%s",arr2);
return 0;
}
(三)、strcat函数
- strcat的函数原型:
char *my_strcat(char *destination, const char*source);
- strcmp函数是将源字符串追加到目标空间的末尾(这个末尾是指第一个’\0’的后面)
- 对于strcmp函数注意以下几点:
源字符串中也得有\0,否则没办法知道追加从哪里开始;
目标空间必须足够的大,能容下源字符串的内容;
目标空间必须可以修改; - strcmp函数的使用:
#include<stdio.h>
#include<string.h>
int main()
{char arr1[20] = "hello ";char arr2[20] = "word";char* ret=strcat(arr1, arr2);printf("%s\n", arr1);
}
结果如下:
显然做到了将arr2追加到arr1字符串后面的作用。
- strcat函数的模拟实现:
#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
//整体分为两步:第一步找\0的位置;第二步拷贝代码char* ret = dest;//记录返回的位置assert(dest && src);while (*dest!='\0')//找\0{dest++;}while (*dest++=*src++)//拷贝代码{;}return ret;
}
int main()
{char arr1[20] = "hello ";char arr2[20] = "word";char* ret=my_strcat(arr1, arr2);printf("%s\n", arr1);
}
(四)、strcmp函数
- 函数原型:
int strcmp ( const char * str1, const char * str2 );
- strcmp函数开始比较每个字符串的第一个字符。如果它们是相等,继续比较下一个字符,
直到字符不同或直到结束达到空字符。字符不同时候,字符ASCII值大的代表整个字符串大。 - 对于strcmp函数注意以下几点:
第一个字符串大于第二个字符串,则返回大于0的数字;
第一个字符等于第二个字符,则返回0;
第一个字符小于第二个字符,则返回小于0的数字; - strcmp函数的使用
#include<stdio.h>
#include<string.h>
int main()
{char arr1[]= "abq";char arr2[]="abcdef";int ret = strcmp(arr1, arr2);//比较的是对应位置的ascii码值printf("%d ", ret);
}
返回的是大于0的数字,显然是第一个字符串大于第二个字符串。
- strcmp函数的模拟实现:
#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{assert(str1 && str2);//判断指针是否为空while (*str1==*str2){if (*str1 == '\0')//比较到结束,如果还相等,那么两个字符串相等{return 0;}str1++;str2++;}return (*str1-*str2);
}int main(){char arr1[]= "abq";char arr2[]="abcdef";int ret = my_strcmp(arr1, arr2);//比较的是对应位置的ascii码值printf("%d ", ret);}
(五)、strncpy函数
- 函数原型:
char * strncpy ( char * destination, const char * source, size_t num );
- 拷贝num个字符从源字符串到目标空间,如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边,直到num个。
- 函数的使用:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20]={0};
char arr2[20]="abcde";
strncpy(arr1,arr2,4);
printf("%s",arr1);
}
此结果只显示前4个字符。
(六)、strncat函数
- 函数原型:
char * strncat ( char * destination, const char * source, size_t num );
- 将source指向字符串的前num个字符追加到destination指向的字符串末尾,再追加⼀个
符’\0’ - 如果source 指向的字符串长度小于num的时候,只会将字符串中到’\0’的内容追加到destination指向的字符串末尾。
- 函数的使用:
#include<stdio.h>
#include<string.h>
int main()
{char str1[20];char str2[20];strcpy (str1,"To be ");strcpy (str2,"or not to be");strncat (str1, str2, 6);printf("%s\n", str1);return 0;
}
结果只是将str2前6个字符追加到str1的末尾。
(七)、strncmp函数
- 函数原型:
int strncmp ( const char * str1, const char * str2, size_t num );
- ⽐较str1和str2的前num个字符,如果相等就继续往后⽐较,最多⽐较num个字⺟,如果提前发现不⼀样,就提前结束,⼤的字符所在的字符串⼤于另外⼀个。如果num个字符都相等,就是相等返回0.
比较返回结果如下:
- 函数的使用:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20]="abcdef";
char arr2[20]="abcqfe";
printf("%d\n",strncmp(arr1,arr2,4));
printf("%d\n",strncmp(arr1,arr2,3));
return 0;}
如果只比较前三个字符,则两个字符串相等,如果比较前4个字符则d的ASCII值比q的ASCII值小,故而代表第一个字符串比第二个字符串小。
(八)、strstr函数
- 函数介绍:
函数原型: char * strstr ( const char * str1, const char * str2);
这是一个找字串的函数,函数的作用是返回字符串str2在字符串str1中第一次出现的位置,字符串比较匹配不包含‘\0’字符,以‘\0’作为结束标志。 - 函数的使用:
#include <stdio.h>
#include <string.h>
int main (){char str[] ="This is a simple string";char * pch;pch = strstr (str,"simple");strncpy (pch,"sample",6);//从printf("%s\n", str);return 0;}
这里我们调用strstr函数后 返回的是simple中s字符的位置,然后将sample复制到simple的位置,最后打印出str为如图结果。
- 函数的模拟实现BF算法(暴力破解)
代码如下:
#include<stdio.h>
#include<assert.h>
const char* my_strstr(const char* str1, const char* str2)
{//场景1:一次就能匹配成功//场景2:多次匹配才能成功assert(str1 && str2);const char* s1 = NULL;const char* s2 = NULL;const char* cur = str1;//记录str1当前比较的初始位置if (*str2 == '\0')//注意解引用{return str1;}while (*cur != '\0'){s1 = cur;//执行str1运动过程s2 = str2;//执行str2运动过程while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2){s1++;s2++;}if (*s2 == '\0'){return cur;}cur++;}return NULL;
}
//strstr找字符串字串函数的使用:
int main()
{char arr1[] = "abcefab";char arr2[] = "bc";const char* ret = my_strstr(arr1, arr2);if (ret == NULL){printf("不存在");}else{printf("%s\n",ret);}
}
我们实现的是依据BF暴力破解算法,
- 函数的模拟实现KMP算法(优化)
代码实现:
#include<stdio.h>
#include<assert.h>
void GetNext(char s[], int next[]) {int len = 0;len = strlen(s);next[0] = 0;//以下标为0的字符结尾的字符串的相同前后缀为0int j = 0;//指向前缀末尾位置//i:指向后缀末尾位置for (int i = 1; i < len; i++)//从1开始是因为0的位置已经赋值{while (j > 0 && s[j] != s[i]) {//前后缀末尾不相同时,前缀位置向前回退j = next[j - 1];//j回退到以下标为j-1的字符结尾的字符串的最长相同前后缀的前缀的下一个位置}if (s[j] == s[i]) {//前后缀末尾相同j++;}next[i] = j;//以下标为i的字符结尾的字符串的相同前后缀的长度}
}
const char* my_strstr(const char* s1, const char* s2)
{
int len1 = 0;
len1 = strlen(s1);
int len2 = 0;
int next[1000] = { NULL };
len2 = strlen(s2);
if (len2 == 0) { return 0; }
GetNext(s2, next);
int j = 0;
for (int i = 0; i < len1; i++)
{while (j > 0 && s2[j] != s1[i]) {j = next[j - 1];//next下标对应的值十当j+1不对应相等的时候,在s2中返回的位置}if (s2[j] == s1[i]) { j++;if (j == len2) {char* cur = &s1[i - j + 1];return cur;}}
}
return NULL;
}
void test1()
{char arr1[] = { NULL };char arr2[] = { NULL };while (scanf("%s %s", &arr1, &arr2) != EOF){if (arr1[0]=='0'&&arr2[0]=='0') {break;}if (my_strstr(arr1, arr2) != NULL){printf("%s\n", my_strstr(arr1, arr2));}else{printf("不存在\n");}}
}
int main()
{test1();
}
(九)、strtok函数
- 这个函数不常见,实现起来有一些困难,这里我们只介绍其使用
- 函数原型:
char * strtok ( char * str, const char * sep);
- 关于strtok函数注意以下几点:
sep参数指向了一个字符串,定义了用作分隔符的字符的集合;
第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记;
strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针(注意:strtok会改变被操作的字符串,所以strtok函数切分的字符串一般都是临时拷贝的内容并且都是可以修改的);
若strtok函数的第一个参数不为NULL,函数找到str中的第一个标记,strtok函数将保存它在字符串中的位置;
若strtok函数的第一个参数为NULL,则函数将会在同一个字符串中被保存的位置开始,查找下一个标记;
如果字符串中不存在更多的标记,则返回NULL指针。 - 函数的使用:
#include<stdio.h>
#include<string.h>
int main()
{char arr1[] = "zpengwei@year.net";char buf[256] = { 0 };strcpy(buf, arr1);char sep[] = "@.";//务必是字符串for (char* ret=strtok(buf,sep); ret !=NULL; ret=strtok(NULL,sep)){printf("%s", ret);printf("\n");}
}
很显然这里的strtok具有记忆功能,这个函数就第二个参数中分隔符来将第一个参数代表的字符串进行分割。
(十)、strerror函数
- 函数原型:
char* strerror ( int errnum );
- strerror 函数可以把部分错误码对应的错误信息的字串串地址返回来
- 在不同的系统和c语言标准库中都规定了一些错误码,一般放在errno.h这个头文件中的,C语言程序启动的时候就会用一个全局变量errno来记录程序当前的错误码(要引用头文件errno.h),只是当程序启动的时候errno是0,表示没有错误,当我们在使用标准库中的函数发生了某种错误,就会将对应的错误码,存放在errno中,而一个错误码的数字是整数很难理解什么意思,所以每一个错误码都是有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。
- 对应代码举例:
#include<stdio.h>
#include<string.h>
int main()
{
for(int i =0;i<=10;i++)
{
printf("%s\n",strerror(i));
}
return 0;
}
结果如图显示:
如上图所示每一行代表出错的原因。
下面写一个打开文件失败的代码,并显示错误原因:
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE*pFile;//定义文件变量
pFile=fopen("rist.txt","r");//读操作打开文件
if(pFile==NULL)
printf("Error opening file rist.txt:%s\n",strerror(errno));//将错误放在errno变量里(全局变量)
return 0;
}
结果如图显示:
- 我们利用perror函数(头文件stdio.h),perror函数会打印参数字符串,冒号,空格,错误信息。
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE*pFile;//定义文件变量
pFile=fopen("rist.txt","r");//将文件以读操作打开
if(pFile==NULL)
{
printf("Error opening file rist.txt:%s\n",strerror(errno));//将错误码存到errno里然后打印出错误信息。
perror("Error opening file rist.txt\n");//等效于printf函数和strerror函数的结合使用。
}
}
结果如下:
很显然这里perror函数就等效于printf函数和strerror函数的作用。
总结
本文主要介绍C语言库中针对单个字符的函数以及针对字符串的函数的使用细则以及模拟实现。感谢支持,如有错误请批评指正。