数组越界死循环以及部分内存函数实现

目录

 一、数组越界死循环

二、strcpy函数

三、memcpy函数

四、memmove函数

五、memcmp函数

六、memset函数​


sizeof和strlen

int main(int argc, const char* argv[])
{
	char ii[10] = { 1,2,3,4,5,6,7,8,9 };
	char hh[10] = { "123456789A" };
	printf("%zu\n", hh[0]);//49//'1' = '0'+1

	char gg[10] = { '1','2','3' };
	printf("%zu\n", gg[0]);//49//'0'这个的ascii码是48,注意和0的出别//'1' = '0'+1

	char ff[10] = { 1,2,3,4,5,6,7,8,9,10 };
	char ee[10] = { 1,2,3,4 };
	char dd[10] = { 0,1,0,0,1 };
	char cc[10] = { 0,0,0,0,0 };
	char bb[10] = { 0 };
	printf("%zu\n", bb[0]);//0
	char aa[10];
	printf("-----\n");
	

	char A[] = "ABCDEF";//这个自带\0
	char B[6] = "ABCDEF";//确定了个数,没有\0的位置
	char C[6] = "ABCDE";//不初始化的地方自动补上\0
	printf("%zu\n", strlen(A));//6
	printf("%zu\n", strlen(B));//随机值
	printf("%zu\n", strlen(C));//5
	printf("-----\n");

	printf("%zu\n", strlen(aa));//随机值//没有初始化,烫烫烫烫
	printf("%zu\n", strlen(ii));//9
	printf("-----\n");

	/*hh和B是一个道理,gg和C也是一个道理,没初始化的地方自动补\0*/
	printf("%zu\n", strlen(hh));//随机值//找不到\0
	printf("%zu\n", strlen(gg));//3
	printf("-----\n");

	printf("%zu\n", strlen(ff));//随机值//找不到\0
	printf("%zu\n", strlen(ee));//4
	printf("%zu\n", strlen(dd));//0//找到\0
	printf("-----\n");

	/*0和\0在这里是一个概念*/
	printf("%zu\n", strlen(cc));//0
	printf("%zu\n", strlen(bb));//0
	printf("%zu\n", strlen(aa));//随机值
	printf("-----\n");

	/*打印数组的大小*/
	printf("%zu\n", sizeof(aa) / sizeof(aa[0]));//10
	printf("%zu\n", sizeof(cc) / sizeof(cc[0]));//10
	printf("%zu\n", sizeof(hh) / sizeof(hh[0]));//10
	printf("-----\n");

	


	return 0;
}
int main(int argc, const char* argv[])
{
	char ii[10] = { 1,2,3,4,5,6,7,8,9 };
	char hh[10] = { "123456789A" };
	char gg[10] = { '1','2','3' };
	char ff[10] = { 1,2,3,4,5,6,7,8,9,10 };
	char ee[10] = { 1,2,3,4 };
	char dd[10] = { 0,1,0,0,1 };
	char cc[10] = { 0,0,0,0,0 };
	char bb[10] = { 0 };
	char aa[10];

	printf("%zu\n", strlen(aa));//随机值//没有初始化,烫烫烫烫
	printf("%zu\n", strlen(ii));//9
	printf("%zu\n", strlen(hh));//随机值//找不到\0
	printf("%zu\n", strlen(gg));//3
	printf("%zu\n", strlen(ff));//随机值//找不到\0
	printf("%zu\n", strlen(ee));//4
	printf("%zu\n", strlen(dd));//0//找到\0
	printf("%zu\n", strlen(cc));//0
	printf("%zu\n", strlen(bb));//0
	printf("%zu\n", strlen(aa));//随机值
	printf("%zu\n", sizeof(aa) / sizeof(aa[0]));//10
	printf("%zu\n", sizeof(cc) / sizeof(cc[0]));//10
	return 0;
}

数组初始化注意事项:

int main()
{
	//int a[][3] = { 0 };
	//int arr[3][] = { 0 };
	//int a[1][3] = { 1,2,3,4 };
	int a[2][3] = { {1,2} ,{3,4} ,{5,6} };
	//120 340 560
	//二维数组会自动补齐
	//所以这样初始化是错误的,会报初始值设定项太多报错
	return 0;
}

 一、数组越界死循环

数组越界死循环问题(详细,通俗,易懂)_数组加i死循环-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_55420366/article/details/120394302

//数组随着下标的增长,地址由低到高增长
//栈区的内存,先使用高地址,再开辟低地址
#include<stdio.h>
int main()
{
	int i = 0;
	/*数组中的下标从0开始,那么在上面代码中只能访问:a[1]、a[2]、a[3]、a[4]、a[5]、a[6]、a[7]、a[8]、a[9];当i自加到10时,a[10]属于数组下标越界。*/
	int arr[10] = { 1,2,3,4,5,6,7,8,9 };
	
	for (i = 0; i <= 12; i++)
	{
		arr[i] = 0;
		printf("hehe\n");
	}
	printf("%d\n", i);//12
	return 0;
}
/*声明一个数组a[5],该数组中只能存放5个元素,下标索引值取值范围0~4,超过这个范围就属于下标越界;*/

         这个程序放到编译器中运行的话会造成死循环,那这时我们可能会想,数组的总元素是10,而循环语句中的i要循环到12才结束,那么肯定会出现数组越界报错啊,但为什么会出现死循环而不是数组越界,并且这个语句为什么会形成死循环呢?下面我来给大家解释。

        首先我们得先从栈开始讲起(不知道什么是栈的小伙伴可以自己去搜),我们平时创建的局部变量就放在栈中,而栈的使用规则从高地址向低地址使用的。并且单个数组元素在栈中的地址相对大小和下标大小相同,也就是说变量i和数组在栈中的位置关系如下图所示。


        那么这就明了了,当数组越界后,i一直++,直到i=12时,此时arr[12]与i,他们俩的地址一样,所代表的的内存空间一样,可以说arr[12]就是i了,此时给arr[12]赋值为0,也就是重新给i赋值为0,那么这个循环会重新开始,也就造成了死循环。

 数组名表示首元素的地址,但是有两个例外:

1.sizeof(数组名),这个数组名表示整个数组

2.&数组名,这个数组名也表示整个数组,取出的是整个数组的地址

int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 2,3,4,5,6 };
	int arr3[] = { 3,4,5,6,7 };
	int* parr[3] = {arr1,arr2,arr3};
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		char j = 0;
		for (j = 0; j < sizeof(arr1) / sizeof(arr1[0]);j++)
		{
			/*arr1存放的是其首元素1的地址
			parr[1]存放的是arr1的地址也就是arr1首元素的地址
			现在对parr进行解引用实际得到的是arr1首元素的地址
			arr1首元素的地址存放的是arr1的首元素,解引用得到1*/
			printf("%d ", *(*(parr + i) + j));
			if (j == 4)
			{
				printf("\n");
			}
		}
		
	}
	
	return 0;
}

数组指针:

二、strcpy函数

int main()
{ 
	char name[20] = "xxxxXXxxxx";
	char name1[20] = "xxxxXXxxxx";

	char arr[] = { 'a','b','c','i' };
	strcpy(name, "zhangsan");
	strcpy(name1, "zhang\0san");
	printf("%s\n", name);
	printf("%s\n", name1);
	strcpy(name, arr);
	printf("%s\n", name);
	strcpy(name, "zhangsansssssssssssssssssssssssss");
	//超出,崩溃

	return 0;
}

char* my_strcpy(char* parr2, const char* parr1)
{
	assert(parr1);
	assert(parr2);
	char* ret = *parr1;
	while (*parr2++ = *parr1++);
		/*parr1++;
		parr2++;*/
	*parr2 = '\0';
	return ret;
}
int main()
{
	char arr1[] = "abcdef";
	char arr2[20] = { 0 };
	my_strcpy(arr2, arr1);
	printf("%s\n", arr2);
	
}


三、memcpy函数

/*void*类型不能解引用*/
my_memcpy(void* parr2, void* parr1, unsigned int num)
{
	assert(parr1 && parr2);
	while (num--)
	{
		*(char*)parr2 = *(char*)parr1;
		parr1 = (char*)parr1 + 1;
		parr2 = (char*)parr2 + 1;

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

四、memmove函数

void* my_memmove(void* dst,const void* src,unsigned int num)
{
	assert(dst && src);
	void* ret = dst;
	if (dst < src)//从前向后拷贝
	{
		while (num--)
		{
			*(char*)dst = *(char*)src;
			dst = (char*)dst + 1;
			src = (char*)src + 1;
		}
	}
	else if (dst >= src)//从后向前拷贝
	{
		while (num--)
		{
			*((char*)dst + num) = *((char*)src + num);
		}
	}
	return ret;
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7 };
	my_memmove(arr1, arr1+3, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}

	return 0;
}

五、memcmp函数

arr1<arr2,所以返回<0//一个字节一个字节的比较,只要出现小于就会返回

int my_memcmp(const void* parr1, const void* parr2, unsigned int num)
{
	int ret = 0;
	while (num--)
	{
		if (*(char*)parr1 > *(char*)parr2)
		{
			ret = 1;
			break;
		}
		else if (*(char*)parr1 < *(char*)parr2)
		{
			ret = -1;
			break;
		}
		else
		{
			parr1 = (char*)parr1 + 1;
			parr2 = (char*)parr2 + 1;
		}
		ret = 0;
	}
	return ret;
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7 };
	int arr2[10] = { 1,2,3,5,6,7,8 };
	int arr3[10] = { 1,2,3,4,5,6,7 };
	int arr4[10] = { 1,2,3,2,5,6,7 };
	int ret1 = my_memcmp((void*)arr1, (void*)arr2, 20);
	int ret2 = my_memcmp(arr1, arr3, sizeof(arr1) / sizeof(arr1[0]));
	int ret3 = my_memcmp(arr1, arr4, 20);
	printf("%d\n%d\n%d\n", ret1,ret2,ret3);
	return 0;
}




六、memset函数

int main()
{
	char arr[] = "hello,bit";
	memset(arr, 'x', 5);
	printf("%s\n", arr);
	memset(arr, 0, strlen(arr));
	int i = 0;
	for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%d ",*(arr+i) );
	}
}

 但是注意这样是不对的:(因为memset是按字节进行初始化的)

	int i = 0;
	int arr[10] = { 0 };
	memset(arr, 1, 40);//按照字节进行初始化
	for (i = 0; i < 10; i++)
	{
		printf("%d ", *(arr+i));
	}
	return 0;

memset常用就是赋值为-1或者0

若str指向char型地址,value可为任意字符值;
若str指向非char型,如int型地址,要想赋值正确,value的值只能是-1或0,因为-1和0转化成二进制后每一位都是一样的,设int型占4个字节,则-1=0XFFFFFFFF, 0=0X00000000。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值