前言:
C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中。
字符串常量适用于那些对它不做修改的字符串函数
1、strlen函数
1.1strlen函数的定义
计算字符串长度的函数
size_t strlen ( const char * str );
1>、 头文件:#include<string.h>
2>、strlen计算字符串的长度,字符串以' \0 '做为结束标志,strlen返回的是' \0 '之前出现 的字符个数(不包含' \0 ')。
3>、【参数说明】str是指针,指向被求长度的字符串
参数指向的字符串必须要包含' \0 '。
4>、【返回类型】size_t 在vs编译器中对unsigned int 重新起了一个名字(无符号整型)。
strlen函数的返回值是一个无符号整型。
5>、const 修饰:源字符串参数用const修饰,防止修改源字符串。
代码演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "abcdef";
int ret = strlen(arr);
printf("%d\n",ret);
return 0;
}
1.2、模拟实现strlen函数
#include<stdio.h>
#include<assert.h>
size_t my_strlen(const char* str)
{
assert(str);//防止传过来的指针为空指针
const char* start = str;//将字符串的起始地址传给指针start
const char* end = str;//给指针start和end前加const,作用是保证和指针str的范围相同
while(*end != '\0')
{
end++;
}
return end - start;//用指针-指针来计算字符串的长度
}
int main()
{
char arr[] = "abcdef";
int len = my_strlen(arr);
printf("%d\n",len);
return 0;
}
2、长度不受限制的字符串函数
2.1、strcpy函数
2.1.1、strcpy函数的介绍
字符串拷贝函数
char* strcpy ( char* destination , const char* source);
1>、头文件:#include<string.h>
2>、srtcpy功能:将源头空间的字符串拷贝到目的地空间中;
源字符串必须以' \0 '结束;
在拷贝时会将源字符串中的' \0 '拷贝到目标空间;
目标空间必须足够大,以确保能够存放源字符串;
目标空间必须可修改。
3>、参数:
destination:指向要复制内容的目标数组的指针。
source:要复制的字符串
4>、返回值:返回目标空间中字符串起始地址。
错误代码演示:
#include<stdio.h> #include<string.h> int main() { //情景一、目标空间要足够大、否则会发生越界访问 char arr[10] = "xxxxxxxxxx";//目标空间 const char* p = "abcdef";//要拷贝的字符串 strcpy(arr,p);//使用函数进行拷贝 printf("%s\n",arr); //情景二、目标空间必须可修改。 char* p = "hello worle";//常量字符串不可修改 char arr2[] = "abcdef"; strcpy(p,arr2); printf("%s\n", p); return 0; }
情景三、源字符串必须以' \0 '结束
当arr2中没有字符\0时,vs编译器中不能通过,所以在源字符串中必须有字符\0用作拷贝结束。
2.1.2、模拟实现strcpy函数
#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* dest,const char* src)//dest指向目的地空间,src指向源头空间
{
assert(dest);
assert(src);
char* ret = dest;//将dest的起始位置放在ret中。
while(*dest++ = *src++)//将源头空间中的字符一个一个都拷贝到目的空间中
{
;
}
return ret;//返回目标空间的起始地址
}
int main()
{
char arr[20] = "abc";
char arr2[] = "hello world";
my_strcpy(arr,arr2);
printf("%s\n",arr);
//printf("%s\n", my_strcpy(arr,arr2));因为 my_strcpy函数的返回值是目标空间的起始地
//址,将 my_strcpy函数作为printf函数的参数,叫做函数的链式访问。
return 0;
}
注释:指针dest指向的是目的空间,指针src指向的是源头空间,
2.2、strcat函数
2.2.1、strcat函数的介绍
字符串追加函数
char* strcat (char* destination , const char* source);
1>、头文件:#include<string.h>
2>、【功能】将源空间中的字符串追加到目的空间中,源空间的字符串从目的空间字符串的 \0的位置开始追加。
源字符串必须以' \0 '结束。
目标空间必须有足够大,能容纳下源字符串的内容。
目标空间必须可修改。
3>、【参数】destination:目标空间
source:源头空间
4>、【返回值】返回目标空间中字符串的起始地址
代码演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "hello";
char arr2[] = "world";
strcat(arr1,arr2);//字符串追加函数
printf("%s\n",arr1);
return 0;
}
2.2.2、模拟实现strcat函数
注释:目标空间想要在那个位置追加字符串,就在那个位置用\0 标记,追加函数会从
\0的位置追加字符串.追加的时候会覆盖目的空间字符串中的\0.
strcat函数不能用作自己给自己追加,因为给自己追击字符串,会将字符串中的\0覆盖,所以字符串追加不会停止。
2.3、strcmp函数
2.3.1、strcmp函数介绍
字符串比较函数
int strcmp (const char* str1,const char* str2);
1>、头文件:#include<string.h>
2>、【功能】将指针str1指向的字符串于指针str2指向的字符串进行比较,比较对应位置字 符的ASCII码值的大小。
函数开始比较每个字符串的第一字符。如果他们彼此相等,则继续循环执行该 操作,直到字符不同或者达到终止空字符。
3>、【参数】str1指针指向第一个比较的字符串
str2指针指向第二个比较的字符串
4>、【返回值】返回一个整数值,该值指示字符串之间的关系:
第一个字符串大于第二个字符串,则返回大于0的数字;
第一个字符串等于第二个字符串,则返回0;
第一个字符串小于第二个字符串,则返回小于0的数字。
代码演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abcdef";//arr1第三个字符'c'小于arr2中的'd'
char arr2[] = "abd";
int ret = strcmp(arr1,arr2);//所以返回小于一个小于0的数子
printf("%d\n",ret);
return 0;
}
2.3.2、strcmp函数的模拟实现
#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* str1 , const char* str2)
{
assert(str1)
assert(str2)//防止str1和str2为空指针
while(*str1 == *str2)//当两个空间的字符相等时,进入下边的空间
{
if(*str1 == '\0')//这个判断基于两个字符串\0之前的字符都相等这里*str1 == *str2,
//所以判断一个即可
{
return 0;
}
str1++;
srt2++;
}
if(*str1 > *str2)
return 1;
else
return -1;
//return *str1-*str2; 可以用这句代码简化上述的返回值代码
}
int main()
{
char arr1[] = "abc";
char arr2[] = "abd";
int ret = my_strcmp(arr1,arr2);
if(ret<0)
printf("arr1<arr2\n");
else if(ret>0)
printf("arr1>arr2\n");
else
printf("arr1 == arr2");
printf("%d\n",ret);//输出ret的值
return 0;
}
总结:
strcpy、strcat、strcmp着三个函数都和\0都有关系,所以这一组函数在C语言中被我们叫做长度不受限制的字符串函数
3、长度受限制的字符串函数
3.1、strncpy函数
3.1.1、strncpy函数的介绍
字符串拷贝函数
char * strncpy ( char * destination, const char * source, size_t num );
1>、头文件:#include<string.h>
2>、【功能】拷贝num个字符从源字符串到目标空间。如果源字符串的长度小于num,则 拷贝完源字符串之后,在目标的后边追加0,直到num个,前提是要保证目标 空间可以存放。
3>、参数:destination:指向要复制内容的目标数组的指针。
source:指向要拷贝的源头字符
num:要从源代码复制的最大字符数。size_t是无符号整型。
4>、返回值:返回目标空间中字符串起始地址。
代码演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "abcdef";
char arr2[] = "xxxx";
strncpy(arr1, arr2, 2);
printf("%s\n", arr1);
return 0;
}
3.1.2、strncpy函数的模拟实现
#include<stdio.h>
#include<assert.h>
char* my_strncpy(char* dest,const char* src,size_t num)
{
assert(dest&&src);
char* ret = dest;
while(num&&(*dest++ = *src++)!='\0')
{
num--;
}
if(num)//当num大于src的长度时,将补充空字符
{
while(--num)
{
*dest++ = '\0';
}
}
return ret;
}
int main()
{
char arr[20] = "abcdefg";
char arr2[] = "xxxx";
my_strncpy(arr,arr2,6);
printf("%s\n",arr);
//printf("%s\n", my_strcpy(arr,arr2))
return 0;
}
3.2、strncat函数
3.2.1、strncat函数的介绍
字符串追加函数
char * strncat ( char * destination, const char * source, size_t num );
1>、头文件:#include<string.h>
2>、【功能 】将源头空间的前num个字符追加到目标空间,从目标空间的\0开始追加,外 加一个终止控字符\0。
3>、参数:destination:指向要在其中复制内容的目标数组的指针
source:要追加的源头字符
num:要从源头追加的最大字符数。 size_t:是无符号整型类型
4>、【返回值】:返回目标空间中字符串起始地址
代码演示:
#include<stdio.h>
int main()
{
char arr1[20] = "abcdef\0qqqqq";
char arr2[] = "xyz";
strncat(arr1,arr2,2);
printf("%s\n",arr1);
return 0;
}
3.2.2、strncat函数的模拟实现
#include<stdio.h>
#include<assert.h>
char* my_strncat(char* s1, const char* s2,size_t num)
{
assert(s1&&s2);
char* src = s1;
while(*s1)//对s1解引用,用字符对应的ASCII码值进行判断
{
s1++ ;//地址后移
}
while(num--)
{
*s1++ = *s2++;
}
*s1 ='\0';//追加完成后给指针s1指向的空间后边添加\0
return src;
}
int main()
{
char arr1[20]="xxxxxx\0xxxxxx";
char arr2[]="hijk";
char* ret = my_strncat(arr1,arr2,4);
printf("%s\n",ret);
}
3.3、strncmp函数
3.3.1、strncmp函数的介绍
字符串比较函数
int strncmp ( const char * str1 , const char * str2 , size_t num);
1>、头文件:#include<string.h>
2>、【功能】将字符串str1与str2前num个字符进行比较,比较对应位置的字符大小。
这个函数开始比较每个字符串的第一个字符。
如果它们相等,则继续执行该操作,直到字符不同,直到到达一个终止的null 字符,
或者直到两个字符串中的num字符匹配,以先发生的情况为准。
3>、参数
str1:指向要比较字符串str1
str2:指向要比较字符串str2
num:要比较的最大字符数,size_t:无符号整型
4>、【返回值】返回一个整数值,表示字符串之间的关系
返回值 表明 < 0 第一个不匹配的字符在str1中的值小于str2中的值
0 两个字符串的内容是相等的
> 0 第一个不匹配的字符在str1中的值大于str2中的值
代码演示:
#include<stdio.h>
#include<string.h>
int main()
{
int ret = strncmp("abcdefg", "abd", 4);
printf("%d\n", ret);
return 0;
}
3.3.2、strncmp函数的模拟实现
#include<stdio.h>
#include<assert.h>
int my_strncmp(const char* str1, const char* str2, size_t num)
{
assert(str1 && str2);
while (num&&(*str1 == *str2))//因为num是无符号整型,范围是0~65535,while(0)不进行内部
//程序
{
if (*str1 == '\0')
{
return 0;
}
str1++;
str2++;
num--;
}
}
int main()
{
char arr1[] = "abcde";
char arr2[] = "abd";
int ret = my_strncmp(arr1, arr2, 4);
printf("%d\n", ret);
}
4、字符串查找函数
4.1、strstr函数
4.1.1、strstr函数的介绍
char* strstr ( char* str1 , const char* str2);
1>、头文件:#include<string.h>
2>、【功能】在一个字符串中找另外一个字符串是否存在,若存在,返回的子串第一次出现 的位置;若不存在,返回NULL。
3>、【返回值】指向str2中指定的整个字符序列中str1中第一个出现的字符的指针,如果 str1中没有该序列,则为空指针(NULL)。
代码演示:
#include<stdio.h>
int main()
{
char arr[] = "abcdefabcdef";
char arr2[] = "cde";
char* p = strstr(arr, arr2);
if (p == NULL)
{
printf("不存在\n");
}
else
{
printf("%s\n", p);
}
return 0;
}
4.1.2、strstr函数的模拟实现
#include<stdio.h>
char* my_strstr(const char* str1, const char* str2)
{
const char* s1 = str1;
const char* s2 = str2;
const char* p = str1;
while (*p)//p代表指向的是在总串中与子串第一次出现相同元素的地址
{
s1 = p;
s2 = str2;
while (*s1!='\0'&&*s2!='\0'&&(*s1 == *s2))
{
s1++;
s2++;
}
if (*s2 == '\0')//s2指向要查看的字符序列,若*s2=='\0',则子串结束,表示找到了
{
return p;
}
p++;//代表当前p指向的并不是子串第一次出现的首元素地址,指向的地址要往后跳一个字节
}
return NULL;//找不到子串
}
int main()
{
char arr[] = "abcdefabcdef";
char arr2[] = "cde";
char* p = my_strstr(arr, arr2);
if (p == NULL)
{
printf("不存在\n");
}
else
{
printf("%s\n", p);
}
return 0;
}
1、用指针s1、str1、p都指向第一个字符串首地址,
1>、str1用作接收数组arr传过来的地址,
2>、s1用来遍历寻找,与子串相同的字符,
3>、p用来标记s1找到的与子串相同字符的首地址,当前边相同后边有不同时,让s1能 够返回到p开始标记的地址,当进行完一次查找后,没在总串中找到子串相对应的 元素p向后移动一位,如此循环直到p在总串中找到字符\0,查找结束,返回NULL。
2、用指针str2、s2都指向第二个字符串的首地址。
1>、str2用作接收arr2传过来的地址,当没有在总串中找到子串,用str2将s2带到字符 串首地址。
2>、s2用来遍历子串.
4.2、strtok函数
4.2.1、strtok函数的介绍
char* strtok (char* str ,const char* sep);
【参数】
1>、str:第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个 分隔符分割的标记。
2>、sep参数是个字符串,定义了用分隔符的字符集合
【工作原理】
1>、strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针。 (注:strtock函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都 是临时拷贝的内容并且可以修改。)
2>、strtok函数的第一个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存 它在字符串中的位置。
3>、strtok函数的第一个参数为NULL,函数将在同一个字符串中被保存的位置开始,查找 下一个标记。
4>、如果字符串中不存在更多的标记,则返回NULL指针。
【返回值】
1>、如果找到分隔符,则返回为指向该字符串开头的指针,否则,为空指针。
2>、当在扫描的字符串中到达字符串的末尾(即空字符)时,始终返回空指针。
代码演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "adfadj@lsalji,sdj";
char buf[200] = { 0 };
strcpy(buf, arr);//将arr中的字符串拷贝到buf中,防止原字符串被修改。
const char* p = "@,";//标记字符串
char* str = strtok(buf, p);//第一次查找,第一个参数是非NULL,函数找到buf中第一个标记
//@,将其改为\0,strtok函数将@位置保存,然后strtok函数将字符串adfadj的首地址传给指针str。
printf("%s\n", str);
str = strtok(NULL, p);//第二次调用strtok时,第一个参数是NULL,strtok函数找到上一次保
//存的地址,向后寻找,直到找到',',将','改为\0并且保存其地址,返回字符串lsalji的首地址.
printf("%s\n", str);
str = strtok(NULL, p);//第三次调用strtok函数时,第一个参数为NULL,函数找到上一次保存的
//位置开始,查找下一个标记。并将字符串sbj的首地址穿个str.
printf("%s\n", str);
return 0;
}
将上述的代码优化:
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "adfadj@lsalji,sdj";
char buf[200] = { 0 };
strcpy(buf, arr);
const char* p = "@,";
char* str = NULL;
for (str = strtok(buf, p); str != NULL; str = strtok(NULL, p))
{
printf("%s\n", str);
}
return 0;
}
5、错误信息报告函数
5.1、strerror函数
5.1.1、strerror函数的介绍
char* strerror ( int errnum ) ;
【功能】将错误码转化为错误信息
【参数】errnum:错误号,会把错误码记录到相应的错误号中
【返回值】指向描述错误的错误字符串的指针。
代码演示:
#include<stdio.h>
#include<string.h>
int main()
{
printf("%s\n", strerror(0));//在这里我们将像0、1、2、3、4这样的数字叫做错误码,像我们
//看到的404就是一个错误码。404是http出错时的错误码,0、1、2、3、4是C语言中库函数报错时
//的错误码
printf("%s\n", strerror(2));//strerror函数返回的时候,若返回信息是字符串时,返回的是
//字符串的首地址
printf("%s\n", strerror(3));
printf("%s\n", strerror(4));
return 0;
}
使用场景:
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf = fopen("test.txt", "r");//当没有这个文件时fopen函数就会报错,将错误码放到
//errno这个变量中,然后strerror会将errno中的错误码进行翻译
if (pf == NULL)
{
printf("%s\n", strerror(errno));//用函数strerror将errno中的错误码翻译成对应错误
//信息,返回错误信息对应的地址。
return 1;
}
//读文件
fclose(pf);
pf = NULL;
return 0;
}
//errno 是C语言提供的全局的错误变量,将错误码记录到错误码的变量中
5.2、perror函数
5.2.1、perror函数的介绍
void perror ( const char * str) ;
【功能】打印系统错误信息
代码演示:
#include<errno.h>
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("fopen ");//打印的依然是errno变量中错误码对应的错误信息,perror打印时“ ”
//中可以加一些自定义信息,它还会在自定义信息中加:和空格
return 1;
}
//读文件
fclose(pf);
pf = NULL;
return 0
perror打印时“ ” 中可以加一些自定义信息,它还会在自定义信息中加:和空格。
可以这样理解:perror=printf+strerror。
6、字符分类函数
函数 | 如果他的参数符合下列条件就返回真 |
iscntrl | 任何控制字符 |
isspace | 空白字符:空格' ',换页"\",换行'\n',回车'\r',制表符'\t'或者垂直制表符'\v' |
isdigit | 十进制数组0~9 |
isxdigit | 十六进制数字,包括所有十进制数字,小写字母a-f,大写字母A-F |
islower | 小写字母a~z |
isupper | 大写字母A~Z |
isalnum | 字母或者数字,a~z,A~Z,0~9 |
isalpha | 字母a~z或A~Z |
ispunct | 标点符号,任何不属于数字或者字母的图形字符(可打印) |
isgraph | 任何图形字符 |
isprint | 任何可打印字符,包括图形字符和空白字符 |
以isdigit函数为例:
【返回值】若参数为阿拉伯数字0~9,则返回非0值,否则返回0。
代码演示:
#include<stdio.h>
#include<ctype.h>
int main()
{
char ch ='ad';
int ret =isdigit(ch);//判断是否为数字字符,如果是非数字字符返回0
printf("%d\n",ret);
}