【C语言】字符函数和内存操作函数

这篇具有很好参考价值的文章主要介绍了【C语言】字符函数和内存操作函数。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

大家好,我是苏貝,本篇博客带大家了解字符函数和内存操作函数,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️
【C语言】字符函数和内存操作函数,c语言,开发语言


一.字符函数

1.1 字符分类函数

下面函数的头文件都是<ctype.h>

函数 如果他的参数符合下列条件就返回真即非0,不符合则返回0
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 任何可打印字符,包括图形字符和空白字符

其实字符分类函数很简单,下面就挑两个作为范例
范例1:

int main()
{
	int ret1 = islower('X');//X不是小写字母,返回0
	int ret2 = islower('f');//f是小写字母,返回非0的数
	printf("%d %d", ret1, ret2);
	return 0;
}

【C语言】字符函数和内存操作函数,c语言,开发语言

范例2:

int main()
{
	int ret1 = isxdigit('a');//a是16进制数字
	int ret2 = isxdigit('z');//z不是16进制数字,返回0
	int ret3 = isxdigit('4');//4是16进制数字
	printf("%d %d %d", ret1, ret2, ret3);
	return 0;
}

【C语言】字符函数和内存操作函数,c语言,开发语言

1.2 字符转换函数

字符转换函数只有两个,分别是tolower和toupper,它们的函数原型为:

int tolower ( int c ); //将大写字母转化为小写字母
int toupper ( int c );//将小写字母转化为大写字母

其中,参数的类型为int,是将字符的ASCII码值传过去,返回的也是字符的ASCII码值,所有返回类型也是int

范例1:

int main()
{
	int x = toupper('a');
	printf("%c\n", x);
	x = tolower(x);
	printf("%c\n", x);
	return 0;
}

【C语言】字符函数和内存操作函数,c语言,开发语言

范例2:
将数组arr中的字符全都变成小写字母

int main()
{
	char arr[] = "ABcdeFGhIjk";
	char* p = arr;
	while (*p)
	{
		if (isupper(*p))
		{
			*p = tolower(*p);
		}
		p++;
	}
	printf("%s", arr);

	return 0;
}

【C语言】字符函数和内存操作函数,c语言,开发语言


二.内存操作函数

2.1 memcpy

①函数介绍

void * memcpy ( void * destination, const void * source, size_t num );

memcpy函数的功能:从source的位置开始向后复制num个字节的数据到destination的内存位置。返回值:目标空间的起始位置。这与strcpy函数的功能很相似,那为什么我们已经有了strcpy函数还要设计memcpy函数呢?因为strcmp函数只能拷贝字符串,而内存空间可不是只有字符的,所有我们需要能拷贝非字符类型的函数,memcpy函数应运而生

细节:destination和source的类型都为void * :因为设计该函数的程序员不知道用户想要拷贝的类型,所有用void * 来接收所有类型的指针。source被const修饰:源内存块的内容不会被修改。num是指num个字节

注意:
1.这个函数在遇到 ‘\0’ 的时候并不会停下来。
2.如果source和destination有任何的重叠,复制的结果都是未定义的

范例:
把arr2中的前5个整型的数据拷贝放在arr1中

int main()
{
	int arr1[10] = { 0 };
	int arr2[] = { 1,2,3,4,5 };
	memcpy(arr1, arr2, 20);//20:5*sizeof(int)=5*4
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

【C语言】字符函数和内存操作函数,c语言,开发语言

②模拟实现

模拟函数的三个参数没有改变,依旧是只需要源内存块的起始地址和目标空间的起始地址以及要拷贝的字节数。先对dest和src断言,避免它们为空指针。用while循环num次,当num==0时退出循环。接下来就是将src的内容拷贝到dest中。因为src和dest指针都是void * 类型的,所有需要先强制类型转化为char * ,拷贝一次后,两指针都要指向下一个字节,因为强制类型转化是暂时的,所有完成赋值语句后,两指针还是void * 类型,所有为了指向下一个字节,我们需要再对它们强制类型转化为char * 类型,写成dest=(char*)dest + 1;那可以写成(char*)dest++;吗?不能,因为++的优先级高于强制类型转化。那可以写成++(char*)dest;吗?最好不要,有些编译器会报错

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;
}

③我们是否可以用所写的模拟函数让下面代码的数组arr从第5个元素开始往后的5个字符作为源内存块,将第3个元素开始往后的5个字符作为目标内存块,从source的位置开始向后复制num个字节的数据到destination的内存位置呢?即将数组arr变为{ 1,2,3,4,3,4,5,6,7,10}

