字符分类函数
C语言中有⼀系列的函数是专门做字符分类的,也就是⼀个字符是属于什么类型的字符的。
这些函数的使用都需要包含⼀个头文件:ctype.h
这些函数的用法非常类似。
c
int islower ( int c )
islower
是能够判断参数部分是否是小写字母的。
通过返回值来说明是否是小写字母,如果是小写字母就返回非0的整数,如果不是小写字母,则返回0
练习:
写⼀个代码**,** 将字符串中的小写字母转大写,其他字符不变。
c
#include<stdio.h>
#include<ctype.h>
int main()
{
char str[] = "Test String";
int i = 0;
while(str[i])//'\0'的ASCLL码为0
//while (str[i] != '\0')
{
if (islower(str[i]))
str[i] -= 32;
//写法一:putchar
putchar(str[i]);
i++;
}
printf("\n");
//写法二:%s
printf("%s", str);
return 0;
}
输出结果:
TEST STRING
TEST STRING
字符转换函数
C语⾔提供了2个字符转换函数,头文件为ctype.h
c
int tolower(int c);//将参数传进去的大写字母转小写字母
int toupper(int c);//将参数传进去的小写字母转大写字母
上面的代码,我们将小写转大写,是-32完成的效果,有了转换函数,就可以直接使用转换函数。
c
#include<stdio.h>
#include<ctype.h>
int main()
{
char str[] = "Test String";
int i = 0;
while (str[i])
{
if (islower(str[i]))
str[i] = toupper(str[i]);
putchar(str[i]);
i++;
}
return 0;
}
strlen的使用和模拟实现
基本用法
strlen
是C语言库函数,功能是求字符串长度。
头文件为string.h
c
size_t strlen ( const char * str );
- 统计的是从
strlen
函数的参数str
中这个地址开始向后,\0
之前 字符串中字符的个数(不包含'\0'
)。 strlen
函数会⼀直向后找\0
字符,直到找到为止,所以可能存在越界查找。
我们可以通过代码来理解:
c
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abc";
char arr2[] = { 'a', 'b' , 'c' };
char arr3[] = { 'a', 'b' , 'c' , '\0' };
printf("%s\n%s\n%s\n", arr1, arr2, arr3);
int len1 = strlen(arr1);
int len2 = strlen(arr2);
int len3 = strlen(arr3);
printf("%d\n%d\n%d\n", len1, len2, len3);
return 0;
}
运行结果为:
我们可以看到,字符串中有\0
和无\0
的结果不同,这是因为arr2
因为没有\0
而打印没有停止,继续打印了一些随机值。
- 函数的返回值为
size_t
,是无符号的。
c
#include<stdio.h>
#include<string.h>
int main()
{
if (strlen("abc") - strlen("abcdef") > 0)
printf(">");
else
printf("<");
return 0;
}
输出结果为>
strlen
的返回值为size_t
类型,是无符号整型。
无符号整型 - 无符号整型,结果为无符号整型。
模拟实现
方法一
c
//计数器方式
size_t my_strlen(const char* str)
{
assert(str);
//assert(str != NULL);
size_t count = 0;
while (*str)
{
count++;
str++;
}
return count;
}
int main()
{
char str[] = "Test String";
size_t i = my_strlen(str);
printf("%zd", i);
return 0;
}
方法二
:
c
//指针 --- 指针
#include<stdio.h>
#include<assert.h>
size_t my_strlen(const char* str)
{
assert(str);
//assert(str != NULL);
char* p = str;
while (*str)
{
str++;
}
return str - p;
}
int main()
{
char str[] = "Test String";
size_t i = my_strlen(str);
printf("%zd", i);
return 0;
}
方法三
:
c
//不创建临时变量------函数递归
#include<stdio.h>
#include<assert.h>
size_t my_strlen(const char* str)
{
assert(str);
//assert(str != NULL);
if (*str == '\0')
return 0;
else
return 1 + my_strlen(str + 1);
}
int main()
{
char str[] = "Test String";
size_t i = my_strlen(str);
printf("%zd", i);
return 0;
}
strcpy
的使用和模拟实现
基本用法
strcpy
是C语言库函数,功能是字符串的拷贝。
头文件为string.h
c
char* strcpy(char * destination, const char * source );
- Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point).
- 源字符串必须以\0结束。
- 会将源字符串中的'\0'拷贝到目标空间,拷贝至'\0'`结束。
- 目标空间必须足够大,以确保能存放源字符串。
- 目标空间必须可修改(常量字符串不能作为目标空间)。
strcpy
的返回值为目标空间的起始地址(便于链式访问)。
:::
c
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "abcdef";
char arr2[20] = "ghijkl";
strcpy(arr1, arr2);
printf("%s", arr1);
return 0;
}
模拟实现
c
#include<stdio.h>
#include<assert.h>
char* my_strcpy (char* des, const char* sour)
{
char* p = des;
assert(des && sour);
while (*des++ = *sour++)
//=的返回值为所赋的值
{
;
}
//拷贝\0
*des = *sour;
return p;
}
int main()
{
char arr1[20] = "abcdef";
char arr2[20] = "ghijkl";
my_strcpy(arr1, arr2);
printf("%s", arr1);
return 0;
}
strcat
的使用和模拟实现
基本用法
strcat
是C语言库函数,功能是追加字符串。
头文件为string.h
c
char * strcat ( char * destination, const char * source );
- Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a null-character is included at the end of the new string formed by the concatenation of both in destination.
- 源字符串必须以'\0'结束。
- 目标字符串中也得有'\0',否则不知道从哪里开始追加。
- 目标空间必须有足够的大,能容纳下源字符串的内容。
- 目标空间必须可修改。
- 返回值为目标空间的地址。
- 不适用于字符串自己给自己追加。
c
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "hello ";
char arr2[20] = "world!";
strcat(arr1, arr2);
printf("%s", arr1);
return 0;
}
模拟实现
c
#include<stdio.h>
#include<assert.h>
char* my_strcat(char* des, const char* sour)
{
char* p = des;
assert(des && sour);
//找到'\0'
while (*des)
{
des++;
}
//追加字符串
while (*des++ = *sour++)
{
;
}
return p;
}
int main()
{
char arr1[20] = "hello ";
char arr2[20] = "world!";
my_strcat(arr1, arr2);
printf("%s", arr1);
return 0;
}
注意:strcat `不适用于字符串自己给自己追加。
c
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcat(char* des, const char* sour)
{
char* p = des;
assert(des && sour);
while (*des)
{
des++;
}
while (*des++ = *sour++)
{
;
}
return p;
}
int main()
{
char arr1[20] = "abc";
my_strcat(arr1, arr1);
printf("%s", arr1);
//陷入死循环
//源字符串中的'\0'被破坏
return 0;
}
c
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "abc";
strcat(arr1, arr1);
printf("%s", arr1);//输出 abcabc
//在VS中,strcat能够实现字符串自己给自己的追加
return 0;
}
strcmp
的使用和模拟实现
基本用法
strcmp
是C语言库函数,功能是比较字符串。
- This function starts comparing the first character of each string. If they are equal to each other, it continues with the following pairs until the characters differ or until a terminating null-character is reached.
- 比较的不是字符串的长度,而是对应位置 ASCLL 码值的大小。
- 标准规定:
- 第⼀个字符串大于第二个字符串,则返回大于0的数字
- 第⼀个字符串等于第二个字符串,则返回0
- 第⼀个字符串小于第二个字符串,则返回小于0的数字
c
#include<stdio.h>
#include<string.h>
int main()
{
int i = strcmp("abcde", "abq");
printf("%d", i);//输出 -1
return 0;
}
c
#include<stdio.h>
#include<string.h>
int main()
{
int r = strcmp("abcdef", "abq");
if (r == 1)
printf("字符串一大于字符串二");
else if (r == 0)
printf("字符串一等于字符串二");
else
printf("字符串一小于字符串二");
return 0;
}
这串代码正不正确?
在VS2022等部分编译器中,是正确的,因为这些编译器的返回值只为-1,1,0。
模拟实现
方法一
c
//VS2022中的写法
#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0;
str1++;
str2++;
}
if (*str1 > *str2)
return 1;
else
return -1;
}
int main()
{
int i = strcmp("abcde", "abq");
printf("%d", i);
return 0;
}
方法二
c
#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0;
str1++;
str2++;
}
return *str1 - *str2;
}
int main()
{
int i = my_strcmp("abcde", "abq");
printf("%d", i);
return 0;
}
strncpy
函数的使用
strncpy
是C语言库函数,功能是字符串的拷贝。
头文件为string.h
c
char * strncpy ( char * destination, const char * source, size_t num );
- 拷贝
num
个字符从源字符串到目标空间。 - 如果源字符串的长度小于
num
,则拷贝完源字符串之后,在目标的后边追加\0
,直到num
个。 - 返回值为目标空间的地址。
c
#include<stdio.h>
#include<string.h>
int main()
{
char str1[20] = "abcdef";
char str2[20] = "ghi";
strncpy(str1, str2, 5);
printf("%s", str1);
return 0;
}
strncat
函数的使用
c
char * strncat ( char * destination, const char * source, size_t num );
- 将source指向字符串的前num个字符追加到destination指向的字符串末尾,再追加⼀个\0字符
- 如果source指向的字符串的长度小于num的时候,只会将字符串中到\0的内容追加到指向的字符串末尾。
- 返回值为目标空间的地址。
c
#include<stdio.h>
#include<string.h>
int main()
{
char str1[20] = "abc";
char str2[20] = "defghi";
strncat(str1, str2, 3);
printf("%s", str1);
return 0;
}
c
#include<stdio.h>
#include<string.h>
int main()
{
char str1[20] = "xxx\0xxxxxx";
char str2[20] = "abc";
strncat(str1, str2, 6);
printf("%s", str1);
return 0;
}
注意:字符串给自身追加的操作用 **strncat**
更安全。
c
#include<stdio.h>
#include<string.h>
int main()
{
char str1[20] = "abcdefghi";
size_t len = strlen(str1);
strncat(str1, str1, len);
printf("%s", str1);//输出 abcdefghiabcdefghi
return 0;
}
strncmp
函数的使用
c
int strncmp ( const char * str1, const char * str2, size_t num );
- 比较str1和>str2的前num个字符,如果相等就继续往后比较,**最多比较num<个字母,如果提前发现不⼀样,就提前结束,大的字符所在的字符串大于另外⼀个。如果字符都相等,就是相等返回0
- 比较的不是字符串的长度,而是对应位置 ASCLL 码值的大小。
- 标准规定:
- 第⼀个字符串大于第二个字符串,则返回大于0的数字
- 第⼀个字符串等于第二个字符串,则返回0
- 第⼀个字符串小于第二个字符串,则返回小于0的数字
c
#include<stdio.h>
#include<string.h>
int main()
{
char str1[20] = "abcdefg";
char str2[20] = "abcde";
int i = strncmp(str1, str2, 7);
printf("%d", i);//输出 0
return 0;
}
strstr
的使用和模拟实现
strstr
是C语言库函数,功能是在字符串中查找子串。
头文件为string.h
基本功能
c
char * strstr ( const char * str1, const char * str2);
- Returns a pointer to the first occurrence of str2 in str1, ora null pointer if str2 is not part of str1. (函数返回字符串str2在字符串str1<中第⼀次出现的位置)。
- The matching process does not include the terminating null-characters, but it stops there. (字符串的比较匹配不包含\0字符,以\0作为结束标志)。
c
#include<stdio.h>
#include<string.h>
int main()
{
char str1[20] = "abcdefabcdef";
char str2[20] = "def";
char* p = strstr(str1, str2);
if (p == NULL)
printf("找不到");
else
printf("找到了");
return 0;
}
模拟实现
c
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
//强制类型转换,更加规范
char* p1 = (char*) str1;
char* p2 = (char*) str2;
if (!*str2/* *str2 == '\0' */)
return (char*)str1;
while (*p1)
{
//多次匹配保留起始位置
char* s1 = p1;
char* s2 = p2;
while (*s1 && *s2 && !(*s1 - *s2)/* *s1 == *s2 */)
{
s1++;
s2++;
}
if (!*s2)
return p1;
p1++;
}
return NULL;
}
int main()
{
char str1[20] = "abcdefabcdef";
char str2[20] = "def";
char* p = my_strstr(str1, str2);
if (p == NULL)
printf("找不到\n");
else
{
printf("找到了\n");
printf("%s", p);
}
return 0;
}
strtok
函数的使用
c
char * strtok ( char * str, const char * sep);
● sep参数指向⼀个字符串,定义了用作分隔符的字符集合
● str参数指定⼀个字符串,它包含了0个或者多个由sep字符串中⼀个或者多个分隔符分割的标记。
● strtok函数找到str中的下⼀个标记,并将其用\0结尾,返回⼀个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串⼀般都是临时拷贝的内容并且可修改。)
● strtok函数的第⼀个参数不为NULL,strtok函数将保存它在字符串中的位置。
● strtok函数的第⼀个参数为NULL,函数将在同⼀个字符串中被保存的位置(存放于一个静态变量中)开始,查找下⼀个标记。
● 如果字符串中不存在更多的标记,则返回NULL指针。
c
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "zpw@bitedu.net";
const char arr2[] = "@.";
char* p = strtok(arr1, arr2);
printf("%s\n", arr1);//输出 zpw
printf("%s\n", p);//输出 zpw
return 0;
}
c
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "zpw@bitedu.net";
const char arr2[] = "@.";
char* r = NULL;
char* p1 = strtok(arr1, arr2);
char* p2 = strtok(r, arr2);
printf("%s\n", p1);//输出 zpw
printf("%s\n", p2);//输出 biteedu
return 0;
}
strerror函数的使用
基本用法
c
char * strerror ( int errnum );
strerror函数可以把参数部分错误码对应的错误信息的字符串地址返回来,头文件为string.h。
在不同的系统和C语言标准库的实现中都规定了⼀些错误码,⼀般是放在errno.h这个头文件中说明的,C语言程序启动的时候就会使用⼀个全面的变量errno来记录程序的当前错误码,只不过程序启动的时候errno是0,表示没有错误,当我们在使用标准库中的函数的时候发生了某种错误,就会讲对应的错误码,存放在errno中,而⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。
c
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
int i = 0;
for (i = 0; i <= 10; i++)
{
printf("%d:%s\n", i, strerror(i));
}
return 0;
在vs2022 + windows11
环境下,输出结果为:
c
0:No error
1:Operation not permitted
2:No such file or directory
3:No such process
4:Interrupted function call
5:Input/output error
6:No such device or address
7:Arg list too long
8:Exec format error
9:Bad file descriptor
10:No child processes
c
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf = fopen("test.txt", "r");//以读的形式打开文件
if (pf == NULL)
{
//打开文件失败
printf("错误信息是:%s\n", strerror(errno));
//输出 错误信息是: No such file or directory
}
return 0;
}
perror
函数的使用
c
void perror(const char* str);
c
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf = fopen("test.txt", "r");//以读的形式打开文件
if (pf == NULL)
{
//打开文件失败
perror("错误信息是");
//输出 错误信息是: No such file or directory
//在括号中加字符串时,会自动添加':'和' '
printf("错误信息是: %s\n", strerror(errno));
//输出 错误信息是: No such file or directory
}
return 0;
}