C语言字串函数、内存函数介绍以及模拟实现

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

   

目录

前言

本期内容介绍:

一、字符串函数

strlen介绍

strlen 模拟实现(三种方式)

方法一:计数器法

 方法二:递归法(不创建临时变量法)

方法三:指针-指针

strcpy介绍

strcpy模拟实现

​编辑strcmp介绍

strcmp模拟实现

strcat介绍

strcat模拟实现

strncpy介绍

strncpy模拟实现

strncmp介绍

strncmp模拟实现

​编辑strncat介绍

strncat模拟实现

 strstr介绍

strstr模拟实现

strtok介绍

 strtok模拟实现【了解】

strerror介绍

二、字符函数【了解】

 三、内存函数

memcpy介绍

memcpy模拟实现

memmove介绍

memmove模拟实现

memset介绍

memset模拟实现

memcmp介绍

memcmp模拟实现


前言

我们以前在求字符串的时候会经常用strlen来求字符串的大小!我们仅仅知道他是一个库函数,它的详细介绍我们好像没有了解过,本期小编将带你来了解各种字符串函数和内存函数,以及模拟实现比较重要的函数!

本期内容介绍:

字符串函数:

字符串长度:strlen

长度不受限制的字符串函数:strcpy strcat strcmp

长度受限制的字符串函数:strncpy strncat strncmp

字符串查找函数:strstr strtok

错误信息报告函数:strerror

各种字符函数介绍

内存操作函数memcpy memmove memset memcmp

上面加粗绿色的函数为重点函数,会模拟实现!

一、字符串函数

strlen介绍

我们先来看一下官网上的介绍:

C语言字串函数、内存函数介绍以及模拟实现,c语言

这个函数的返回值是size_t , 参数是 const char* str 这里用const修饰是说明str指向的字符串不能被修改!该函数的作用是求字符串的长度,字符串的结束标志是'\0' ,strlen函数返回的是字串的长度,即到'\0'之前的字符个数(不包括'\0')。该函数的参数指向的字符串的必须要以'\0'结束!它的返回值是:size_t(这个我们前面说过实际上是无符号整形)。

OK!了解了它的用法我们来举个栗子实操一下:

#include<stdio.h>
#include<string.h>

int main()
{
	char str1[] = "abcdef";
	char* str2 = "abcdef";
	char str3[] = { 'a', 'b', 'c', 'd', 'e','f' };
	printf("str1 = %d\n", strlen(str1));
	printf("str2 = %d\n", strlen(str2));
	printf("str3 = %d\n", strlen(str3));
	return 0;
}

思考一下结果是多少?

看结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

前两个都应该没什么问题,问题就是最后一个,为什么他是19呢?不明明str3数组里面就6个字符怎么会是19?其实他不一定是19,他应该是一个随机值!原因: 该函数的参数指向的字符串的必须要以'\0'结束!这个数组的\0在哪里,不知道!所以他会继续找直至知找到\0就停止!我们来调试看一看:

C语言字串函数、内存函数介绍以及模拟实现,c语言

左右两边其实都能够看出来!左边str1和str2都是后面没有...这就说明字符串结束了!而str3后面还有!右边str1数组里面有六个字符而这里显示大小是7说明后面有一个\0而str3只有六个字符没有\0所以是6!str3在计算长度的时候 找不到\0他就会一直越界找直至找到了就返回到\0的长度!如果要让strlen(str1)和strlen(str3)相等需要在str3里面加入一个'\0'即可!

C语言字串函数、内存函数介绍以及模拟实现,c语言

关于这个函数再来看一个笔试题:

int main()
{
	const char* str1 = "abcdef";
	const char* str2 = "bbb";

	if (strlen(str2) - strlen(str1) > 0)
	{
		printf("str2 > str1\n");
	}
	else
	{
		printf("str1 > str2\n");
	}
	return 0;
}

思考一下结果是多少?

看结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

为什么是str2 > str1?不应该是str1 > str2吗?是的,的确应该是 str1 > str2。这里是因为strlen的返回值是size_t(unsigned int)他们的返回值恒大于等于0,两者作差也是恒大于等于0!因此走了if这样写达不到我们的效果,要比较两个字符串的长度大小。

写成下面就可以(让他们直接比较不要作差!):

C语言字串函数、内存函数介绍以及模拟实现,c语言

OK,strlen的介绍就到这里!下面我们来模拟实现一下!

strlen 模拟实现(三种方式)

strlen函数实际上返回的是\0之前的字符个数!所以相当于我们只需要想办法返回\0之前的字符个数即可!

方法一:计数器法

