字符函数·字符串函数·C语言内存函数
- 1.字符分类函数
- 2. 字符转换函数
- 3. `strlen`的使用和模拟实现
- 4.`strcpy`的使用和模拟实现
- 5.`strcat`的使用和模拟实现
- 6.`strcmp`的使用和模拟实现
- 7.`strncpy`的模拟和实现
- 8.`strncat`的实现和模拟实现
- 9.`strncmp`函数使用
- 10.`strstr`的使用和模拟实现
- 11.`strtok`函数使用
- 12.`strerror`函数的使用
- 13.`memcpy`函数的使用和模拟实现
- 14.`memmove`使用和模拟实现
- 15.`memset`函数的使用
- 16.`memcmp`函数的使用
1.字符分类函数
- C语言中有一系列函数专门用来做字符的分类,用于对单个字符进行各种分类测试,也就是一个字符是属于什么类型的字符的,。这些函数通常用于检查字符是否属于特定的类别,如字母、数字、标点符号等。这些函数的使用通常需要包含头文件
<ctype.h>
。
函数 | 如果它的参数符合下列条件就返回真 |
---|---|
iscntrl | 任何控制字符 |
isspace | 空白字符“空格 ‘ ’,换页‘\f’, 换行‘\n’, 回车‘\r‘,制表符’\t’或者垂直制表符‘\v’ |
isdigit | 十进制数字0~9 |
isxdigit | 十六进制数字,包括所有十进制数字,小写字母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 | 任何可打印字符,包括图形字符和空白字符 |
这些函数的使用方法类似,比如isupper
:
int isupper(int a)
isupper
能判断参数部分的a
是否是大写字母。我们可以通过返回值来判断是否为大写字母,如果返回值为非零的数则为大写字母,否则返回0。
- 例如:写一个代码将字符串中的大写字母转小写,其他字符不变。
#include <stdio.h>
#include <ctype.h>
int main()
{
int i = 0;
char str[] = "Lyz and Fzy!\n";
char c;
while (str[i])
{
c = str[i];
if (isupper(c))
c += 32;
putchar(c);
i++;
}
return 0;
}
2. 字符转换函数
- C语言中提供了2个字转换函数:
int tolower(int c);//将参数传进去的大写字母转小写
int toupper(int c);//将参数传进去的小写字母转大写
刚刚我们写的大小写转换的代码是用+32
完成的,有了字符转换函数,就可以直接使用tolower
:
#include <stdio.h>
#include <ctype.h>
int main()
{
int i = 0;
char str[] = "Lyz and Fzy!\n";
char c;
while (str[i])
{
c = str[i];
if (isupper(c))
c = tolower(c);
putchar(c);
i++;
}
return 0;
}
3. strlen
的使用和模拟实现
- 功能:统计
\0
之前的的字符个数(字符串中必须要有\0
);
函数原型:
size_t strlen (const char * str);
- 字符串以
\0
作为结束的标志,strlen
函数返回的是在字符串中\0
前面出现的字符个数(不包含\0
); - 参数指向的字符串必须以
\0
结束; - 注意函数的返回值是
size_t
是无符号的; strlen
使用需要包含头文件<string.h>
;
strlen
的使用:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "lyz and fzy!";
size_t length;
// 使用 strlen 计算字符串的长度
length = strlen(str);
// 输出字符串的长度
printf("%s: %zu\n", str, length);
// 注意:strlen 不包括字符串末尾的空字符 '\0'
return 0;
}
strlen
的模拟实现(三种):
//方式一(计数器方式):
#include <stdio.h>
#include <assert.h>
int my_strlen(const char* arr)
{
assert(arr != NULL);
int count = 0;
while (*arr != '\0')
{
count++;
arr++;
}
return count;
}
int main()
{
char arr[] = "abcdefghijk";
int ret = my_strlen(arr);
printf("%d\n",ret);
return 0;
}
//方式二:不创建临时变量计数器(递归)
#include <stdio.h>
#include <assert.h>
int my_strlen(const char* arr)
{
assert(arr != NULL);
if (*arr == '\0')
{
return 0;
}
else
return 1 + my_strlen(arr + 1);
}
int main()
{
char arr[] = "abcdefghijk";
int ret = my_strlen(arr);
printf("%d\n",ret);
return 0;
return 0;
}
//方法三:指针-指针
#include<stdio.h>
#include <assert.h>
int my_strlen(const char* arr)
{
assert(arr != NULL);
char* p = arr;
while (*p != '\0')
p++;
return p - arr;
}
int main()
{
char arr[] = "abcdefghijk";
int ret = my_strlen(arr);
printf("%d\n",ret);
return 0;
}
4.strcpy
的使用和模拟实现
- 功能:字符串的拷贝,将源字符串(包括其终止的空字符 ‘\0’)复制到目标字符数组中;
char* strcpy(char * destination,const char * source);
destination
是一个指向目标字符数组的指针,该数组必须足够大,以容纳源字符串source
的内容及其终止的空字符 ‘\0’。source
是一个指向源字符串的指针。strcpy
函数将source
指向的字符串复制到destination
指向的位置,并返回destination
的指针。复制过程包括源字符串的所有字符,直到遇到源字符串的终止符\0
,并将这个终止符也复制到目标字符串中。
- 使用需要包含头文件
<string.h>
; - 源字符串必须以
\0
结尾; - 它会将源字符串的
\0
拷贝到目标空间中; - 目标空间必须足够大,确保有足够大的内存存放源字符串;
- 目标空间必须是可以修改的;
strcpy
的使用:
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "lyz and fzy!";
char dest[50]; // 确保目标数组足够大,以容纳源字符串及其终止符
// 使用 strcpy 复制字符串
strcpy(dest, src);
// 输出复制后的目标字符串
printf("%s\n", dest);
// 注意:如果目标数组 dest 不够大,strcpy 会导致缓冲区溢出,这是非常危险的。
// 在实际编程中,应确保目标数组有足够的空间来存储源字符串及其终止符。
return 0;
}
这里定义了一个源字符串 src
和一个足够大的目标字符数组 dest
。然后,我们使用 strcpy
函数将 src
复制到 dest
中。最后,我们打印出复制后的目标字符串 dest
。
值得注意的是,strcpy
不会检查目标数组 dest
的大小是否足以容纳源字符串 src
及其终止的空字符。如果目标数组太小,就会发生缓冲区溢出,这可能会导致程序崩溃。因此,在使用 strcpy
时,一定要确保目标数组有足够的空间。
为了避免缓冲区溢出,可以使用 strncpy
函数,它允许你指定一个最大字符数来限制复制的字符数量。但是,使用 strncpy
时也要注意正确处理字符串的终止符。
strcpy
的模拟实现:
#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* destination, const char* source)
{
assert(destination != NULL);
assert(source != NULL);
char* ret = destination;
while (*destination++ = *source++)
;
return ret;
}
int main()
{
char arr1[] = "Hello fzy!";
char arr2[20] = "ooooooooooooooooooo";
int ret = my_strcpy(arr2, arr1);
printf("%s\n",arr2);
return 0;
}
5.strcat
的使用和模拟实现
- 功能:用于将两个字符串连接(追加拼接)起来;
char * strcat ( char * destination, const char * source );
destination
是一个指向目标字符数组的指针,该数组必须已经包含一个以空字符\0
结尾的字符串。函数会将source
字符串连接到这个字符串的末尾。source
是一个指向源字符串的指针,该字符串将被添加到destination
字符串的末尾。
strcat
函数会找到 destination
字符串的末尾(即空字符 \0
的位置),然后将 source
字符串的字符逐个复制到 destination
字符串的末尾,并在复制完成后在拼接后的字符串末尾添加一个新的空字符 \0
。
- 源字符串必须以
\0
结束; - 目标字符串也得有
\0
,否则无法得知是从哪里开始追加的; - 目标空间必须足够大,以至于容纳下源字符串的内容;
- 目标空间保证可以修改
strcat
的使用:
#include <stdio.h>
#include <string.h>
int main() {
char dest[100] = "lyz and ";
char src[] = "fzy!";
// 确保目标数组 dest 足够大,以容纳拼接后的字符串及其终止符
// 使用 strcat 连接字符串
strcat(dest, src);
// 输出拼接后的目标字符串
printf("%s\n", dest);
// 注意:如果目标数组 dest 初始内容之后的剩余空间不足以容纳源字符串 src,strcat 会导致缓冲区溢出
// 应确保目标数组有足够的剩余空间来存储源字符串及其终止符。
return 0;
}
这里定义了一个目标字符串 dest
和一个源字符串 src
。然后,使用 strcat
函数将 src
添加到 dest
的末尾。最后打印出拼接后的目标字符串 dest
。
同样值得注意的是,strcat
不会检查目标数组 dest
是否还有足够的空间来容纳源字符串 src
及其终止的空字符。如果目标字符串的剩余空间不足以容纳源字符串,就会发生缓冲区溢出。因此,在使用 strcat
时,一定要确保目标数组有足够的剩余空间。
strcat
的模拟实现:
#include <stdio.h>
#include <assert.h>
char* my_strcat(char* destination, const char* source)
{
assert(destination != NULL);
assert(source != NULL);
char* ret = destination;
while (*destination != '\0')
destination++;
while (*destination++ = *source++)
;
return ret;
}
int main()
{
char arr1[20] = "hello ";
char arr2[] = "fzy!";
int ret = my_strcat(arr1, arr2);
printf("%s\n",arr1);
return 0;
}
6.strcmp
的使用和模拟实现
- 功能:比较两个字符串内容,并根据比较结果返回一个整数;
int strcmp ( const char * str1, const char * str2 );
- 如果
str1
和str2
相等(即内容完全相同),则返回0
。 - 如果
str1
大于str2
,则返回整数。 - 如果
str1
小于str2
,则返回负数。
- 如果
- 比较两个字符串:比较两个字符串在对应位置上
ASCII
码值的大小;
strcmp
的使用:
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "lyz";
char str2[] = "fzy";
char str3[] = "lyz";
if (strcmp(str1, str2) == 0) {
printf("str1和str2相等\n");
}
else {
printf("str1和str2不相等\n");
}
if (strcmp(str1, str3) == 0) {
printf("str1和str3相等\n");
}
else {
printf("str1和str3不相等\n");
}
return 0;
}
注意:strcmp
是区分大小写的;
strcmp
的模拟实现:
include <stdio.h>
#include <assert.h>
#include <string.h>
int my_strcmp(const char* arr1, const char* arr2)
{
assert(arr1 && arr2);
while (*arr1 == *arr2)
{
if (*arr1 == '\0')
return 0;
arr1++;
arr2++;
}
return *arr1 - *arr2;
}
int main()
{
char arr1[] = "abvdef";
char arr2[] = "asdfgh";
int ret = my_strcmp(arr1, arr2);
printf("%d\n",ret);
return 0;
}
7.strncpy
的模拟和实现
- 功能:长度受限制的将一个字符串(源字符串)复制到另一个字符串(目标字符串)中;
- 函数原型:
char * strncpy ( char * destination, const char * source, size_t num );
destination
:指向目标字符串的指针,即想要将源字符串复制到的位置。source
:指向源字符串的指针,即想要复制的字符串。num
:要复制的字符的最大数量。
- 拷贝
num
个字符从源字符串到目标空间中; - 如果源字符串的长度小于
num
,则拷贝完源字符串后,在目标后追加0
,直到num
个;
strncpy
的使用:
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, World!";
char dest[20];
strncpy(dest, src, 5);
dest[5] = '\0'; // 确保目标字符串正确终止
printf("源字符串: %s\n", src);
printf("目标字符串(目的地): %s\n", dest);
return 0;
}
strncpy
的模拟实现:
#include <stdio.h>
#include <assert.h>
char* my_strncpy(char* destination, const char* source, size_t num)
{
assert(source && destination);
char* ret = destination;
for (int i = 0; source[i] != '\0' && i < num; i++)
{
destination[i] = source[i];
}
destination = '\0';
return ret;
}
int main()
{
char arr1[200] = "Hello!fzy";
char arr2[] = "WWM";
char* ret = my_strncpy(arr1, arr2,3);
printf("%s\n",arr1);
return 0;
}
8.strncat
的实现和模拟实现
- 功能:常速受限制的将一个字符串(源字符串)的前n个字符追加到另一个字符串(目标字符串)的末尾;
- 函数原型:
char * strncat ( char * destination, const char * source, size_t num );
- 将
source
指向字符串的前num
个字符追加到destination
指向的字符串末尾,再追加一个\0
字符。 - 如果
source
指向的字符串的长度小于num
的时候,只会将字符串中到\0
的内容追加到destination
指向的字符串末尾;
- 将
strncat
的使用:
#include <stdio.h>
#include <string.h>
int main() {
char dest[50] = "lyz and ";
const char *src = "fzy";
size_t n = 3; // 追加前3个字符
strncat(dest, src, n);
printf("Result: %s\n", dest);
return 0;
}
strncat
的模拟实现:
#include <stdio.h>
#include <assert.h>
char* my_strncat(char* dest, const char* src, size_t num)
{
char* ret = dest;
while (*dest)
{
dest++;
}
for (int i = 0; src[i] != '\0' && i < num; i++)
{
dest[i] = src[i];
}
dest = '\0';
return ret;
}
int main()
{
char arr1[20] = "hello!";
char arr2[] = "lyz fzy";
char* ret = my_strncat(arr1, arr2, 7);
printf("%s\n",arr1);
return 0;
}
9.strncmp
函数使用
- 功能:用于比较两个字符串的前n个字符是否相等;
- 函数原型:
int strncmp ( const char * str1, const char * str2, size_t num );
- 比较
str1
和str2
的前num
个字符,如果相等就继续往后比较,最多比较num
个字符,如果提前发现不一样,就提前结束,则大的字符所在的字符串大于另一个。如果num
个字符都相等返回0
;
strncmp
的使用:
- 比较
#include <stdio.h>
#include <assert.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abqdefghi";
int ret = strncmp(arr1, arr2, 2);
printf("%d\n", ret);
return 0;
}
10.strstr
的使用和模拟实现
- 功能:在一个字符串中查找另一个字符串是否存在
- 函数原型:
char * strstr ( const char * str1, const char * str2 );
- 函数返回字符串str2在字符串str1中出现的位置
- 字符串的比较匹配不包含
\0
字符,以\0
作为结束标志;
strstr
的使用:
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "This is a simple string";
char* pch;
pch = strstr(str, "simple");
strncpy(pch, "sample", 6);
printf("%s\n", str);
return 0;
}
```strstr`的模拟实现:
#include <stdio.h>
char* my_strstr(const char* str1, const char* str2)
{
const char* s1 = NULL;
const char* s2 = NULL;
const char* cur = str1;
if (*str2 == '\0')
{
return (char *)str1;
}
while (*cur)
{
s1 = cur;
s2 = str2;
while (*s1 != '\0'&& *s2 != '\0' && * s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return (char*)cur;
}
cur++;
}
return NULL;
}
int main()
{
char arr1[] = "hello fzy yyds!";
char arr2[] = "fzy";
char* ret = my_strstr(arr1, arr2);
if (ret == NULL)
{
printf("找不到!");
}
else
{
printf("%s\n", ret);
}
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
指针;
strtok
函数的使用:
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "lyz@fzy.com";
char* sep = "@.";
char* str = NULL;
for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep))
{
printf("%s\n", str);
}
return 0;
}
12.strerror
函数的使用
- 功能:把参数部分错误码对应的错误信息的字符串地址返回。
strerror
的使用通常需要包含头文件<error.h>,在不同的系统和C语言标准库的实现里面都规定了一些错误码。- C语言程序启动时就会使用一个全面的变量
errno
来记录程序的当前的错误码,只不过程序启动时errno
是0
,表示没有错误,当我们使用标准库里的函数时发生了某种错误,就会将对应的错误码存放在errno
中,而错误码都用对应的错误信息。所以strerror
函数就可以将错误对应的错误信息字符串的地址返回。
#include <errno.h>
#include <string.h>
#include <stdio.h>
//打印0~10这些错误码对应的信息
int main()
{
int i = 0;
for (i = 0; i <= 10; i++) {
printf("%s\n", strerror(i));
}
return 0;
}
例如:
#include <stdio.h>
#include <string.h>
#include <errno.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;
}
fopen
以读的形式打开文件,如果文件不存在,则打开失败。
perror函数,可以直接将错误信息打印出来。perror函数打印完参数部分的字符串后,在打印一个冒号和空格,在打印错误信息。
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main ()
{
FILE * pFile;
pFile = fopen ("unexist.ent","r");
if (pFile == NULL)
perror("Error opening file unexist.ent");
return 0;
}
13.memcpy
函数的使用和模拟实现
- 功能:对内存块进行拷贝;
- 函数原型:
void * memcpy ( void * destination, const void * source, size_t num );
- 函数
memcpy
从source
的位置开始向后复制num
个字节的数据到destination
指向的内存位置; - 这个函数在遇到
\0
的时候不会停下来; - 如果
source
和destination
有任何的重叠部分,复制的结果都是未定义的;
memcpy
的使用:
#include <stdio.h>
#include <string.h>
int main() {
char source[] = "lyz and fzy!";
char destination[20];
// 使用 memcpy 复制字符串到 destination
memcpy(destination, source, strlen(source) + 1); // +1 是为了复制字符串末尾的空字符 '\0'
// 输出 destination 中的内容
printf("%s\n", destination);
return 0;
}
memcpy
的模拟实现:
#include <stdio.h>
#include <assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
assert(dest && src);
void* ret = dest;
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
int main()
{
char arr1[20] = "fzy";
char arr2[] = "lyz";
my_memcpy(arr1, arr2, 3);
printf("%s\n",arr1);
return 0;
}
14.memmove
使用和模拟实现
- 功能:将一块内存区域的内容移动到另一块内存区域中;
- 函数原型:
void * memmove ( void * destination, const void * source, size_t num );
- 和
memcpy
的差别在于memmove
函数处理的源内存和目标内存块是可以重叠的; - 如果源空间和目标空间出现重叠,就需要使用
memmove
函数处理;
memmove
的使用:
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr1 + 2, arr1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
memmove的模拟实现:
#include <stdio.h>
void* my_memmove(void* dest, const void* src, size_t num)
{
void* ret = dest;
if (dest < src)
{
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
dest = (char*)dest + num - 1;
src = (char*)src + num - 1;
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest - 1;
src = (char*)src - 1;
}
}
}
int main()
{
char arr[200] = "lyz like fzy!";
my_memmove(arr + 9, arr, 3);
printf("%s\n",arr);
return 0;
}
15.memset
函数的使用
- 功能:将内存中的值以字节为单位设置成想要的内容;
- 函数原型:
void * memset ( void * ptr, int value, size_t num );
memset使用:
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "lyz and fzy!";
memset(str, 'x', 3);
printf(str);
return 0;
}
16.memcmp
函数的使用
- 功能:完成内存的比较
- 函数原型:
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
- 比较
ptr1
和ptr2
指针指向的位置开始,向后的num
个字节; - 返回值:
memcmp
的使用:
#include <stdio.h>
int main()
{
int arr1[] = { 1,2,3,4,5,6,7 };
int arr2[] = { 1,2,3,4,8,8,8 };
int ret = memcmp(arr1, arr2, 20);
printf("%d\n", ret);
return 0;
}