复刻常用字符、内存函数

前言: “字符串是一种重要的数据类型,但是C语言并没有显式的字符串数据类型,因为字符串以字符串常量的形式出现或者存储与字符数组中。” ——摘自《C和指针》


1. strlen

1.1 函数介绍

函数原型:size_t strlen( const char *string );

函数功能:获取字符串长度,即返回该字符串中'\0'前的字符个数。

如下所示,使用strlen函数计算字符串abcd的长度。

int main()
{
	char array[] = "abcd";
	int ret = strlen(array);
	printf("%d", ret);
	return 0;
}

1.2 函数复刻

方法1:使用指针相减得到字符串中字符个数。

//方法1:指针相减
size_t my_strlen(const char* string)
{
	char* ptr = string;
	while (*string != '\0')
	{
		string++;
	}
	return string - ptr;
}

方法2:使用递归求解。

 

//方法2:递归
size_t my_strlen(const char* string)
{
	if (*string != '\0')
	{
		return 1 + my_strlen(++string);
	}
	return 0; 
}

 方法2:使用迭代计数。

//方法3:迭代计数 while循环
size_t my_strlen(const char* string)
{
	int count = 0;
	while (*string != '\0')
	{
		string++;
		count++;
	}
	return count;
}

//迭代计数 for循环
size_t my_strlen(const char* string)
{
	int count = 0;
    for(count = 0; *string++ != '\0'; )
        count++;
	return count;
}

2. strcpy

2.1 函数介绍

函数原型:char *strcpy( char *strDestination, const char *strSource );

函数功能:实现字符串的拷贝,并返回拷贝后字符串的地址。

int main()
{
	char strDestination[] = "abcd";
	char strSource[] = "fk";
	char* ret = strcpy(strDestination, strSource);
	printf("%s", ret);
	return 0;
}

通过调试可以清晰的看到字符串strDestination中的内容是被字符串strSource完全覆盖了,以此达到了字符串拷贝的效果。

 2.2 函数复刻 

方法:使用两个字符指针分别指向源字符串和目标字符串,将源字符串的内容赋值给目标字符串,直到源字符串'\0'时赋值完毕后结束循环。

char* my_strcpy(char* strDestination, const char* strSource)
{
	char* ptr_strDestination = strDestination;
	char* ptr_strSource = strSource;
	while (*ptr_strDestination++ = *ptr_strSource++);
	return strDestination;
}

3. strcat

3.1 函数介绍

函数原型:char *strcat( char *strDestination, const char *strSource );

函数功能:实现字符串的追加,并返回追加后字符串的地址。

int main()
{
	char strDestination[20] = "abcd";
	char strSource[5] = "fk";
	char* ret = strcat(strDestination, strSource);
	printf("%s", ret);
	return 0;
}

 通过调试可知字符串追加功能是从被追加字符串的'\0'位置处开始追加,再将追加字符串拷贝至被追加字符串,这就要求被追加字符串需要拥有足够大的空间,否则会导致越界。

 3.2 函数复刻

方法:使用一个字符指针指向被追加字符串,指针不断指向下一位置,直到指针所指向位置的值为'\0',停止循环,而后重复字符拷贝的过程,实现字符追加。

char* my_strcat(char* strDestination, const char* strSource)
{
	char* ptr_strDestination = strDestination;
	while (*strDestination != '\0')
	{
		strDestination++;
	}
	while (*strDestination++ = *strSource++);
	return ptr_strDestination;
}

4. strcmp

4.1 函数介绍

函数原型:int strcmp( const char *string1, const char *string2 );

函数功能:实现字符串的比较(比较字符串中每个字符的ASCII码值)。string1 < string2 返回小于0的值,string1 = string2 返回0,string1 > string2 返回大于0的值。

4.2 函数复刻

方法:当两个字符串字符相等时,指向两个字符串的指针分别向后移动一次,当碰到'\0'时表示两个字符串相等,返回0,若两个字符串中字符不等,则返回两个字符串中字符ASCII的差值。