size_t my_strlen(const char* str)
{
	assert(str);
	int count = 0;

	while (*str++)
	{
		count++;
	}

	return count;
}

看结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

 方法二:递归法(不创建临时变量法)

size_t my_strlen(const char* str)
{
	assert(str);

	if (*str == '\0')
		return 0;
	else
		return 1 + my_strlen(str + 1);
}

看结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

方法三:指针-指针

我们在指针基础哪里介绍过:指针-指针得到的是两指针之间的字符个数! 

size_t my_strlen(const char* str)
{
	assert(str);
	const char* ret = str;
	
	while (*str)
		str++;

	return str - ret;
}

看结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

strcpy介绍

我们先来看一看官网对他的介绍:

C语言字串函数、内存函数介绍以及模拟实现,c语言

该函数的作用是拷贝字符串。strcpy有两个参数,一个是char* destination 另一个人是const char* source,意思就是从source这个指针指向的数组向destination指针指向的数组拷贝内容(包括\0),它的返回值是char*返回的是destdination 的地址!同样,source 指向的数组仅仅让拷贝不让其修改内容,所以用const 修饰!而且还要注意的是:source指向的那个数组必须要有\0destination指向的那个数组的空间必须得足够大能放得下source指向的那个字符串!

OK!举个栗子:

int main()
{
	char str1[20] = "abcdef";
	char str2[] = "bbb";
	strcpy(str1, str2);
	printf("%s\n", str1);
	return 0;
}

看结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

他果然拷贝过去了,而且还把\0也拷贝过去了! 下面我们来模拟实现一下:

strcpy模拟实现

我们知道拷贝实际上是一个一个的搬过去,我们也就依靠这用思路实现!

char* my_strcpy(char* dest, const char* src)
{
	assert(dest);
	assert(src);

	char* ret = dest;
	while (*dest++ = *src++)
		;

	return ret;
}

上面这个代码就是*src先解引用赋值给*dest然后连个都++;等*src = '\0'赋值给*dest的时候while循环判断为假结束,此时正好把source里面的所有内容都拷贝过去了!

上面的方法很巧妙,但实际上我们第一个想到的应该是下面这个版本(比较容易理解):

char* my_strcpy(char* dest, const char* src)
{
	assert(dest);
	assert(src);

	char* ret = dest;
	while (*src)
	{
		*dest = *src;
		dest++;
		src++;
	}

	*dest = '\0';

	return ret;
}

这里当source的拷贝结束之后在最后加上\0即可!我们来验证一下:

C语言字串函数、内存函数介绍以及模拟实现,c语言

strcmp介绍

老样子先来看一看官网的介绍:

C语言字串函数、内存函数介绍以及模拟实现,c语言

这个函数是比较字符串他有两个参数:str1 和 str2 都是被const修饰原因是仅仅比较他们不需要改变!他是从两个字符串的第一个字符开始比较,相同跳过,不同时看第一个字符串的字符是否大于第二个字符串字符的大小(ASCII)!如果第一个字符串的字符大于第二个字符串的字符返回正数,小于返回负数,等于返回0!

OK!举个栗子用一下:

int main()
{
	char str1[] = "acbdef";
	char str2[] = "abcdef";
	if (strcmp(str1, str2) > 0)
		printf("str1 > str2\n");
	else if (strcmp(str1, str2) < 0)
		printf("str1 <str2\n");
	else
		printf("str1 == str2\n");
	return 0;
}

我们先来分析一下:str1数组的a 和str2数组的 a相等说以跳过比较下一个字符!第一个字符的c 大于第二个字符的b所以返回str1 >str2

我们来看一下结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

果然和我们分析的一样 !OK!这个函数我们同样来实现一下:

strcmp模拟实现

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1);
	assert(str2);

	while (*str1 || *str2)
	{
		if (*str1 > *str2)
			return 1;
		else if (*str1 < *str2)
			return -1;

		str1++;
		str2++;
	}

	return 0;
}

这是一种实现思路,循环判断条件那里只要两个字符串有一个不是\0也就是有一个没结束就可以比较!即使一个是\0另一个不是\0还是可以比较的,\0的ASCII的是0,其他任何字符都比0大!当他们两个都是\0说明两个字符串是一样的!

看一下结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

当然这个代码也可以这样写:

int my_strcmp(const char* str1, const char* str2)
{
	assert(str1);
	assert(str2);

	while (*str1 == *str2)
	{
		if (*str1 == '\0')
			return 0;

		str1++;
		str2++;
	}

	if (*str1 > *str2)
		return 1;
	else
		return -1;

}

当两个字符串相等的时候各自++,并且判断一下:如果两个中的一个是\0因为连个相等所以另一个也就是\0这就说明两个字符串的内容是一样的返回0即可!否可外面在判断一下!大于返回1小于返回-1!

