C中常见的字符函数和内存函数讲解

字符串函数和内存函数

本文重点(前言)

介绍我们在平常编写代码时常见的字符串,以及怎么用c语言怎么实现并且该如何使用。
C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组 中。
字符串常量 适用于那些对它不做修改的字符串函数.

常见字符串的分类

  1. 求字符串的长度 - - -(strlen)
  2. 长度不受限制的字符串函数 - - -(strcpy strcat strcmp)
  3. 长度受限制的字符串函数介绍- - -(strncpy strncat strncmp)
  4. 字符串查找- - -(strstr strtok)
  5. 错误信息的报告- - -(strerror)
  6. 字符操作
  7. 内存操作函数- - -(memset memmove memcpy memcpy)

函数介绍

怎么在哪找参考资料

我们在学习这些字符函数光凭自己的知识储备是远远不够的,我们需要借鉴一些资料,我们可以在www.cpluscplus.com网站去查找。
对于这个网站现在更新了,变成了新版,如果喜欢用旧版的话可以点击右上角的[Legacy version]
在这里插入图片描述

函数介绍

(1)strlen

<1>strlen函数介绍

strlen的参数和返回值可以在www.cpluscplus.com上查询 ,如图:

在这里插入图片描述

strlen怎么用
由名字就可以看出strlen是由string+length组成的,意思就是求字符串长度,统计的就是字符串中 \0前的出现的字符个数,对于一个字符串 "hello"用双引号括住,包括 h e l l o \0这6个字符, \0用于结束一个字符串,而再用 strlen计算字符串的大小不算 \0这个字符。
有人问如果是中文怎么办对于c语言来说,其实一个中文占两个字符,知道这个就行了

在这里插入图片描述

strlen的参数
const char* str是被 const修饰的 char型不可修改的指针
strlen的返回值
size_t .可能有的同学不认识这个东西不妨打开vs编译器,对这个 转到定义查看,就能一目了然。用我们已知的知识可以知道 typedef是重命名,将无符号整型重命名为 size_t 所以 strlen的返回值是无符号整型。

在这里插入图片描述

关于strlen的返回值的例题
对于strlen的返回值是无符号整型
#include <stdio.h>
#include<string.h>
int main()
{
	if (strlen("abc") - strlen("abcdef") > 0)
	{
		printf(">\n");
	}
	else
	{
		printf("<\n");
	}
	return 0;
}

对于上述这道题,乍一看,可能觉得strlen("abc")是3,而strlen("abcdef")是6,3 - 6是 -3,小于0,但是我们要记住是strlen的返回值是无符号整型,没有负数,自动转换为整数所以正确答案是 > 在这里插入图片描述

<2>strlen函数的模拟实现
strlen函数的模拟实现代码
用指针-指针的方法实现strlen函数代码如下(对于相同类型的数据来说,按照c语言规定来说指针-指针就是元素个数)
#include<assert.h>
#include<stdio.h>
size_t my_strlen(const char* str)//用const修饰char*,表示不让修改str,让代码更健壮
{
	assert(str);//断言函数,防止str是空指针。
	const char* start = str;
	const char* end = str;
	while (*end!='\0')
	{
		end++;
	}
	return end-start;
}
int main()
{
	char arr[] = "abcdef";
	printf("len = %d\n", my_strlen(arr));
	return 0;
}

(2)strcpy

<1>strcpy的函数介绍

strcpy的参数和返回值可以在www.cpluscplus.com上查询 ,如图:在这里插入图片描述

strcpy函数是干什么的
由名字就可以看出strcpy是由string+copy组成的,意思就是字符串拷贝.
strcpy函数的参数是什么
char * destination, const char * source,可以看出有两个参数,从英文可以看出,一个是目的地,一个是源头,就是从源头拷贝到目的地。对于源头参数来说,是不可修改的所以用const修饰。
strcpy函数的返回值是什么
char *strcpy的返回值是char*,返回一个字符指针。
strcpy怎么用
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’ 拷贝到目标空间。
目标空间必须足够大,以确保能存放源字符串。
目标空间必须可变。
在这里插入图片描述
请找出下面代码的问题
代码如下
#include<stdio.h>
#include<string.h>
int main()
{
	char arr1 = "hello people";
	char arr2[20] = "abcedef";
	//将arr2的内容拷贝到arr1中
	printf("%s\n", strcpy(arr1, arr2));
	//第一个参数是目的地,第二个是源头。
	//因为返回值是char*所以可以链式访问
	return 0;
}

