C语言——字符函数和字符串函数
1.字符分类函数
2.字符转换函数
3.strlen的使用和模拟实现
4.strcpy的使用和模拟实现
5.strcat的使用和模拟实现
6.strcmp的使用和模拟实现
7.strncpy的使用和模拟实现
8.strncat的使用和模拟实现
9.strncmp的使用
10.strstr的使用
11.strtok的使用
12.strerror的使用
1.字符分类函数
在C语言中有一系列的函数是专门做字符分类的
这些函数的头文件都是ctype.h
iscntrl : 任何控制字符
isspace : 空白字符:空格’ ‘,换页‘f’,换行‘\n’,回车’\r’,制表符’\t’或者垂直制表符‘\v’
isdigit :十进制数字0到9
isxdigit :十六进制数字,包括0到9,小写字母a到f,大写字母A到F
islower :小写字母a到z
isupper :大写字母A到Z
isalpha :字母a到z或字母A到Z
isalnum :字母或者数字,a到z,A到Z,0到9
ispunct :标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph :任何图形字符
isprint :任何可打印字符,包括图形字符和空白字符
在上面的函数中,如果符合后面的条件,就返回真
我们现在通过讲解一个函数,通过这个函数,我们同时也可以知道别的函数的用法
int islower(int c);
这个部分是用来判断参数部分c是否是小写字母
通过返回值来说明是否是小写字母,如果是小写字母,则返回非0的整数,不是小写字母,就返回0
接下来我们来写一个练习
练习:写一个代码,将字符串中的小写字母改为大写,其他字母不变
#include<stdio.h>
#include<ctype.h>
int main()
{
char str[] = "i am a Student\n";
int i = 0;
char c = 0;
while (str[i])
{
c = str[i];
if (islower(c))
{
c -= 32;
}
putchar(c);
i++;
}
return 0;
}
2.字符转换函数
C语言提供了2个字符转换函数:
is tolower(int c);//将大写字母改为小写
is toupper(int c);//将小写字母改为大写
通过前面我们学习的知识可知,小写字母和大写字母之间相差32,所以我们将小写字母转为大写字母时,需要-32,反之+32;
例如上面的代码
3. strlen的使用和模拟实现
size_t strlen(const char *str)
-
字符串以’\0’作为结束标志,strlen函数返回的是字符串中’\0’前面的字符个数(不包含‘\0’)
-
参数指向的字符串必须要以’ \0’结束
-
注意函数的返回值是size_t,是无符号的
-
strlen的使用必须要包含头文件
-
学会strlen的模拟实现
strlen的使用
#include<stdio.h>
#include<string.h>
int main()
{
const char *str1 = "abcdef";
const char *str2 = "bbb";
if(strlen(str2)-strlen(str1))
{
printf("str2>str1\n");
}
else
{
printf("str1>str2\n");
}
return 0;
}
strlen的模拟实现
方式1:计数器方式
int my_strlen(const char *str)
{
int count = 0;
assert(str);//断言检查指针是否有效(防止空指针)
while(*str)
{
count++; //计数器增加
str++;//指针移动到下一个字符
}
return count;
}
方式2:
//不能创建临时变量计数器,递归形式
int my_strlen(const char *str)
{
assert(str);
if(*str=='\0')
return 0;
else
return 1+my_strlen(str+1);
}
方式3:
//指针——指针的方式
int my_strlen(char *str)
{
assert(str != NULL);
char *p=str;
while(*p != '\0')
p++;
return p-str;
}
4. strcpy的使用和模拟实现
char *strcpy(char *destination,const cahr *source)
//简化为char *my_strcpy(char *dest, const char *src);
-
将源字符串(source 所指向的字符串)复制到目标数组(destination 所指向的数组)中,包括终止的空字符(\0),并在复制到该字符时停止。
-
源字符串必须以’\0’结束
-
会将源字符串中的’\0’拷贝到目标空间
-
目标空间必须足够大,以确保能存放源字符串
-
目标空间必须可修改
-
学会模拟实现
strcpy的模拟实现
#include<stdio.h>
char* my_strcpy(char* dest, const char* src)
{
//1.保存目标字符串的起始地址
char* ret = dest;
//2.对字符进行逐个复制,直到碰到'\0'字符
while(1)
{
*dest = *src;
if (*dest == '\0')
break;
dest++;
src++;
}
//3.返回目标字符串的起始地址
return ret;
}
int main()
{
char str1[] = "hello,world!";
char str2[50];
my_strcpy(str2,str1);
printf("%s\n", str2);
return 0;
}
5. strcat的使用和模拟实现
char *strcpy(char *destination,const cahr *source)
-
将源字符串添加到目标字符串的末尾,目标字符串的’\0’字符会被源字符串的首字符的第一个字符覆盖,并且在两个合并起来的新字符串后面添加’\0’
-
源字符必须以’\0’结束
-
目标字符串中也得有’\0’,否则没办法知道追加从哪里开始
-
目标空间必须足够大,能容纳下源字符串的内容
-
目标空间必须可以修改
-
字符串自己给自己追加
模拟实现strcat函数
#include<stdio.h>
char* my_strcat(char* dest, const char* src)
{
//1.保存目标字符串的起始地址
char* ret = dest;
//2.找到目标字符串的末尾('\0'的位置)
while (*dest != '\0')
{
dest++;
}
//3.将原字符串的内容追加到目标字符串末尾
while (*src != '\0')
{
*dest++ = *src++;
}
//4.添加新的字符串终止符
*dest = '\0';
//5.返回目标字符串的起始地址
return ret;
}
int main()
{
char str1[50] = "hello,";
char str2[] = "world!";
my_strcat(str1, str2);
printf("%s\n", str1);
return 0;
}
6. strcmp的使用和模拟实现
int my_strcmp(const char* str1, const char* str2)
- 从两个字符串的首字符开始比较,如果相同,则继续比较,知道遇到不相等的字符串或者某个字符串遇到’\0’字符
- 第一个字符串大于第二个字符串的话,返回大于0的数字
- 第一个字符串小于第二个字符串的话,返回小于0的数字
- 第一个字符串等于第二个字符串的话,返回0
- 要想判断两个字符串的大小,我们可以两个字符串对应的ASCIII码值的大小
#include<stdio.h>
int my_strcmp(const char* str1, const char* str2)
{
while (*str1 != '\0' && *str2 != '\0')
{
if (*str1 != *str2)
{
return *str1 - *str2;
}
str1++;
str2++;
}
return *str1-*str2;
}
int main()
{
char str1[] = "jackwojskf";
char str2[] = "kdhgebjfs";
int ret = my_strcmp(str1, str2);
printf("%d\n",ret);
return 0;
}
7. strncpy的使用和模拟实现
char *strncpy(char *destination, const char *source,size_t num)
- 将源字符串的前num个字符复制到目标缓冲区,如果在复制完num个字符之前遇到了源字符串的结束字符(“\0”),则目标缓冲区会用’\0’填充,直到总共写入num个字符为止
- 拷贝num个字符从源字符串到目标空间
- 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后面追加0,直到num个
#include<stdio.h>
char* my_strncpy(char* dest, const char* src, size_t n)
{
char* original_dest = dest;
size_t i;
//复制最多n个字符
for (i = 0; i < n && src[i] != '\0'; i++)
{
dest[i] = src[i];
}
//如果src长度小于n,用'\0'填充剩余空间
for (; i < n; i++)
{
dest[i] = '\0';
}
return original_dest;
}
int main()
{
char dest[20];
const char* src = "Hello, World!";
// 复制前5个字符
my_strncpy(dest, src, 5);
dest[5] = '\0'; // 确保字符串正确终止
printf("复制5个字符: %s\n", dest); // 输出: Hello
// 复制超过源字符串长度的字符
my_strncpy(dest, "Hi", 10);
printf("复制2个字符但n=10: '%s'\n", dest); // 输出: 'Hi'后面跟着8个'\0'
return 0;
}
8. strncat的使用和模拟实现
char *strncat(char *destination, const char *source, size_t num );
- 将source指向字符串的前num个字符追加到destination指向的字符串末尾,再追加⼀个’\0’字符
- 如果source指向的字符串的长度小于num的时候,只会将字符串中到\0的内容追加到destination指向的字符串末尾
#include<stdio.h>
char* my_strncat(char* dest, const char* src, size_t n)
{
char* ret = dest;
// 1. 找到 dest 的末尾
while (*dest != '\0')
{
dest++;
}
// 2. 从 src 复制最多 n 个字符到 dest 末尾
size_t i;
for (i = 0; i < n && src[i] != '\0'; i++)
{
*dest++ = src[i];
}
// 3. 添加终止空字符
*dest = '\0';
return ret;
}
int main()
{
char dest[20] = "Hello";
const char* src = ", World!";
my_strncat(dest, src, 5); // 只追加 ", Wo"
printf("%s\n", dest); // 输出: Hello, Wo
return 0;
}
9. 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()
{
const char* str1 = "Hello, World!";
const char* str2 = "Hello, C!";
int result = strncmp(str1, str2, 5);//只比较前5个字符
if (result == 0)
{
printf("前5个字符相同\n");
}
else if (result < 0)
{
printf("str1 < str2\n");
}
else
{
printf("str1 > str2\n");
}
return 0;
}
10. strstr的使用
char *strstr( const char *str1, const char *str2);
- 函数返回字符串str2在字符串str1中第⼀次出现的位置
- 字符串的比较匹配不包括’\0’字符,以’\0’作为结束标志
#include <stdio.h>
#include <string.h>
int main()
{
const char* text = "Hello, world! Welcome to C programming.";
const char* substring = "world";
// 在 text 中查找 substring
char* result = strstr(text, substring);//调用strstr函数
if (result != NULL)
{
printf("找到子串: %s\n", result); // 输出从 "world" 开始的剩余部分
printf("位置偏移: %ld\n", result - text); // 计算偏移量
}
else
{
printf("未找到子串\n");
}
return 0;
}
11. strtok的使用
char *strtok ( char *str, const char * sep);
-
sep参数指向一个字符串,定义了用作分隔符的字符集合
-
第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标志
-
strtok函数找到str中的下⼀个标记,并将其用 ‘\0’ 结尾,返回⼀个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串⼀般都是临时拷贝的内容 并且可修改。)
-
strtok函数的第⼀个参数不为NULL,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置
-
strtok函数的第一个参数为NULL,函数将在同一个字符串中将被保存的位置开始,查找下一个标记
-
如果字符串中不存在更多的标记,则返回NULL指针
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "Hello,world!This is,a test."; // 必须用可修改的字符数组(不能是字符串常量)
const char* delimiters = ",.! "; // 分隔符:逗号、句号、感叹号、空格
// 第一次调用:传入原字符串
char* token = strtok(str, delimiters);//调用strtok函数
while (token != NULL)
{
printf("找到子串: %s\n", token);
// 后续调用:传入 NULL
token = strtok(NULL, delimiters);
}
return 0;
}
12. strerror的使用
char * strerror(int errnum );
strerror函数可以把参数部分错误码对应的错误信息的字符串地址返回来
在不同的系统和C语言标准库的实现中都规定了⼀些错误码,⼀般是放在 errno.h 这个头文件中说明的,C语言程序启动的时候就会使用⼀个全面的变量errno来记录程序的当前错误码,只不过程序启动的时候errno是0,表示没有错误,当我们在使用标准库中的函数的时候发生了某种错误,就会讲对应的错误码,存放在errno中,而⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。
#define _CRT_SECURE_NO_WARNINGS
#include<errno.h>
#include<stdio.h>
#include<string.h>
int main()
{
int i = 0;
for (i = 0; i <= 10; i++)//循环
{
printf("%s\n", strerror(i));//打印每个错误码对应的描述
}
return 0;
}
在VS2022的环境下输出结果为

举例:
#define _CRT_SECURE_NO_WARNINGS
#include<errno.h>
#include<stdio.h>
#include<string.h>
int main()
{
FILE* pFile;//声明文件指针
pFile = fopen("unexist.ent", "r");//尝试以只读模式打开文件
if (pFile == NULL)//检查文件是否成功打开
printf("Error opening file unexist.ent:%s\n", strerror(errno));
return 0;
}
输出结果

我们也可以了解perror函数,perror函数相当于一次就将上述代码中的第9行完成了,直接将错误信息打印出来。perror函数打印完参数部分的字符串后,再打印一个冒号和一个
#define _CRT_SECURE_NO_WARNINGS
#include<errno.h>
#include<stdio.h>
#include<string.h>
int main()
{
FILE* pFile;
pFile = fopen("unexist.ent", "r");
if (pFile == NULL)
perror("Error opening file unexist.ent");
return 0;
}
输出结果


1924

被折叠的 条评论
为什么被折叠?