C语言字串函数、内存函数介绍以及模拟实现,c语言

strcat介绍

我们先来看看官网对他的介绍:

C语言字串函数、内存函数介绍以及模拟实现,c语言

strcar这个函数有两个参数一个是destination和被const修饰的source,后者不需要改变所以用const修饰!该函数的作用是连接字符串,将source指向的字符连接到destination指向字符串的后面,destination指向字符串的\0被source指向的第一个字符覆盖!并且会在新字符串的后面加上一个\0,返回的是destination的地址(连接后的字符串的地址) 。

OK!举个栗子用一下:

int main()
{
	char str1[20] = "abcdef";
	char str2[] = "123456";
	strcat(str1, str2);
	printf(str1);
	return 0;
}

看结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

OK!连接成功!我们还是来模拟实现一下:

strcat模拟实现

当找到dest指向字符串的\0后,将src指向的字符串内容逐一给dest即可!

char* my_strcat(char* dest, const char* src)
{
	assert(dest);
	assert(src);

	char* ret = dest;
	while (*dest)
		dest++;

	while (*dest++ = *src++)
		;

	return ret;
}

 我们来看一下结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

这里还有一个问题就是:字符串能不能给自己追加?验证一下:

C语言字串函数、内存函数介绍以及模拟实现,c语言 这里不是什么都没有输出而是这个程序挂了! 一般正常的程序结束是后面的那个代码为0,异常结束为负数!

为什么呢?下面我画个图来解释一下:

C语言字串函数、内存函数介绍以及模拟实现,c语言

strncpy介绍

老样子先看官网介绍:

C语言字串函数、内存函数介绍以及模拟实现,c语言

这个函数和上面的strcpy就差一个参数不一样!它的作用是:从source指向的字符串拷贝num个字符到destination 指向的字符串中,如果拷贝num个字符时发现已经到了source指向的字符串的末尾也就是\0,则destination剩下的用0填充知道够num!而且源头也目标不能重叠!关于最后重叠拷贝这个问题后面memmove会说明!

OK!举个栗子用一下:

int main()
{
	char str1[20] = "abcdef";
	char str2[] = "123456";
	strncpy(str1, str2,2);
	printf("%s\n",str1);
	return 0;
}

看结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

果然把str2中的两个之父 拷贝过去了!那下面我们就来实现一下:

strncpy模拟实现

char* my_strncpy(char* dest, const char* src, size_t num)
{
	assert(dest);
	assert(src);

	char* ret = dest;
	while (num--)
	{
		*dest++ = *src++;
	}

	return ret;
}

验证一下:

C语言字串函数、内存函数介绍以及模拟实现,c语言

strncmp介绍

老样子先看官网介绍:

C语言字串函数、内存函数介绍以及模拟实现,c语言

这个函数也和上面介绍的strcmp就差一个参数不一样!这个也和strcmp的功能差不多!他是比较两个字符串前num 个字符是否相同!

他也是大于返回整数小于返回负数等于返回0!

OK!使用一下:
 

int main()
{
	char str1[] = "abcdef";
	char str2[] = "kmd";
	if (strncmp(str1, str2, 2) > 0)
		printf(">");
	else if (strncmp(str1, str2, 2) < 0)
		printf("<");
	else
		printf("==");
	
	return 0;
}

他应该是<,看结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

OK!下面来模拟实现一下:

strncmp模拟实现

int my_strncmp(const char* str1, const char* str2, size_t num)
{
	assert(str1);
	assert(str2);

	while ((num) && (*str1 == *str2))
	{
		num--;
		str1++;
		str2++;
	}

	if (num != 0)
	{
		if (*str1 > *str2)
			return 1;
		else
			return -1;
	}
	else
	{
		return 0;
	}
}

这里要注意的是在while循环判断不能写成num--,如果它不符合条件后还会--这样导致多减了一次!还有就是str1和 str2也是一样!否则下面判断的时候解引用的就不是当时的那个字符了!

测试一下:

strncat介绍

C语言字串函数、内存函数介绍以及模拟实现,c语言

这个函数和上面介绍过的strcat基本一样就差一个参数,这个函数的参数有三个,作用是从source指向的字符串向destinaton指向的字符串中拷贝num个字符 !另外还会在新字符串结尾加一个\0!如果拷贝的时候发现source指向的字符串个数小于num那就只拷贝\0之前的字符!

OK!使用一下:

int main()
{
	char str1[20] = "abcdef";
	char str2[] = "xyz123";
	strncat(str1, str2,1);
	printf("%s\n", str1);
	return 0;
}