int my_strcmp(const char* string1, const char* string2)
{
	while (*string1 == *string2)
	{
		if (*string1 == '\0')
		{
			return 0;
		}
		string1++;
		string2++;
	}
	return *string1 - *string2;
}

5. strstr

5.1 函数介绍

函数原型:char *strstr( const char *string, const char *strCharSet );

函数功能:实现字符串中子串的查找,如果没有找到返回空指针,找到了返回子串在字符串中第一个位置的地址。

例如:查找字符串abbcd中的子串bcd,返回位置应为第二个b的地址,下方代码结果应打印bcd。

int main()
{
	char string[20] = "abbcd";
	char strCharSet[5] = "b";
	char* ret = strstr(string, strCharSet);
	printf("%s", ret);
	return 0;
}

5.2 函数复刻

 方法:使用三个指针,ptr_strCharSet指向子串,ptr_string指向源字符串, cur用以标记查找位置。具体查找过程如图所示。

char* my_strstr(const char* string,const char* strCharSet)
{
	char* ptr_string;
	char* ptr_strCharSet;
	char* cur = string;

	if (*strCharSet == '\0')
	{
		return string;
	}

	while (*cur)
	{
		ptr_string = cur;
		ptr_strCharSet = strCharSet;

		while (*ptr_strCharSet && *ptr_string && *ptr_string == *ptr_strCharSet)
		{
			ptr_string++;
			ptr_strCharSet++;
		}

		if (*ptr_strCharSet == '\0')
		{
			return cur;
		}

		cur++;
	}

	return NULL;
}

6. strncpy

6.1 函数介绍

函数原型:char *strncpy( char *strDest, const char *strSource, size_t count );

函数功能:实现指定数量的字符拷贝。strncpy函数将strSource的初始计数字符复制到strDest并返回strDest。如果count小于或等于strSource的长度,则不会自动将空字符追加到复制的字符串中。如果count大于strSource的长度,目标字符串将被填充到长度count之前的空字符。

6.2 函数复刻

char* my_strncpy(char* strDest, const char* strSource, size_t count)
{
	int i = 0;
	char* ptr_strDest = strDest;
	while (i++ < count && (*strDest++ = *strSource++) != '\0');
	if (*(strDest) != '\0')
		*strDest = '\0';
	return ptr_strDest;
}

7. strncat

7.1 函数介绍

函数原型:char *strncat( char *strDest, const char *strSource, size_t count );

函数功能:追加指定个数的字符。在追加指定个数的字符后,末尾自动添加'\0'。

7.2 函数复刻

char* my_strncat(char* strDest, const char* strSource, size_t count)
{
	char* ptr_strDest = strDest;
	while (*strDest++ != '\0');
	while (count--)
	{
		if((*strDest = *strSource) != '\0');
	} 
	*strDest = '\0';
	return ptr_strDest;
}


8. strncmp

8.1 函数介绍

函数原型:int strncmp( const char *string1, const char *string2, size_t count );

函数功能:实现指定字符个数的字符大小比较。

8.2 函数复刻

int my_strncmp(const char * str1, const char * str2, size_t num)
{
	while (num--)
	{
		if ((*str1 == *str2) && (*str1 != 0) && (*str2 != 0))
		{
			str1++;
			str2++;
		}
	}
	return *str1 - *str2;
}

9. memcpy

9.1 函数介绍

函数原型:void *memcpy( void *dest, const void *src, size_t count );

函数功能:以字节为单位拷贝内存中存储的任意类型数据。需注意的是,如果源操作数与目标操作数重叠,那么拷贝结果是未定义的。

按以下代码执行,由于只从数组src中拷贝了4个字节的内容,所以只拷贝了100,打印结果应为100和0。

int main()
{
	int dest[20] = {0};
	int src[] = {100, 200};		
	int* ret = (int*)memcpy(dest, src, 4);
	printf("%d %d", *ret, *(ret + 1));
	return 0;
}

9.2 函数复刻

