C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中。
字符串常量适用于那些对它不做修改的字符串函数
前言:
目录:
1、strlen函数
1.1strlen函数的定义
1.2、模拟实现strlen函数
2、长度不受限制的字符串函数
2.1、strcpy函数
2.1.1、strcpy函数的介绍
2.1.2、模拟实现strcpy函数
2.2、strcat函数
2.2.1、strcat函数的介绍
2.2.2、模拟实现strcat函数
2.3、strcmp函数
2.3.1、strcmp函数介绍
2.3.2、strcmp函数的模拟实现
3、长度受限制的字符串函数
3.1、strncpy函数
3.1.1、strncpy函数的介绍
3.1.2、strncpy函数的模拟实现
3.2、strncat函数
3.2.1、strncat函数的介绍
3.2.2、strncat函数的模拟实现
3.3、strncmp函数
3.3.1、strncmp函数的介绍
3.3.2、strncmp函数的模拟实现
4、字符串查找函数
4.1、strstr函数
4.1.1、strstr函数的介绍
4.1.2、strstr函数的模拟实现
4.2、strtok函数
4.2.1、strtok函数的介绍
5、错误信息报告函数
5.1、strerror函数
5.1.1、strerror函数的介绍
5.2、perror函数
5.2.1、perror函数的介绍
6、字符分类函数
计算字符串长度的函数
size_t strlen ( const char * str );
1>、 头文件:#include
2>、strlen计算字符串的长度,字符串以' \0 '做为结束标志,strlen返回的是' \0 '之前出现 的字符个数(不包含' \0 ')。
3>、【参数说明】str是指针,指向被求长度的字符串
参数指向的字符串必须要包含' \0 '。
4>、【返回类型】size_t 在vs编译器中对unsigned int 重新起了一个名字(无符号整型)。
strlen函数的返回值是一个无符号整型。
5>、const 修饰:源字符串参数用const修饰,防止修改源字符串。
代码演示:
#include
#include
int main()
{
char arr[] = "abcdef";
int ret = strlen(arr);
printf("%d\n",ret);
return 0;
}
#include
#include
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;
}
字符串拷贝函数
char* strcpy ( char* destination , const char* source);
1>、头文件:#include
2>、srtcpy功能:将源头空间的字符串拷贝到目的地空间中;
源字符串必须以' \0 '结束;
在拷贝时会将源字符串中的' \0 '拷贝到目标空间;
目标空间必须足够大,以确保能够存放源字符串;
目标空间必须可修改。
3>、参数:
destination:指向要复制内容的目标数组的指针。
source:要复制的字符串
4>、返回值:返回目标空间中字符串起始地址。
错误代码演示:
#include
#include 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用作拷贝结束。
#include
#include
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指向的是源头空间,
字符串追加函数
char* strcat (char* destination , const char* source);
1>、头文件:#include
2>、【功能】将源空间中的字符串追加到目的空间中,源空间的字符串从目的空间字符串的 \0的位置开始追加。
源字符串必须以' \0 '结束。
目标空间必须有足够大,能容纳下源字符串的内容。
目标空间必须可修改。
3>、【参数】destination:目标空间
source:源头空间
4>、【返回值】返回目标空间中字符串的起始地址
代码演示:
#include
#include
int main()
{
char arr1[20] = "hello";
char arr2[] = "world";
strcat(arr1,arr2);//字符串追加函数
printf("%s\n",arr1);
return 0;
}
注释:目标空间想要在那个位置追加字符串,就在那个位置用\0 标记,追加函数会从
\0的位置追加字符串.追加的时候会覆盖目的空间字符串中的\0.
strcat函数不能用作自己给自己追加,因为给自己追击字符串,会将字符串中的\0覆盖,所以字符串追加不会停止。
字符串比较函数
int strcmp (const char* str1,const char* str2);
1>、头文件:#include
2>、【功能】将指针str1指向的字符串于指针str2指向的字符串进行比较,比较对应位置字 符的ASCII码值的大小。
函数开始比较每个字符串的第一字符。如果他们彼此相等,则继续循环执行该 操作,直到字符不同或者达到终止空字符。
3>、【参数】str1指针指向第一个比较的字符串
str2指针指向第二个比较的字符串
4>、【返回值】返回一个整数值,该值指示字符串之间的关系:
第一个字符串大于第二个字符串,则返回大于0的数字;
第一个字符串等于第二个字符串,则返回0;
第一个字符串小于第二个字符串,则返回小于0的数字。
代码演示:
#include
#include
int main()
{
char arr1[] = "abcdef";//arr1第三个字符'c'小于arr2中的'd'
char arr2[] = "abd";
int ret = strcmp(arr1,arr2);//所以返回小于一个小于0的数子
printf("%d\n",ret);
return 0;
}
#include
#include
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("arr10)
printf("arr1>arr2\n");
else
printf("arr1 == arr2");
printf("%d\n",ret);//输出ret的值
return 0;
}
总结:
strcpy、strcat、strcmp着三个函数都和\0都有关系,所以这一组函数在C语言中被我们叫做长度不受限制的字符串函数
字符串拷贝函数
char * strncpy ( char * destination, const char * source, size_t num );
1>、头文件:#include
2>、【功能】拷贝num个字符从源字符串到目标空间。如果源字符串的长度小于num,则 拷贝完源字符串之后,在目标的后边追加0,直到num个,前提是要保证目标 空间可以存放。
3>、参数:destination:指向要复制内容的目标数组的指针。
source:指向要拷贝的源头字符
num:要从源代码复制的最大字符数。size_t是无符号整型。
4>、返回值:返回目标空间中字符串起始地址。
代码演示:
#include
#include
int main()
{
char arr1[20] = "abcdef";
char arr2[] = "xxxx";
strncpy(arr1, arr2, 2);
printf("%s\n", arr1);
return 0;
}
#include
#include
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;
}
字符串追加函数
char * strncat ( char * destination, const char * source, size_t num );
1>、头文件:#include
2>、【功能 】将源头空间的前num个字符追加到目标空间,从目标空间的\0开始追加,外 加一个终止控字符\0。
3>、参数:destination:指向要在其中复制内容的目标数组的指针
source:要追加的源头字符
num:要从源头追加的最大字符数。 size_t:是无符号整型类型
4>、【返回值】:返回目标空间中字符串起始地址
代码演示:
#include
int main()
{
char arr1[20] = "abcdef\0qqqqq";
char arr2[] = "xyz";
strncat(arr1,arr2,2);
printf("%s\n",arr1);
return 0;
}
#include
#include
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);
}
字符串比较函数
int strncmp ( const char * str1 , const char * str2 , size_t num);
1>、头文件:#include
2>、【功能】将字符串str1与str2前num个字符进行比较,比较对应位置的字符大小。
这个函数开始比较每个字符串的第一个字符。
如果它们相等,则继续执行该操作,直到字符不同,直到到达一个终止的null 字符,
或者直到两个字符串中的num字符匹配,以先发生的情况为准。
3>、参数
str1:指向要比较字符串str1
str2:指向要比较字符串str2
num:要比较的最大字符数,size_t:无符号整型
4>、【返回值】返回一个整数值,表示字符串之间的关系
返回值 表明 < 0 第一个不匹配的字符在str1中的值小于str2中的值
0 两个字符串的内容是相等的
> 0 第一个不匹配的字符在str1中的值大于str2中的值
代码演示:
#include
#include
int main()
{
int ret = strncmp("abcdefg", "abd", 4);
printf("%d\n", ret);
return 0;
}
#include
#include
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);
}
char* strstr ( char* str1 , const char* str2);
1>、头文件:#include
2>、【功能】在一个字符串中找另外一个字符串是否存在,若存在,返回的子串第一次出现 的位置;若不存在,返回NULL。
3>、【返回值】指向str2中指定的整个字符序列中str1中第一个出现的字符的指针,如果 str1中没有该序列,则为空指针(NULL)。
代码演示:
#include
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;
}
#include
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用来遍历子串.
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
#include
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
#include
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;
}
char* strerror ( int errnum ) ;
【功能】将错误码转化为错误信息
【参数】errnum:错误号,会把错误码记录到相应的错误号中
【返回值】指向描述错误的错误字符串的指针。
代码演示:
#include
#include
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
#include
#include
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语言提供的全局的错误变量,将错误码记录到错误码的变量中
void perror ( const char * str) ;
【功能】打印系统错误信息
代码演示:
#include
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。
函数 | 如果他的参数符合下列条件就返回真 |
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
#include
int main()
{
char ch ='ad';
int ret =isdigit(ch);//判断是否为数字字符,如果是非数字字符返回0
printf("%d\n",ret);
}