看结果!

C语言字串函数、内存函数介绍以及模拟实现,c语言

这里我们可以调试一下看一下另一个东西:

C语言字串函数、内存函数介绍以及模拟实现,c语言

这个栗子就说明了只要超过要拷贝字符串的字符个数 就会只拷贝\0之前的字符而且会在新字符串的结尾加上一个\0

OK!介绍的差不多了,下面来模拟实现一个:

strncat模拟实现

char* my_strncat(char* dest, const char* src, size_t num)
{
	assert(dest);
	assert(src);

	char* ret = dest;
	while (*dest)
	{
		dest++;
	}

	while (num--)
	{
		*dest++ = *src++;
	}

	return ret;
}

验证一下:

C语言字串函数、内存函数介绍以及模拟实现,c语言

在通过上面的strcat的函数调试的调试一下:
 C语言字串函数、内存函数介绍以及模拟实现,c语言

 strstr介绍

还是看官网介绍:

C语言字串函数、内存函数介绍以及模拟实现,c语言

这个函数的作用是在str1中查找str2,如果有返回str2在str1中出现第一次位置的地址,如果没有返回空指针!注意的是在查找的时候\0不算作查找内容!\0仅仅为结束标志!

OK!用一下:

int main()
{
	char* str1 = "abedfwef";
	char* str2 = "fwef";

	char* ret = strstr(str1, str2);
	if (ret != NULL)
	{
		printf(ret);
	}
	else
	{
		printf("没有!\n");
	}

	return 0;
}

看结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

果然返回了第一次出现的地址,然后printf接收到地址开始从这个地址打印\0之前的所有字符!OK,我们还是来实现一下:

strstr模拟实现

const char* my_strstr(const char* str1, const char* str2)
{
	assert(str1);
	assert(str2);

	const char* cp = str1;
	const char* s2 = str2;
	const char* s1 = cp;

	if (*str2 == '\0')
	{
		return str1;
	}

	while (*cp)
	{
		s1 = cp;
		s2 = str2;
		while (*s2 && *s1 && (*s2 == *s1))
		{
			s1++;
			s2++;
		}

		if (*s2 == '\0')
		{
			return cp;
		}

		cp++;
	}

	return NULL;
}

通过三个指针来实现!str1赋值cp,让他记录要比较的str1 的字符的位置,如果他开始的字符匹配失败则++一下,看下一个字符看看是否能匹配成功!然后cp赋值给s1,str2赋值给s2,s1和s2访问两个字符串!如果s1和s2指向的内容不为\0并且他两相等就让他们继续找!即s1++,s2++;当内层循环结束就可以看一下s2是否为\0,如果是\0则说明在cp的这个位置开始就是s2字符串第一次出现的位置!如果两层循环结束了还没返回就说明没有,直接返回NULL!如果str2一开始就是\0直接返回str1(没法找)!

ok,我上面说的可能不怎么清楚,下面画个图直观看看理解一下:

C语言字串函数、内存函数介绍以及模拟实现,c语言

 再来举个栗子画一下:

C语言字串函数、内存函数介绍以及模拟实现,c语言

OK!验证一下:

C语言字串函数、内存函数介绍以及模拟实现,c语言

strtok介绍

ok!我们来看一个很那啥的函数!先看官网介绍:

C语言字串函数、内存函数介绍以及模拟实现,c语言

他官网介绍有点长,对于英语不太好的不太友好,我下面用汉语解释一下:

这个函数的作用是按标记分隔字符串!标记是各种分隔字符串的字符的集合!例如:@.- 等

这个函数的声明:

C语言字串函数、内存函数介绍以及模拟实现,c语言

delimiters是一个字符指针,指向分隔符的集合!

str是指向一个字符串,它里面包含了0个或者多个delimiters指向的字符串中的分隔符的标记!

strtok找到str中的下一个标记将他换成\0并且返回指向这个标记的指针!但注意:strtok会改变str字符串,所以一般先拷贝一份str并可以被修改!

这几句我先来解释一下:

C语言字串函数、内存函数介绍以及模拟实现,c语言

当strtok函数的第一个参数不为NULL则将找到str中的第一个标记,strtok会保存这个标记在字符串中的位置!

当strtok的第一个参数为空指针(NULL)的时候,会在字符串中被保存的位置继续找下一个标记!

如果标记不存更多的标记在则返回NULL!

ok!举个例子:
 

int main()
{
	char str[] = "abcd.234.gyh@90";
	char delimiters[] = ".@";
	char copy[20];
	strcpy(copy, str);
	char *ret = strtok(copy, delimiters);
	printf("%s\n",ret);
	ret = strtok(NULL, delimiters);
	printf("%s\n", ret);
	ret = strtok(NULL, delimiters);
	printf("%s\n", ret);
	ret = strtok(NULL, delimiters);
	printf("%s\n", ret);
	return 0;
}

 看结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

