大家好!今天我们来学习C语言中的字符函数,字符串函数和内存函数。
目录
1. 字符函数
1.1 字符分类函数
1.2 字符转换函数
1.2.1 tolower(将大写字母转化为小写字母)
1.2.2 toupper(将小写字母转化为大写字母)
2. 字符串函数
2.1 字符串输入函数
2.1.1 gets()
2.1.2 fgets()
2.2 字符串输出函数 puts()
2.3 字符串求长度函数 strlen
2.4 长度不受限制的字符串函数
2.4.1 字符串复制函数 strcpy
2.4.2 字符串连接函数 strcat
2.4.3 字符串比较函数 strcmp
2.5 长度受限制的字符串函数
2.5.1 strncpy
2.5.2 strncat
2.5.3 strncmp
2.6 字符串查找函数 strstr
2.7 字符串分割函数 strtok
2.8 错误处理函数 strerror
3. 内存函数
3.1 memcpy
3.2 memmove
3.3 memset
3.4 memcmp
3. 总结
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
函数原型:
注意事项:
1. 字符串已经 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包
含 '\0' )。
2. 参数指向的字符串必须要以 '\0' 结束。
3. 注意函数的返回值为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
函数原型:
注意事项:
1. 源字符串必须以 '\0' 结束。
2. 会将源字符串中的 '\0' 拷贝到目标空间。
3. 目标空间必须足够大,以确保能存放源字符串。
4. 目标空间必须可变。
用法示例:
#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
函数原型:
注意事项:
1. 源字符串必须以 '\0' 结束。
2. 目标空间必须有足够的大,能容纳下源字符串的内容。
3. 目标空间必须可修改。
4. 字符串不能自己追加自己
用法示例:
#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
函数原型:
注意事项:
1. 拷贝num个字符从源字符串到目标空间。
2. 如果源字符串的长度小于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函数的作用是将一个字符串按照指定的分隔符进行分割,并返回分割后的子字符串。
函数原型:
注意事项:
1. sep参数是个字符串,定义了用作分隔符的字符集合。
2. 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
3. strtok函数找到str中的下一个标记,并将其用' \0' 结尾,返回一个指向这个标记的指针。(注:
strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容
并且可修改。)
4. strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
5. strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标
记。
6. 如果字符串中不存在更多的标记,则返回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函数用来处理不重叠的内存拷贝。
函数原型:
注意事项:
1. 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
2. 这个函数在遇到 '\0' 的时候并不会停下来。
3. 如果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语言中的字符函数,字符串函数和内存函数。有什么问题欢迎在评论区讨论。如果觉得文章有什么不足之处,可以在评论区留言。如果喜欢我的文章,可以点赞收藏哦!