对于arr1来说,"hello people"是一个常量字符串,对于常量字符串来说是不可修改的。而我们知道strcpy的第一个参数是目的地是可修改的。

<2>strcpy的函数模拟实现
strcpy模拟实现的代码
代码如下
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{
	assert(dest && src);//断言,防止是空指针
	char* ret = dest;
	while (*ret++ = *src++)//就是拷贝,拷贝到\0的时候停下来。
	{
		;
	}
	return dest;//返回目的地的起始地址。
}
int main()
{
	char arr1[20] = "hello people";
	char arr2[20] = "abcedef";
	//将arr2的内容拷贝到arr1中
	printf("%s\n", my_strcpy(arr1, arr2));
	//第一个参数是目的地,第二个是源头。
	//因为返回值是char*所以可以链式访问
	return 0;
}

(3)strcat

<1>strcat的函数介绍

strcat的参数和返回值可以在[www.cpluscplus.com](strcpy的参数和返回值可以在www.cpluscplus.com上查询 ,如图:)上查询 ,如图:在这里插入图片描述

strcat函数是干什么的
这个从名字看不出来,但是可以看上述网站上对于该函数的功能介绍。
Appends a copy of the source string to the destination string. The terminating null characterin destination is overwritten by the first character of source, and a null-character is includedat the end of the new string formed by the concatenation of both in destination.
其实就是字符追加函数,比如 arr1[20]="hello";``arr2[20]="world";就可以用这个函数追加成 "hello world"
strcat函数的参数是什么
char * destination, const char * source,可以看出有两个参数,从英文可以看出,一个是目的地,一个是源头,就是从源头追加到目的地。对于源头参数来说,是不可修改的所以用const修饰。
strcat函数的返回值是什么
char *strcat的返回值是char*,返回一个字符指针。
strcat怎么用
源字符串必须以 ‘\0’ 结束。
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。
追加是从源字符串后 \0后追加。
在这里插入图片描述
<2>strcat的函数模拟实现
strcat模拟实现的代码
代码如下
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
	assert(dest && src);//断言,防止是空指针
	char* ret = dest;
	while (*dest)//读取到目的地的\0的位置
	{
		*dest++;
	}
	while (*dest++ = *src++)//追加
	{
		;
	}
	return ret;
}
int main()
{
	char arr1[20] = "hello ";
	char arr2[20] = "world";
	printf("%s\n", my_strcat(arr1, arr2));//链式访问
	return 0;
}
strcat模拟实现的代码思考一个问题,能不能自己给自己追加?
其实是不可以的,他有一定的缺陷,加入 arr1[20]="we"自己给自己追加w覆盖\0,e覆盖后面的\0,当原本的\0,没有了变为了w,就让这个不能够停下来,所以用自己追加自己时不要用strcat自己追加自己。

(4)strcmp

<1>strcmp的函数介绍

strcpy的参数和返回值可以在www.cpluscplus.com上查询 ,如图:
在这里插入图片描述

strcmp函数是干什么的
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.
由名字就可以看出strcmp是由string+compare组成的,意思就是字符串比较.
strcmp函数的参数是什么
const char * str1, const char *str2,可以看出有两个参数,从英文可以看出,是两个比较的参数。对于这两个比较的参数来说,都是是不可修改的所以用const修饰。
strcmp函数的返回值是什么
int,strcmp的返回值是int,返回一个整型变量。
strcmp函数怎么比较
标准规定:
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
比较对应位置的字符,比较他们的ASCⅡ值,如果相同就比较下一个,直到分出大小。
画图解释
请看下图
在这里插入图片描述
在这里插入图片描述

返回小于1的数字,说明arr1小于arr2,也说明我们的解释正确

<2>strcmp的函数模拟实现
strcmp模拟实现的代码
代码如下
#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);//断言
	while (*str1 == *str2 )//判断两个字符是否相等,如果相等,两个加分别+1,
	{
		if (*str1 == '\0')//如果都为\0那么两个字符串相等
		{
			return 0;
		}
		str1++;
		str2++;
	}
	return *str1 - *str2;//直接相减,为ascⅡ值相减,正负就是大小的表示
}
int main()
{
	char arr1[20] = "abcdef";
	char arr2[20] = "abq";
	printf("%d\n", my_strcmp(arr1, arr2));//链式访问
	return 0;

}

