1. 字符函数
1.1 字符分类函数
字符分类函数的头文件为ctype.h
具体用法可以看这个:https://legacy.cplusplus.com/reference/cctype/
1.2 字符转换函数
字符转换函数的头文件也为ctype.h
1.2.1 tolower(将大写字母转化为小写字母)
函数原型:
用法示例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<ctype.h>
int main() {
char ch = 'B';
char new_ch = tolower(ch);
printf("%c", new_ch);
return 0;
}
1.2.2 toupper(将小写字母转化为大写字母)
函数原型:
用法示例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<ctype.h>
int main() {
char ch = 'b';
char new_ch = toupper(ch);
printf("%c", new_ch);
return 0;
}
2. 字符串函数
字符串输入函数和字符串输出函数的头文件均为stdio.h
其它的字符串函数头文件一般为string.h
2.1 字符串输入函数
2.1.1 gets()
函数原型:
gets() 函数的功能是从输入缓冲区中读取一个字符串存储到字符指针变量 str 所指向的内存空间。缓冲区(Buffer)又称为缓存(Cache),是内存空间的一部分。有时候,从键盘输入的内容,或者将要输出到显示器上的内容,会暂时进入缓冲区,待时机成熟,再一股脑将缓冲区中的所有内容“倒出”,我们才能看到变量的值被刷新,或者屏幕产生变化。
用法示例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main() {
char str[30];
gets(str);
puts(str);
return 0;
}
但是这个函数在C或C++不可再用(自C11和C++14起),因为不安全
(不过在实际做题中,我发现有些oj上还是能用的~)
2.1.2 fgets()
因为前面说了gets()函数不安全,在新版C++已经不可再用,所以fgets()用来替代gets()。
但注意fgets()不会删除行末的回车字符
fgets()函数是C语言中的一个输入函数,用于从标准输入(例如键盘)读取一行字符串。
函数原型:
fgets()的作用是读取一行字符并存储到指定的字符串缓冲区中,直到读取到换行符或者达到指定的最大字符数(包括换行符)为止。
其中,str是指向存储读取字符串的缓冲区的指针,num是缓冲区的大小,stream是要读取的文件流(通常使用stdin表示标准输入)。
fgets函数返回指向存储读取字符串的缓冲区的指针,如果读取成功,则返回值与str相同,如果出现错误或者到达文件末尾,则返回NULL。
用法示例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main() {
char str[30];
fgets(str,30,stdin);
puts(str);
return 0;
}
2.2 字符串输出函数 puts()
函数原型:
用法示例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main() {
char str[30] = "hello world";
puts(str);
return 0;
}
2.3 字符串求长度函数 strlen
函数原型:
注意事项:
- 字符串已经 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包
含 '\0' )。 - 参数指向的字符串必须要以 '\0' 结束。
- 注意函数的返回值为size_t,是无符号的。
用法示例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main() {
char str[30] = "abcdef";
printf("%d\n", strlen(str));
return 0;
}
strlen的模拟实现
size_t my_strlen(const char* str)
{
assert(str);
int cnt = 0;
while (*str!='\0')
{
cnt++;
str++;
}
return cnt;
}
2.4 长度不受限制的字符串函数
2.4.1 字符串复制函数 strcpy
函数原型:
注意事项:
源字符串必须以 '\0' 结束。
会将源字符串中的 '\0' 拷贝到目标空间。
目标空间必须足够大,以确保能存放源字符串。
目标空间必须可变。
用法示例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main() {
char str1[30] = {
0 };
char str2[30] = "abcdef";
strcpy(str1, str2);
printf("%s\n",str1);
return 0;
}
strcpy的模拟实现
char* my_strcpy(char *dest,const char *src)
{
assert(dest && src);
char* ret = dest;
while (*dest++=*src++)
{
;
}
return ret;
}
2.4.2 字符串连接函数 strcat
函数原型:
注意事项:
源字符串必须以 '\0' 结束。
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。
字符串不能自己追加自己
用法示例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main() {
char str1[30] = "hello ";
char str2[30] = "world";
printf("%s\n",strcat(str1,str2));
return 0;
}
strcat的模拟实现
char* my_strcat(char* dest, const char* src)
{
assert(dest && src);
char* ret = dest;
while (*dest!='\0')
dest++;
while (*dest++ = *src++)
{
;
}
return ret;
}
2.4.3 字符串比较函数 strcmp
函数原型:
标准规定:
第一个字符串大于第二个字符串,则返回大于0的数字。
第一个字符串等于第二个字符串,则返回0。
第一个字符串小于第二个字符串,则返回小于0的数字。
我们结合下图就能很直观理解上面的标准规定~
用法示例:
情况一:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main() {
char str1[30] = "above";
char str2[30] = "about";
printf("%d\n",strcmp(str1,str2));
return 0;
}
情况二:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main() {
char str1[30] = "About";
char str2[30] = "about";
printf("%d\n",strcmp(str1,str2));
return 0;
}
情况三:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main() {
char str1[30] = "about";
char str2[30] = "about";
printf("%d\n",strcmp(str1,str2));
return 0;
}
strcmp的模拟实现
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0;
str1++;
str2++;
}
if (*str1 > *str2) return 1;
else return -1;
}
2.5 长度受限制的字符串函数
2.5.1 strncpy
函数原型:
注意事项:
拷贝num个字符从源字符串到目标空间。
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
用法示例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main() {
char str1[30] = "abcdef";
char str2[30] = "xxxxxxxxxxxxxx";
strncpy(str1, str2, 4);
printf("%s\n", str1);
return 0;
}
2.5.2 strncat
函数原型:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main() {
char str1[30] = "hello ";
char str2[30] = "worldxxxxxx";
strncat(str1, str2, 5);
printf("%s\n", str1);
return 0;
}
2.5.3 strncmp
函数原型:
逐个比较两个字符串字符的ASCII码值,直到出现不一样的字符或者一个字符串结束或者num个字符全部比较完。
用法示例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main() {
char str1[30] = "abc";
char str2[30] = "abcdef";
char str3[30] = "aba";
printf("%d\n", strncmp(str1, str2, 3));
printf("%d\n", strncmp(str1, str2, 4));
printf("%d\n", strncmp(str1, str3, 5));
return 0;
}
2.6 字符串查找函数 strstr
函数原型:
strstr函数的作用是在字符串str1中查找是否含有字符串str2的子串,如果存在,返回str2在str1中第一次出现的地址;否则返回空指针NULL。
用法示例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main() {
char str1[30] = "abcdef";
char str2[30] = "abc";
if (strstr(str1, str2))
printf("找到了\n");
else
printf("找不到\n");
return 0;
}
strstr的模拟实现
char* my_strstr(char* str1, char* str2)
{
assert(str1 && str2);
char* cp = str1;
char* s1 = cp;
char* s2 = str2;
if (str2 == '\0')
return str1;
while (*cp)
{
s1 = cp;
s2 = str2;
while (*s1 && *s2 && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
return cp;
cp++;
}
return NULL;
}
2.7 字符串分割函数 strtok
strtok函数的作用是将一个字符串按照指定的分隔符进行分割,并返回分割后的子字符串。
函数原型:
注意事项:
sep参数是个字符串,定义了用作分隔符的字符集合。
第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
strtok函数找到str中的下一个标记,并将其用' \0' 结尾,返回一个指向这个标记的指针。(注:
strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容
并且可修改。)strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标
记。如果字符串中不存在更多的标记,则返回NULL 指针。
用法示例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main() {
char str[] = "Hello, world! How are you today?";
char delim[] = " ,!?"; // 分隔符包括空格、逗号和感叹号
// 使用第一次调用strtok函数
char* token = strtok(str, delim);
// 循环调用strtok函数以获取每个子字符串
while (token != NULL) {
printf("%s\n", token);
token = strtok(NULL, delim);
}
return 0;
}
以上代码将输入字符串"Hello, world! How are you today?"按照空格、逗号和感叹号作为分隔符,将其分割成多个子字符串,并依次打印每个子字符串。输出结果如下:
注意:在整个循环过程中,使用NULL作为第一个参数,以便继续分割原字符串。这样可以依次获取每个子字符串。
2.8 错误处理函数 strerror
strerror的作用是根据给定的错误代码返回相应的错误描述字符串。
具体而言,strerror函数接受一个整数参数errno作为输入,该参数代表了一个错误代码。函数会根据给定的错误代码查找对应的错误描述字符串,并将其返回。
函数原型:
用法示例:
示例一:
下面代码是将错误码0~9所对应的错误信息给打印出来:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
int main()
{
int i = 0;
for (int i = 0; i < 10; i++)
{
printf("%d:%s\n", i, strerror(i));
}
return 0;
}
示例二:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include <errno.h>
int main() {
FILE* file = fopen("nonexistent.file", "r");
if (file == NULL) {
int error_code = errno;
const char* error_msg = strerror(error_code);
printf("Failed to open file: %s\n", error_msg);
}
else {
// 文件打开成功,继续其他操作
// ...
fclose(file);
}
return 0;
}
以上代码尝试打开一个名为"nonexistent.file"的文件,如果文件打开失败,则获取对应的错误代码,并使用strerror函数获取错误描述字符串,最后将错误描述字符串打印出来。输出结果类似于:
需要注意的是,strerror函数返回的错误描述字符串可能是静态分配的,多次调用strerror函数可能会覆盖之前的结果。因此,建议尽量将结果保存在变量中,而不是直接在printf等函数中使用strerror函数。
3. 内存函数
内存函数的头文件一般也为string.h
3.1 memcpy
memcpy函数作用是将指定长度的内存块从源地址复制到目标地址。
也就是说,memcpy函数用来处理不重叠的内存拷贝。
函数原型:
注意事项:
函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
这个函数在遇到 '\0' 的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的。
用法示例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
int main() {
int arr1[] = {
1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = {
0 };
//将arr1中的内容,拷贝到arr2中
memcpy(arr2, arr1, 40);
for (int i = 0; i < 20; i++)
printf("%d ", arr2[i]);
return 0;
}
memcpy的模拟实现
void* my_memcpy(void* dest, const void* src, size_t num) //num单位是字节
{
void* ret = dest;
assert(src && dest);
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
3.2 memmove
memmove函数作用是将指定长度的内存块从源地址移动到目标地址,允许源和目标内存块重叠。
也就是说,memmove函数用来处理重叠内存拷贝。
函数原型:
用法示例:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
int main()
{
int arr1[] = {
1,2,3,4,5,6,7,8,9,10 };
memmove(arr1 + 2, arr1, 20);
for (int i = 0; i < 10; i++)
printf("%d ", arr1[i]);
return 0;
}
memmove的模拟实现:
void* my_memmove(void* dest, const void* src, size_t num) //num单位是字节
{
void* ret = dest;
assert(dest && src);
if (dest < src) //前->后拷贝
{
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else //后->前拷贝
{
while (num--)
{
*((char*)dest+num) = *((char*)src+num);
}
}
return ret;
}
3.3 memset
memset函数作用是将指定长度的内存块填充为指定的值。
函数原型:
用法示例:
示例一:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
int arr[5];
memset(arr, 0, sizeof(arr));
for (int i = 0; i < 5; i++)
printf("%d ", arr[i]);
return 0;
}
数组arr的所有元素都将被设置为0。
示例二:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main(){
char arr[] = "hello world";
memset(arr + 1, 'x', 4); //以字节为单位设置的
printf("%s\n", arr);
return 0;
}
3.4 memcmp
memcmp的作用是比较两个内存块的内容。
函数原型:
注意事项:
比较从ptr1和ptr2指针开始的num个字节
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main(){
int arr1[] = {
1,2,1,4,5,6 };
int arr2[] = {
1,2,257 };
int ret = memcmp(arr1, arr2, 10);
printf("%d\n", ret);
return 0;
}
3. 总结
到这里,我们就介绍完了C语言中的字符函数,字符串函数和内存函数。有什么问题欢迎在评论区讨论。如果觉得文章有什么不足之处,可以在评论区留言。如果喜欢我的文章,可以点赞收藏哦!