是不是取出了!但这样的代码仅仅是为了演示这个函数的分隔!如果平时写这样那真的太cuo了哈哈!下面我们来看看她如何简洁一点使用:

int main()
{
	char str[] = "abcd.234.gyh@90";
	char delimiters[] = ".@";
	char copy[20];
	strcpy(copy, str);
	char* ret;
	for (ret = strtok(copy, delimiters); ret != NULL; ret= strtok(NULL, delimiters))
	{
		printf("%s\n", ret);
	}
	return 0;
}

 看结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

第一次传上去 如果不是NULL就会返回一个第一个标记的地址!如果为空就从同一字符串的上一次保存地址开始找!直到str没有分隔符结束返回NULL!只有str找完了没有分隔符了才会反感会NULL否则每次返回的都是有效地址!

再来来练习一个简单的!

int main()
{
	char str[] = "192.168.1.1";
	char sep[] = ".";
	char copy[20];
	strcpy(copy, str);
	char* ret;
	for (ret = strtok(copy, sep); ret != NULL; ret = strtok(NULL, sep))
	{
		printf("%s\n", ret);
	}
	return 0;
}

看结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

 strtok模拟实现【了解】

char* my_strtok(char* str, const char* delimiters) {
    static char* nextToken = NULL; // 用于保存下一个标记的位置

    if (str != NULL) {
        nextToken = str; // str!=NULL,表示第一次调用,设置初始位置
    }

    if (nextToken == NULL || *nextToken == '\0') {
        return NULL; // 没有更多的标记可供拆分
    }

    // 跳过开始的分隔符字符
    while (*nextToken && strchr(delimiters, *nextToken)) {
        nextToken++;
    }

    if (*nextToken == '\0') {
        return NULL; // 已到达字符串末尾
    }

    // 找到标记的起始位置
    char* currentToken = nextToken;

    // 继续查找下一个分隔符位置,将其替换为\0字符
    while (*nextToken && !strchr(delimiters, *nextToken)) {
        nextToken++;
    }

    if (*nextToken) {
        *nextToken = '\0'; // 替换为 \0字符
        nextToken++; // 下一个标记的起始位置
    }

    return currentToken; // 返回当前拆分的标记
}

int main() {
    char str[] = "192.168.1.1";
    char delimiters[] = ".";
    char copy[30];
    strcpy(copy, str);
    char* ret;

    for (ret = my_strtok(copy, delimiters); ret != NULL; ret = my_strtok(NULL, delimiters))
    {
        printf("%s\n", ret);
    }

    return 0;
}

看一下结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

OK!这个函数模拟实现的时候一定要注意,要把标记的那个位置用static 修饰,否则第二次进去的时候就不会找到上一次的那个位置了!当然这里面也使用了了另外一个函数:strchr这个函数从字符串中差找指定字符的!如果有返回字符串中这个字符的地址,没有返回空地址!要想了解的点击strchr!这个函数实现起来也不是很难,有兴趣的可以实现一下!

strerror介绍

这个函数可是一个很有意思的函数!OK我们先来看看逛网对他的介绍:

C语言字串函数、内存函数介绍以及模拟实现,c语言

这个函数的作用是,获取指向错误信息字符串的指针!当库函数在执行的时候发生错误就会生成一个错误码,这个错误码会存在C语言提供的erron这个全局变量中(大家共用),erron其实是一个宏!当strerror接收到一个错误码(erron)之后会返回对应错误信息字符串的首元素地址!然后就可以打印出来!

ok !我们来试着打印一下0~9:

int main()
{
	for (int i = 0; i < 10; i++)
	{
		printf("%d : %s\n", i,strerror(i));
	}
	
	return 0;
}

看结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

ok !我们来举个实例(文件打开):

#include<errno.h>

int main()
{
	//打开文件用fopen他的返回值是一个FILE类型的指针
	FILE* pf = fopen("deta.text", "r");//r是只读,"data.txt"是当前路径下
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		exit(-1);//异常退出
	}
	//读写...

	//关闭文件
	fclose(pf);
	return 0;
}

当前路径下是没有data.txt这个文件的,我们可以看一下:

C语言字串函数、内存函数介绍以及模拟实现,c语言

看一下结果:这里要包含头文件:errno.h

C语言字串函数、内存函数介绍以及模拟实现,c语言 这里 还有一个和这个功能很相似的一个函数:perror他也是打印错误的perror:

我们来看一看他们的不同点:

C语言字串函数、内存函数介绍以及模拟实现,c语言

 perror这个函数好像会自动加:和\n而strerror不会加要手动加!这两个函数你想用哪个都行!

这里肯定有疑问:不是说代码下面错误框会报错,那这个和那个有啥区别?

错误框报错报的是语法错误其他错误不报,这两个函数报的是运行时错误

二、字符函数【了解】

我们以前了解过一些字符函数:如putchar、getchar等其实还有很多的字符函数比如:判断空间大写转小写,小写转大写!下面我们来看看:

C语言字串函数、内存函数介绍以及模拟实现,c语言

这里小编使用几个其他同理:

#include<ctype.h>
int main()
{
	char c= '\n';
	if (isspace(c))
		printf("空\n");
	else
		printf("非空\n");
	return 0;
}

这个函数要注意包含头文件:ctype.h

C语言字串函数、内存函数介绍以及模拟实现,c语言

 这里小编再来使用一个:isgraph这个函数是判断ASXII中是否有着个ASCII对应的图形:

#include<ctype.h>

int main()
{
	char c = '3';
	int ip = isdigit(c);
	if (ip)
	{
		if(isprint(c))
			printf("有这个图形,可以打印 %c  %d \n",c,c);
		else
			printf("有这个图形,不可以打印\n");
	}
	else
	{
		printf("没有这个图形\n");
	}
		
	
	return 0;
}

看结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言下面还有两个比较常见的函数:tolower和toupper 分别是转换小写和转换大写!

我们来看一个例子:一定要包含头文件ctype.h

#include<ctype.h>

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

看结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

这就是这个函数的用法!我们下面来实现一个功能:把字符串中小写全部转换为大写,不是小写字母不管!:

#include<ctype.h>
#include<stdlib.h>

int main()
{
	char str[20];
	gets(str);
	char* p = str;
	while (*p)
	{
		if (islower(*p))
		{
			*p = toupper(*p);
		}

		p++;
	}

	puts(str);
	return 0;
}

 看结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

三、内存函数

memcpy介绍

C语言字串函数、内存函数介绍以及模拟实现,c语言

这个函数的作用是将source 这个指针指向的内存块的内容拷贝给destination 指向的内存块!拷贝num个字节!这个函数的参数是void*destination 是指被拷贝的那块内存的起始位置,void*我们前面说过是可以接受任何类型的指针类型!后面的source用const修饰是说明你只要让source 的内容拷贝给destination 的内存块而不让它修改!最后返回拷贝的那块内存的首地址也就是最开始destination 的地址!这个函数如果destination 和source 有重复则复制的结果是未定义行为!而且这个函数不会因为\0结束!~用的时候得自己决定好要拷贝的字节数! 

ok !举个例子用一下(把arr1中的数据拷贝20个字节到arr2中):

#include<string.h>

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

	return 0;
}

验证一下:

C语言字串函数、内存函数介绍以及模拟实现,c语言

这里有的朋友会想到用strcpy但这是整形不是字符类型所以不能用strcpy !当然拷贝也是一样的!

这里的这个例子是整形其他类型也可以!ok!下面我们来模拟实现一下:

memcpy模拟实现

#include<assert.h>

void* my_memcpy(void* dest, const void* src, size_t num)
{
	assert(dest);
	assert(src);

	void* ret = dest;
	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}

	return ret;
}

其他应该都没有问题,有问题的是:dest = (char*)dest + 1;和src = (char*)src+ 1;这里有的朋友可能不太明白了为什么呢?他不难道是dest++和src++吗?不绝对不可以他们是void*都不知道指向哪里不能++,还有朋友说不能强转为char*再++吗?其实也是不行的!强转是瞬间的!那前置++总可以吧!确实在VS上可以过去但其他编译器不好说!为了保险,小编这样的方法还是最保险的!

OK!验证一下:

C语言字串函数、内存函数介绍以及模拟实现,c语言

再来换个数据类型测试一下:

C语言字串函数、内存函数介绍以及模拟实现,c语言

我们再来是一组:12345678910拷贝成12123458910能不能实现呢?验证一下:

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

	return 0;
}

我们预期12123458910看结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

这结果好像不是我们想要的!那里出问题了呢?我画个图解释一下:

C语言字串函数、内存函数介绍以及模拟实现,c语言

其实这种拷贝(重复)用下面我要介绍的memmove要做就好,但VS这个编译器memcpy也能做memmove的事!我们来看一下:

C语言字串函数、内存函数介绍以及模拟实现,c语言 ok !下面我们还是来学习一下memmove这个函数!memcpy仅仅再VS的编译器下把memmove的功能给实现了,其他编译器不清楚应该也没有实现!因此我们有必要了解清楚memmove这个函数以及他的使用方式:

memmove介绍

C语言字串函数、内存函数介绍以及模拟实现,c语言

这个函数的作用上面已经说了就是 移动字符串!允许源头和目标地址重叠!他的参数和上面的memcpy的一摸一样!

我们来使用一下:

C语言字串函数、内存函数介绍以及模拟实现,c语言

当然它也可以不重叠:

C语言字串函数、内存函数介绍以及模拟实现,c语言

也就是说memmove能左memcpy的事,但memcpy不一定能做memmove的事!但在VS这个编译器上两个都一样!ok !我们还是来模拟实现一波:

memmove模拟实现

#include<assert.h>

void* my_memmove(void* dest, const void* src, size_t num)
{
	assert(dest);
	assert(src);

	void* ret = dest;
	if (dest > src)
	{
		while (num--)
		{
			
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	else
	{
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}

	return ret;
}

 什么意思呢?我来画个图解释一下:

C语言字串函数、内存函数介绍以及模拟实现,c语言

分别检验一下:

C语言字串函数、内存函数介绍以及模拟实现,c语言

C语言字串函数、内存函数介绍以及模拟实现,c语言总结一下这个函数实现的思路就是分治,把dest大于src和小于src的分开考虑,这样就呢个很好的解决这个问题了!当两个字符串指针相交时总有一个大或者一个小的,当dest>src时采用从后向前拷贝,这样就解决了数据被覆盖的问题!当dest < src从前往后往前拷贝!

如线图:

C语言字串函数、内存函数介绍以及模拟实现,c语言

 总结为一张图为:

C语言字串函数、内存函数介绍以及模拟实现,c语言

memset介绍

C语言字串函数、内存函数介绍以及模拟实现,c语言

这个函数就比较简单了,作用是把内存中指定的字节数的内存块设置为指定值val!同样这个函数也不知道你要设置的类型是什么,所以指向被设置的指针为void*,设置成功后返回起始地址!

ok!我们来用一下:

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

C语言字串函数、内存函数介绍以及模拟实现,c语言

 再来换个数据类型:

int main()
{
	char arr[20] = "zbcdefghkaijsdfhio";
	
	memset(arr, 64, 12);
	for (unsigned int i = 0; i <strlen(arr); i++)
	{
		printf("%c ", arr[i]);
	}
	return 0;
}

看结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

memset模拟实现

void* my_memset(void* str, int val, size_t num)
{
	assert(str);

	void* ret = str;
	while (num--)
	{
		*(unsigned char*)str = (unsigned char)val;
		str = (char*)str + 1;
	}

	return ret;
}

 这个函数简单应该问题不大!看一下结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

C语言字串函数、内存函数介绍以及模拟实现,c语言

memcmp介绍

C语言字串函数、内存函数介绍以及模拟实现,c语言

这个函数的作用是将ptr1中的前num个字节的内存块的内容与ptr2中的逐一比较,如果相同返回0否则比较他们两个,ptr1 > ptr2大于返或回大于0的数!否则返回小于0的数!注意这个函数遇到\0不会结束!

ok !用一下:


int main()
{
	int arr1[] = { 1,2,1,4,5,6 };
	int arr2[] = { 1,2,257 };
	if (memcmp(arr1, arr2, 9) > 0)
		printf("ptr1 > ptr2\n");
	else if (memcmp(arr1, arr2, 9) < 0)
		printf("ptr1 < ptr2\n");
	else
		printf("ptr1 = ptr2\n");
	return 0;
}

C语言字串函数、内存函数介绍以及模拟实现,c语言

 看结果:

C语言字串函数、内存函数介绍以及模拟实现,c语言

再来看一个例子:

int main()
{
	char str1[] = "abc112233";
	char str2[] = "abcdef";
	;
	if (memcmp(str1, str2, 3) > 0)
		printf("str1 > str2\n");
	else if (memcmp(str1, str2, 3) < 0)
		printf("str1 < str2\n");
	else
		printf("str1 = str2\n");
	return 0;
}

 这个例子前三个字符相等后面就不相等了!先看内存:

C语言字串函数、内存函数介绍以及模拟实现,c语言

验证一下:

前三个字符:

C语言字串函数、内存函数介绍以及模拟实现,c语言

3个以后:

C语言字串函数、内存函数介绍以及模拟实现,c语言

 ok !我们还是来模拟实现一下:

memcmp模拟实现

int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
	size_t i = 0;

	while (i < num)
	{
		if (*((unsigned char*)ptr1 + i) > *((unsigned char*)ptr2 + i))
			return 1;
		else if (*((unsigned char*)ptr1 + i) < *((unsigned char*)ptr2 + i))
			return -1;

		i++;
	}
	
	return 0;
}

将他们按照官网的一样先转换为无符号char然后一个又一个比较,相等不管,不想等你比大小,大于返回1否则返回-1,等循环结束了说明num字节的两个内存块的内容相同返回0!

Ok !验证一下:

C语言字串函数、内存函数介绍以及模拟实现,c语言

C语言字串函数、内存函数介绍以及模拟实现,c语言

 再换一个类型验证一下:

C语言字串函数、内存函数介绍以及模拟实现,c语言

C语言字串函数、内存函数介绍以及模拟实现,c语言

验证没有问题!

OK!好兄弟我们下期再见!文章来源地址https://www.toymoban.com/news/detail-619606.html

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

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

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

相关文章

  • 【C语言】内存函数memcpy和memmove的功能与模拟实现

    1.memcpy 功能:把source指向的前num个字节内容拷贝到destination指向的位置去,可以拷贝任意类型的数据。 注:1.memcpy并不关心\\0,毕竟传的也不一定是字符串,因此拷贝过程中遇到\\0也不会停下来。 2.num的单位是字节,并不是要拷贝的元素个数 3.如果source和destination有任何的重叠

    2024年02月19日
    浏览(40)
  • C语言从入门到实战——常用内存函数的了解和模拟实现

    内存函数(memory functions)指的是控制计算机内存操作的函数 函数 memcpy 从 source 的位置开始向后复制 num 个字节的数据到 destination 指向的内存位置。 这个函数在遇到 \\\'\\0\\\' 的时候并不会停下来。 如果 source 和 destination 有任何的重叠,复制的结果都是未定义的。 对于重叠的内存

    2024年02月03日
    浏览(35)
  • 【C语言】memcpy memmove memset memcmp 四大内存操作函数(详解+用法+模拟实现)

    头文件string.h中常用内存操作函数共有四大,学习完本篇文章,各种类型数组的常见处理轻松拿下。 对字符串(字符数组)的操作函数有很多,但是我们想要操作整型数组等呢: 这就需要内存操作函数了, memory在计算机科学中是内存的意思 ,这也是四大内存操作函数都有mem头

    2024年02月10日
    浏览(47)
  • C语言内存操作函数,memcpy的使用和模拟实现,memmove的使用和模拟实现,memcmp的使用,memset的使用。

    函数原型: void *dest 目标数据首元素地址 const void *src 源数据(需要拷贝过去的数据) size_t count 需要拷贝数据的字节大小 void *memcpy 拷贝结束后,返回目标数据的起始地址 函数作用: 拷贝 count 个字节的数据从源数据起始地址到目标空间。 函数的使用 函数的模拟实现: 注:

    2024年02月09日
    浏览(44)
  • 详细介绍五种常用字符串库函数 以及对库函数的模拟实现

    本文介绍了strlen.strcpy.strcmp.strcat.strstr五大字符串库函数及使用自定义函数模拟实现这五个字符串库函数.学会使用字符串库函数,在处理字符串时会事半功倍… 使用字符串库函数首先需要包含字符串头文件-#includestring.h 这篇博客中详细介绍到了函数-库函数和自定义函数 strlen为

    2024年02月15日
    浏览(38)
  • 【C语言】字符函数和字符串函数(一)—>库函数的介绍与模拟实现

    目录 前言: 一、函数介绍: (一)求字符串长度 (1)strlen (二)长度不受限制的字符串函数 (2)strcpy (3)strcat (4)strcmp (三)长度受限制的字符串函数 (5)strncpy (6)strncat (7)strncmp (四)字符串查找 (8)strstr (9)strtok (五)错误信息报告 (10)strerror (六)

    2024年02月15日
    浏览(46)
  • 动态内存管理函数介绍及C语言实现通讯录管理系统2.0版(动态增长版本)

    之前向大家介绍了C语言实现通讯录管理系统1.0版本,但该版本有明显的不足之处,比如:一开始就开辟了1000个date数组,如果联系人很少,那么就会造成严重的内存浪费,或者联系人超过了1000人,那么原数组就放不下了,所以今天我们考虑使用动态内存管理的办法来实现一个

    2023年04月08日
    浏览(49)
  • 【C语言】动态内存函数介绍

    目录 1.malloc和free 2.calloc 3.realloc   C语言提供了一个动态内存开辟的函数malloc: 这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。 ✔如果开辟成功,则返回一个指向开辟好空间的指针。 ✔如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做

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

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

    2024年03月18日
    浏览(59)
  • 一篇博客学会系列(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)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包