方法:将void*类型强转成char*的类型,确保可按字节进行拷贝,适应任何类型数据的拷贝。按需要拷贝的字节数进行循环,将源操作数拷贝至目标操作数。

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

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

 上述代码欲将数组dest中1,2,3,4,5拷贝至数组dest第三个位置,打印出1,2,1,2,3,4,5,7,8,9。然而实际效果如下,表明memcpy函数源操作数与目标操作数重叠时拷贝顺序是从前往后拷贝,导致拷贝结果被不停覆盖。


10. memmove

10.1 函数介绍

函数原型:void *memmove( void *dest, const void *src, size_t count );

函数功能:与memcpy功能类似,解决了memcpy源操作数与目标操作数重叠时产生的内存覆盖问题。

10.2 函数复刻

方法:首先需区分两种情况即dest在src之后或之前。若dest在src之前,拷贝顺序为从前向后;若dest在src之后,拷贝顺序从后向前依次拷贝。

void * my_memmove(void * destination, const void * source, size_t num)
{
	void* ptr_destination = destination;
	if (destination < source)
	{
		while (num--)
		{
			*(char*)destination = *(char*)source;
			destination = (char*)destination + 1;
			source = (char*)source + 1;
		}
	}
	else
	{
		while (num--)
		{
			*((char*)destination + num) = *((char*)source + num);
		}
	}
	return ptr_destination;
} 

END

《餐馆点餐管理系统——基于Java和MySQL的课程设计解析》 在信息技术日益发达的今天,餐饮行业的数字化管理已经成为一种趋势。本次课程设计的主题是“餐馆点餐管理系统”,它结合了编程语言Java和数据库管理系统MySQL,旨在帮助初学者理解如何构建一个实际的、具有基本功能的餐饮管理软件。下面,我们将深入探讨这个系统的实现细节及其所涉及的关键知识点。 我们要关注的是数据库设计。在“res_db.sql”文件中,我们可以看到数据库的结构,可能包括菜品表、订单表、顾客信息表等。在MySQL中,我们需要创建这些表格并定义相应的字段,如菜品ID、名称、价格、库存等。此外,还要设置主键、外键来保证数据的一致性和完整性。例如,菜品ID作为主键,确保每个菜品的唯一性;订单表中的顾客ID和菜品ID则作为外键,与顾客信息表和菜品表关联,形成数据间的联系。 接下来,我们来看Java部分。在这个系统中,Java主要负责前端界面的展示和后端逻辑的处理。使用Java Swing或JavaFX库可以创建用户友好的图形用户界面(GUI),让顾客能够方便地浏览菜单、下单。同时,Java还负责与MySQL数据库进行交互,通过JDBC(Java Database Connectivity)API实现数据的增删查改操作。在程序中,我们需要编写SQL语句,比如INSERT用于添加新的菜品信息,SELECT用于查询所有菜品,UPDATE用于更新菜品的价格,DELETE用于删除不再提供的菜品。 在系统设计中,我们还需要考虑一些关键功能的实现。例如,“新增菜品和价格”的功能,需要用户输入菜品信息,然后通过Java程序将这些信息存储到数据库中。在显示所有菜品的功能上,程序需要从数据库获取所有菜品数据,然后在界面上动态生成列表或者表格展示。同时,为了提高用户体验,可能还需要实现搜索和排序功能,允许用户根据菜品名称或价格进行筛选。 另外,安全性也是系统设计的重要一环。在连接数据库时,要避免SQL注入攻击,可以通过预编译的PreparedStatement对象来执行SQL命令。对于用户输入的数据,需要进行验证和过滤,防止非法字符和异常值。 这个“餐馆点餐管理系统”项目涵盖了Java编程、数据库设计与管理、用户界面设计等多个方面,是一个很好的学习实践平台。通过这个项目,初学者不仅可以提升编程技能,还能对数据库管理和软件工程有更深入的理解。在实际开发过程中,还会遇到调试、测试、优化等挑战,这些都是成长为专业开发者不可或缺的经验积累
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ZHOUZH_093

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

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

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

打赏作者

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

抵扣说明:

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

余额充值