小总结

我们上面这些函数strcmpstrcpystrcat,这些函数都必须依赖\0,都看\0来进行他们的功能
所以我们叫这些函数是长度不受限制的字符串,不关注对几个字符进行拷贝,追加,和比较。
因此还存在一些函数是长度受限制的字符串,能对几个字符进行拷贝,追加,和比较。
比如strncmpstrncpystrncat,下面我们就介绍这些函数。

(5)strncpy

<1>strncpy的函数介绍

strncpy的参数和返回值可以在www.cpluscplus.com上查询 ,如图:

在这里插入图片描述

strncpy函数是干什么的
我们由上面的strcpy函数可知这是字符串拷贝函数,但是比他多了一个n,是长度受限制的字符串函数,比如:拷贝2个字符,不需要看 \0
其拷贝方法与 strcpy相同.
strncpy函数的参数
char * destination, const char * source, size_t num ,我们可以看出他对于strcpy多了一个 size_t num参数,其他参数相同,而这个参数就是控制要拷贝几个字符。n是几,就表示拷贝几个字符。
strncpy函数的返回值是什么
strncpy的返回值是 char*,返回一个字符指针。
在这里插入图片描述

(6)strncat

在这里插入图片描述

<1>strncat的函数介绍

strncat的参数和返回值可以在www.cpluscplus.com上查询 ,如图:

strncat函数是干什么的
我们由上面的strcat函数可知这是字符串追加函数,但是比他多了一个n,是长度受限制的字符串函数,比如:追加2个字符,不需要看 \0
其追加方法与 strcat相同.
strncat函数的参数
char * destination, const char * source, size_t num ,我们可以看出他对于strcpy多了一个 size_t num参数,其他参数相同,而这个参数就是控制要追加几个字符。n是几,就表示追加几个字符。
strncat函数的返回值是什么
strncat的返回值是 char*,返回一个字符指针。
在这里插入图片描述
strncat的库函数思考上面一个问题,能不能自己给自己追加?
其实是可以的,追加后,自己在最后自动补上 \0,因此如果自己给自己追加,就用 strncat函数.

(7)strncmp

在这里插入图片描述

<1>strncmp的函数介绍

strncmp的参数和返回值可以在[www.cpluscplus.com](strncmp的参数和返回值可以在www.cpluscplus.com上查询 ,如图:)上查询 ,如图:

strncmp函数是干什么的
我们由上面的 strcmp函数可知这是字符串追加函数,但是比他多了一个n,是长度受限制的字符串函数,比如:比较2个字符,不需要看 \0
其追加方法与 strcmp相同.
strncmp函数的参数
const char * str1, const char * str2, size_t num ,我们可以看出他对于 strcmp多了一个 size_t num参数,其他参数相同,而这个参数就是控制要比较几个字符。n是几,就表示比较几个字符。
strncmp函数的返回值是什么
strncmp的返回值是 int,返回一个整型。

在这里插入图片描述

可以看出,比较前三个字符,发现相同,返回值就是0,并且他也是一个一个字符比较。

(8)strstr

在这里插入图片描述
在这里插入图片描述

<1>strstr的函数介绍

strstr的参数和返回值可以在www.cpluscplus.com上查询 ,如图:

strstr函数是干什么的
其实这个函数很好理解,就是在一个字符串里找另一个字符串,看他是否存在于这个字符串中。
比如:在 "abcdefabcdef"字符串中找到 "fab"字符串,就用 strstr函数
如果存在,返子串第一次出现的起始地址,
不存在,返回NULL
strstr函数的参数
const char * str1, const char * str2 ,因为是查找字符串,所以两个字符串都不能修改。所以都用const修饰。在第一个字符串中找第二个字符串。
strstr函数的返回值是什么
strstr的返回值是 char * ,返回一个字符型指针。

在这里插入图片描述