void* my_memcpy(void* dest, const void* src, size_t num)
{
	void* ret = dest;
	assert(dest && src);
	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memcpy(arr + 4, arr + 2, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

答案是不能的,因为当程序想将5赋值给元素7时,5已经被3覆盖。同理,6已经被4覆盖,7已经被3覆盖
【C语言】字符函数和内存操作函数,c语言,开发语言
我们注意到这次的拷贝的源内存块和目标内存块是重叠的,而我们上面写的模拟函数的源内存块和目标内存块要求是不重叠的,所以使用失败。那我们如何解决源内存块和目标内存块重叠时成功拷贝呢?别急,有一个函数可以解决,那就是memmove函数

补充:其实有一些编译器的memcpy函数可以处理源内存块和目标内存块重叠的情况,但是并非所有,因此遇见两内存块重叠的情况时最好还是选择memmove函数


2.2 memmove

①函数介绍

void * memmove ( void * destination, const void * source, size_t num );

1.和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的,其余都相同
2.如果源空间和目标空间出现重叠,就得使用memmove函数处理

你瞧,memcpy解决不了的问题memmove轻松搞定

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove(arr + 4, arr + 2, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

【C语言】字符函数和内存操作函数,c语言,开发语言

②模拟实现
以上面代码的arr数组举例,如果源内存块是从元素3开始的5个元素,目标内存块是从元素5开始的5个元素,此时如果要拷贝,为避免有些重要的值事先被覆盖,我们就要从后往前拷贝,即从源内存块的最后一个字节开始拷贝
【C语言】字符函数和内存操作函数,c语言,开发语言

如果源内存块是从元素3开始的5个元素,目标内存块是从元素1开始的5个元素,此时如果要拷贝我们就要从前往后拷贝
【C语言】字符函数和内存操作函数,c语言,开发语言

如果源内存块和目标内存块无重叠,那么拷贝既可以从前往后也可以从后往前
【C语言】字符函数和内存操作函数,c语言,开发语言

所以我们可以这样想:
1.dest<src时,从前往后拷贝
2.dest>src时,从后往前拷贝

dest<src时,与上面的memcpy模拟实现的思路相同,不再赘述。现在我们来思考如何从后往前拷贝。我们依旧用while循环,循环num次,当num==0时退出循环,while(num)。从后往前拷贝,就是将源内存块的最后一个字节拷贝到目标内存块的最后一个字节,再将源内存块的倒数第二个字节拷贝到目标内存块的倒数第二个字节……本题中,num=20,所以源内存块的最后一个字节的地址是(char*)src+19,目标内存块的最后一个字节的地址是(char*)dest+19。源内存块的倒数第二个字节的地址是(char*)src+18,目标内存块的倒数第二个字节的地址是(char*)dest+18。我们发现,第一次循环的时候19=num(20)-1,经历一次循环,num–=19;第二次循环的时候18=num(19)-1,经历一次循环,num–=18;那我们是不是在while循环的条件中写成while(num–)呢?这样的话每次循环源内存块字节的地址=(char*)src+num,所以写成如下写法

void* my_memmove(char* dest, char* src, size_t num)
{
	assert(dest && src);
	void* ret=dest;
	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;
}

2.3 memset

memset是以字节为单位设置内存的。比如我可以让字符数组arr=“hello world"中从第3个元素开始的5个字符都变成字符’x’,即变成"hexxxxxorld”。

void * memset ( void * ptr, int value, size_t num );

范例1:

int main()
{
	char arr[] = "hello world";
	memset(arr + 2, 'x', 5);
	printf("%s", arr);
	return 0;
}

【C语言】字符函数和内存操作函数,c语言,开发语言

范例2:
下面代码的目的是用memset函数将arr数组中的元素全部改成1,可以做到吗?

int main()
{
	int arr[5] = { 0 };
	memset(arr, 1, 20);
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

如果你觉得可以的话,请看看最后的结果吧!为什么不是我们所想的全是1呢?

【C语言】字符函数和内存操作函数,c语言,开发语言
经过调试我们可以看到,调用完成memset后,数组arr的每个字节都由0变1,导致每个整型元素都变为0x01010101,所以不能用memset函数将arr数组中的元素全部改成1。所以memset更适用于字符数组
【C语言】字符函数和内存操作函数,c语言,开发语言

但是可以将数组中的每个元素都变为0,因为将每个字节都变为0即每个整形元素都为0

int main()
{
	int arr[5] = { 1,2,3,4,5 };
	memset(arr, 0, 20);
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

【C语言】字符函数和内存操作函数,c语言,开发语言


2.4 memcmp

int memcmp ( const void * ptr1,const void * ptr2,size_t num );

memcmp函数是比较从ptr1和ptr2指针开始的num个字节的大小,如果 * ptr1> * ptr2,返回一个正数;如果 * ptr1== * ptr2,返回0;如果 * ptr1< * ptr2,返回一个负数。依旧是比较以字节为单位进行比较

int main()
{
	int arr1[] = { 1,2,3,4,5 };
	//假如是小端存储
	//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00
	int arr2[] = { 1,2,0x11223304 };
	//01 00 00 00 02 00 00 00 04 33 22 11
	int ret = memcmp(arr1, arr2, 9);
	printf("%d", ret);
	return 0;
}

用memcmp函数时,切记不要拿数组中的元素直接比较,我们要看它们各自的存储情况。本题两个数组在前8个字节都相等,看第9个字节,03<04,所以前面<后面,返回一个负数
【C语言】字符函数和内存操作函数,c语言,开发语言


好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞👍吗,感谢看到这里,我们下篇博客见❤️文章来源地址https://www.toymoban.com/news/detail-713991.html

到了这里,关于【C语言】字符函数和内存操作函数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • <C语言> 字符串内存函数

    C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在 常量字符串 或者 字符数组 中。 字符串常量 适用于那些对它不做修改的字符串函数. 注意:字符串函数都需要包含头文件string.h strlen() 函数用于计算字符串的长度,即字符串中字符

    2024年02月15日
    浏览(47)
  • 金丹三层 —— 内存函数和字符串操作函数详解

    目录 一.修炼必备 二.字符串操作的常用函数 2.1 strlen()函数 2.2 strcpy()函数 2.3 strcat()函数 2.4 strcmp()函数 2.5 strstr()函数 2.6 strtok()函数 2.7 strerror()函数 三.内存操作的常用函数 3.1 memcpy()函数 3.2 memmove()函数 3.3 memcmp()函数 结语 1.入门必备:VS2019社区版,下载地址:Visual Studio 较旧的

    2023年04月08日
    浏览(49)
  • C语言进阶---字符串+内存函数

    重点介绍处理字符和字符串的库函数的使用和注意事项。 求字符串长度 strlen() 长度不受限制的的字符串函数 strcpy() strcat() strcmp() 长度受限制的的字符串函数 strncpy() strncat() strncmp() 字符串查找 strstr() strtok() 错误信息报告 strerror() 字符操作 内存操作函数 memcpy() memmove() memset(

    2024年02月12日
    浏览(53)
  • 【C语言】字符函数与字符串函数以及内存函数 { 超详细攻略,一篇学会 }

    今日分享:字符、字符串函数和内存函数 内存函数 就是对内存进行操作的函数 字符串函数 就是对字符串进行操作的函数 字符函数 就是对字符进行操作的函数 str 前缀的函数是字符串函数,头文件string.h mem 前缀的函数是内存函数,头文件stdlib.h 字符分类函数包含在 ctype.h 头

    2024年03月18日
    浏览(60)
  • 进阶C语言——字符串和内存函数

    今天我们学点库函数 字符函数和字符串函数 求字符串长度函数-strlen strlen需要的头文件是string.h ,那它的作用是什么呢?? 他是来求字符串长度的,统计的是’\\0’前的字符串长度 size_t是无符号的意思 学会了strlen函数怎么使用,那我们现在模拟实现一下strlen 之前讲过三种方

    2024年02月16日
    浏览(52)
  • 【c语言:常用字符串函数与内存函数的使用与实现】

    简介:本篇文章是对C语言中常用的字符串函数和内存函数的学习以及模拟实现 文档内容来自:https://legacy.cplusplus.com/ 字符串以 ‘\\0’ 作为结束标志, strlen函数返回的是在字符串中 ‘\\0’ 前⾯出现的字符个数( 不包含 \\\'\\0\\\' )。 参数指向的字符串必须要以 ‘\\0’ 结束。 注意函

    2024年02月04日
    浏览(46)
  • 【C语言基础】:内存操作函数

             书山有路勤为径,学海无涯苦作舟。 创作不易,宝子们!如果这篇文章对你们有帮助的话,别忘了给个免费的赞哟~ 一、memcpy函数的使用和模拟实现 函数原型 : 内存复制块 将num字节的值从源指向的位置直接复制到目标指向的内存块。 源指针和目标指针所指向的对

    2024年04月11日
    浏览(39)
  • 一篇博客学会系列(1) —— C语言中所有字符串函数以及内存函数的使用和注意事项

    目录 1、求字符串长度函数 1.1、strlen 2、字符串拷贝(cpy)、拼接(cat)、比较(cmp)函数 2.1、长度不受限制的字符串函数 2.1.1、strcpy 2.1.2、strcat 2.1.3、strcmp 2.2、长度受限制的字符串函数 2.2.1、strncpy 2.2.2、strncat 2.2.3、strncmp 3、字符串查找函数 3.1、strstr 3.2、strtok 4、错误信息报告函数

    2024年02月08日
    浏览(49)
  • C语言----字符串操作函数汇总

            在C的库函数中,有丰富的字符串操作函数,在平时的coding中灵活运用这些库函数会达到事半功倍的效果 char *strcpy(s, ct) 将字符串ct(包括\\\'\\0\\\')复制到字符串s中,并返回s,需要注意s的长度是否容纳ct。 char *strncpy(s, ct, n) 将字符串ct中最多n个字符复制到字符串s中,并

    2024年02月14日
    浏览(53)
  • 【C语言进阶(三)】字符串操作函数

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:C语言学习分享⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习更多C语言知识   🔝🔝 C语言的标准库为我们提供了丰富的字符串操作函数与内存操作函数,有我们熟悉的 strlen ,strcpy ,也有我们不熟悉的 strchr , strstr 等

    2024年02月09日
    浏览(72)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包