<2>strstr的函数模拟实现
strstr模拟实现的代码
代码如下
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);//断言
	char* p = str1;
	char* s1 = str1;
	char* s2 = str2;
	while (*p)
	{
		s1 = p;
		s2 = str2;
		while (*s1!='\0'&&*s2!='\0'&& * s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return p;//找到字串
		}
		
		p++;
	}
	return NULL;//找不到字串
}
int main()
{
	char arr1[20] = "abcdefabcdef";
	char arr2[20] = "fab";
	char* p= my_strstr(arr1, arr2);
	if (p == NULL)
	{
		printf("没找到字符串。\n");
	}
	else
	{
		printf("%s\n", p);
	}

	return 0;
}

(9)strtok

在这里插入图片描述

<1>strtok的函数介绍

strtok的参数和返回值可以在www.cpluscplus.com上查询 ,如图:

strtok函数是干什么的
这个函数有点不好理解,其实可以理解成字符串分割函数,将一个字符串通过分割符分割成几个单个的字符,从而得到这几个单个的字符,但是需要注意的是使用 strtok会改变原字符串,所以一般先将字符串拷贝,然后将拷贝的字符串进行分割。
比如:现在又一个字符串 123456@QQ.com,分隔符是 '@和.',就可以使用这个函数将字符串分割成 123456, QQ , com,三个字符串。
但是需要注意的一点就是:再找第二个分割字符串时,他已经将第一个字符串的分割符变为 \0,这样打印时就能直接答应,所以在分割第二个字符串时,传空指针直到找到下一个分割符。
不动就看下面代码有注释。
strtok函数的参数
char * str, const char * delimiters ,第一个字符指针指向是要被分割的字符的地址。而第二个字符指针指向分隔符的地址。
strtok函数的返回值是什么
strtok的返回值是 char * ,返回一个字符型指针,返回是分割字符串的起始位置。
在这里插入图片描述

但是这个方法有点挫,你必须知道分割几回,再写每回分割的代码。那有没有好一点的代码呢,能够直接将字符串分割。那肯定有呀。

在这里插入图片描述

这样通过一个循环就能够知道能分割几个字符串了。这样就很智能。

需要注意的几点
1.sep参数是个字符串,定义了用作分隔符的字符集合
2.第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
3.strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
4.strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
5.strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
6.如果字符串中不存在更多的标记,则返回 NULL 指针。

(10)strerror

在这里插入图片描述

<1>strerror的函数介绍

strerror的参数和返回值可以在www.cpluscplus.com上查询 ,如图:

strerror函数是干什么的
返回错误码,所对应的错误信息。我们平常上网遇到的404就是错误码。
这个错误码就是c语言自己规定的
请看下图就可以明白。
在这里插入图片描述
strerror函数的参数
int errnum这个就是错误码,通过错误码来看到是错了什么。
strerror函数的返回值是什么
char *我们从上图可以知道错误信息是一个字符串,通过字符指针来找到这个字符串
strerror函数的应用场景
我们要先看了解 errnoerrno就是将错误信息记录到错误码里的东西。
在这里插入图片描述
补充
perror,也是打印错误信息的函数其实相当于 printf+strerror.
在这里插入图片描述
在这里插入图片描述

字符分类函数:

函数如果他的参数符合下列条件就返回真
iscntrl任何控制字符
isspace空白字符:空格‘ ’,换页‘\f’,换行’\n’,回车‘\r’,制表符’\t’或者垂直制表符’\v’
isdigit十进制数字 0~9
isxdigit十六进制数字,包括所有十进制数字,小写字母af,大写字母AF
islower小写字母a~z
isupper大写字母A~Z
isalpha字母az或AZ
isalnum字母或者数字,az,AZ,0~9
ispunct标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph任何图形字符
isprint任何可打印字符,包括图形字符和空白字符

这些函数都比较简单,可以直接操作,不懂可以上上面的网站上自己看看,他非常简单。

(11)memcpy

在这里插入图片描述

<1>memcpy的函数介绍

memcpy的参数和返回值可以在www.cpluscplus.com上查询 ,如图:

memcpy函数是干什么的
其实这个函数很好理解,可以从字面上理解,memory+copy,就是内存拷贝函数,也是内存函数,这时有的同学就会问,那这和strcpy函数有什么区别呢,其实我们可以通过函数的参数就能明白区别在哪了。memcpy的函数参数是 void*类型,说明他什么都能拷贝,而strcpy不一样,只能拷贝字符串。
memcpy函数的参数
void * destination, const void * source, size_t num
因为是拷贝,源头参数都不能修改,所以用const修饰。
size_t就是拷贝 多少字节个数,这个很重要。如果拷贝一个整型,那么就是4个字节。
memcpy函数的返回值是什么
memcpy的返回值是 void* ,因为不知道返回的是什么类型所以我们用 void*类型接收。

在这里插入图片描述

<2>memcpy的函数模拟实现
memcpy模拟实现的代码
代码如下
void* my_memcpy(void* dest, void* src, size_t num)
{
	assert(dest && src);//断言
	char* ret = dest;
	while (num--)
	{
		*(char*)dest = *(char*)src;
		//因为char*是一个字节一个字节读取,所以我们强制转换为char*类型
		dest = (char*)dest + 1;
		//因为dest是void*类型所以可以接受任何类型,将dest强制类型转换为char*+1,就很合理
		src = (char*)src + 1;
	}
	return ret;
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	my_memcpy(arr2, arr1, 20);
	//拷贝20个字节也就是5个整形。
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d\n", arr2[i]);
	}
	return 0;
}
}

但是如果我们思考一下如果自己拷贝自己几个字符,你觉得用上面这个代码合适吗。
显然这个是不太合适的。当我们自己拷贝自己时,可能会改变我们需要拷贝的字符,进而我们最后拷贝的字符就变成了拷贝完的字符,下来同学们自己思考思考应该怎么做。
所以memcpy一般是不能拷贝重叠的字符,但是在vs编译器下,比较智能,可以实现但是在其他编译器上就有可能不会实现
因此就又有一个函数memmove,内存移动函数,就可移动重叠的字符。

(12)memmove

在这里插入图片描述

<1>memmove的函数介绍

memmove的参数和返回值可以在www.cpluscplus.com上查询 ,如图:

memmove函数是干什么的
其实这个函数很好理解,可以从字面上理解,memory+move,就是内存移动函数,也是内存函数,
memmove函数的参数
void * destination, const void * source, size_t num
因为是只是移动,源头参数都不能修改,所以用const修饰。
size_t就是移动 多少字节个数,这个很重要。如果移动一个整型,那么就是4个字节。
memmove函数的返回值是什么
memmove的返回值是 void* ,因为不知道返回的是什么类型所以我们用 void*类型接收。
注意
和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用 memmove函数处理。

在这里插入图片描述

(13)memcmp

在这里插入图片描述

<1>memcmp的函数介绍

memcmp的参数和返回值可以在www.cpluscplus.com上查询 ,如图:

memcmp函数是干什么的
其实这个函数很好理解,可以参考memcpy,相当于字符串比较的拓展,就是对于什么都可以比较,也是内存函数,比较方法和strcmp比较类似。
memcmp函数的参数
const void * ptr1, const void * ptr2, size_t num
因为是只是比较,两个参数都不能修改,所以用const修饰。
size_t就是移动 多少字节个数,这个很重要。如果比较一个整型,那么就是4个字节。
memmove函数的返回值是什么
memcpy的返回值是 void* ,因为不知道返回的是什么类型所以我们用 void*类型接收。

在这里插入图片描述

(14)memset

在这里插入图片描述

<1>memset的函数介绍

memset的参数和返回值可以在www.cpluscplus.com上查询 ,如图:

memset函数是干什么的
其实这个函数很好理解,memset,就是内存设置函数,将指定的内存设置为指定的内存。
memset函数的参数
void * ptr, int value, size_t numint value就是要将内存设置成什么类型。
size_t就是设置 多少字节个数,这个很重要。如果设置一个整型,那么就是4个字节。
memset函数的返回值是什么
memset的返回值是 void* ,因为不知道返回的是什么类型所以我们用 void*类型接收。

在这里插入图片描述

本文总结

本文主要就是介绍字符串函数和内存设置函数的使用和模拟实现,不过就都是九牛一毛,希望大家可以举一反三,明白怎么学习库函数,网站也给大家了,方法也交给大家啦,我相信大家的学习能力,以后遇到自己没见过的库函数一定可以自己解决,希望大家一键三联,一起加油!!!!😊😊

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

桐桐超努力

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值