栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

疑难代码理解1

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

疑难代码理解1

疑难代码理解
  • 1.sizeof二维数组
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.水仙花数
  • 7.指针-指针(遗留?)
    • 我直接上代码解读指针加减公式
  • 8.字符'*'菱形打印
    • 打印示意图:
    • 代码
    • 代码解读
  • 9.
    • 代码一:
    • 代码二:
  • 10.
    • 题目
    • 代码
    • 错误
    • 重制代码
    • 错误
    • 解决方案
    • 正确代码
    • 代码优化
    • 优化代码中存在的问题
    • 解决

1.sizeof二维数组
main()
{
	int a[3][4] = { 0 };
	//a[0]单独放在sizeof内部,a[0]相当于作为第一行数组的数组名
	//sizeof(arr[0])计算的是第一行的大小
	printf("%dn", sizeof(a[0]));
	//a[0]没有单独放在sizeof内部,a[0]表示二维数组第一行第一个元素的地址
	//a[0]+1表示第一行第二个元素的地址
	printf("%dn", sizeof(a[0] + 1));
	printf("%dn", sizeof(a[0] + 1));
	printf("%dn", sizeof(*(a[0] + 1)));//4-*(a[0]+1)是第一行第二个元素,大小是4个字节。
	printf("%dn", sizeof(a + 1));//a是二维数组的数组名,没有sizeof(数组名),也没有&(数组名),所以a是首元素地址
	//而二维数组的首元素就是它的第一行,a就是第一行(首元素)的地址
	//a+1就是第二行的地址
	printf("%dn", sizeof(&a[0] + 1));//第二行地址
	printf("%dn", sizeof(a[3]));//16,sizeof后面()里的表达式不会计算
	//a[3]是一个4个整形的一维数组,但实际并不存在
}
2.
main()
{
	int a[5][5];
	int(*p)[4] = a;
	printf("%p %dn", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
	//a[4][2]表示*(*(a+4)+2)第五行第三个元素
	//p[4][2]表示*(*(p+4)+2)第4行第4个元素,*(*(p)+0)表示第一行第一个元素
	//%p ,-4打印的是-4补码的直接值
}
3.
main()
{
	int aa[2][5] = {1,2,3,4,5,6,7,8,9,10};
	int *a = (int*)(&aa + 1);
	int *b = (int*)(*(aa + 1)); //*(aa + 1)= aa[1]-第二行首元素地址
	printf("%d %dn",*(a-1),*(b-1));//10  5
}
4.
main()
{
	char *p = "abcdef";//把字符串首字符a的地址放到p里面
	char* a[] = { "work", "at", "alibaba" };
	//元素类型为char*,a数组里面存放的都是字符指针
	//所以a里面存放的是‘w’的地址,‘a’的地址和‘a’的地址
	char** pa = a;
	pa++;
	printf("%sn", pa);//打印at
}

解读图:(或许不准确,会补充讲行指针和列指针)

5.
main()
{
	char*c[] = { "ENTER", "NEW", "POINT", "FIRST" };
	char**cp[] = {c+3,c+2,c+1,c};
	char***cpp = cp;
	printf("%sn", **++cpp);//POINT
	printf("%sn", *--*++cpp+3);//ER而且它把字符二级指针数组的内容改了
	printf("%sn", *cpp[-2]+3);//ST
	printf("%sn", cpp[-1][-1]+1);//EW
	int i;
	for (i = 0; i < 4; i++)
	{
		printf("%pn", cp[i]);
	}
}

最后一个循环打印结果为(证明了在二级字符型指针数组里c+1变成了c)

6.水仙花数

解读:找出1·100000中数值等于各个位上的数字的几位数的平方的数。
疑难:有一个关键问题我没注意到:就是2的n次方不能写成2^n。

#include
#include
main()
{
	int i;
	for (i = 0; i <= 100000; i++)
	{
		//定义一个变量j,得出它是一个几位数
		int j = 1,h=i,f=i;
		while (f /= 10)//i的值变化
		{
			j++;
		}
		//得出i各个位j次方之和,结果为w
		int x,w=0;//x是一个计数器,
		for (x = 0; x < j; x++)
		{
			w = w + pow(h % 10, j);
			h /= 10;
		}
		if (w == i)
			printf("%dn", i);
	}
}

结果为:

7.指针-指针(遗留?)

指针-指针得到的是指针之间的字节个数说法是错误的.
指针-指针得到的是指针之间的元素个数。
指针的加减并不是直接的算术加减,而是一种特殊意义。苏明宇先生提出公式:p = p ±sizeof(*p)*n。
p是指针类型,n代表加减多少。

我直接上代码解读指针加减公式
main()
{
	char arr1[] = "abcde";
	char* p1 = arr1;//字符型指针
	printf("%pn", p1);
	printf("%pn", p1+1);
	printf("%pn", p1 + 2);
	printf("n");
	char(*p2)[5] = &arr1;//数组指针里的[]中的数字是不可省略的?
	printf("%pn", p2);
	printf("%pn", p2+1);
	printf("%pn", p2+2);
	printf("n");
	char(*p3)[6] = &arr1;//数组指针里的[]中的数字是不可省略的?
	printf("%pn", p3);
	printf("%pn", p3 + 1);
	printf("%pn", p3 + 2);
	printf("n");
	int arr2[2] = { 1, 2 };
	int* p4 = arr2;
	printf("%pn", p4);
	printf("%pn", p4 + 1);
	printf("%pn", p4 + 2);
	printf("n");
	int(*p5)[2] = &arr2;
	printf("%pn", p5);
	printf("%pn", p5 + 1);
	printf("%pn", p5 + 2);
	printf("n");
}

结果是:

 	int arr[2] = { 1, 2 };
	int* p1 = &arr[0];
	int* p2 = &arr[1];
	printf("%dn", p2 - p1);
	printf("%dn", &arr[1] - &arr[0]);
	printf("%pn",  &arr[0]);
	printf("%pn", &arr[1]);

结果为:

8.字符’*'菱形打印 打印示意图:

代码
#include
main()
{
	//上
	//自己定义底有多少列
	int max_num=26;
	for (;max_num%2==0;)
	{
		scanf("%d", &max_num);
		if (max_num % 2 == 0)
			printf("不符合图形规则,重新输入n");
	}
	//定义一个变量row判断上要打印多少行
	int row=(max_num-1)/2;
	int count, x;//定义一个计数器
	for (count = 0; count < row;count++)
	{
		for (x = 0; x < (max_num - count * 2 - 1) / 2; x++)
		{
			printf(" ");
		}
		for (x = 0; x < count*2+1;x++)
		{
			printf("*");
		}
		for (x = 0; x < (max_num - count * 2 - 1) / 2; x++)
		{
			printf(" ");
		}
		printf("n");
	}
	//中
	for (x = 0; x < max_num; x++)
		printf("*");
	printf("n");
	//下
	for (count = 0; count < row; count++)
	{
		for (x = 0; x < count+ 1; x++)
		{
			printf(" ");
		}
		for (x = 0; x < max_num - (count+1)*2; x++)//关于这个条件区别于上是有一个底层逻辑的
		{
			printf("*");
		}
		for (x = 0; x < count+ 1; x++)
		{
			printf(" ");
		}
		printf("n");
	}
}
代码解读

1.定义的max_num实际表示的是最大列数(行最多字符‘*’数量)
2.定义的row实际上是指上部分(下部分)的行数
3.我先完成的上面的代码,然后在完成下面的代码时复制粘贴时出现了条件紊乱这个问题,这里想详细说明一下。
上面代码的三个内循环条件

外循环是:for(count = 0; count < row;count++)//外循环只表示行数
for(x=0;x<(max_num-count*2-1)/2;x++)
for(x=0;x 

在这里:(max_num-count2-1)/22+count*2-1恰好是最大列数max_num.
然后在写下代码的时候我认为对比上下的区别是冗余的,可直接根据我们定义的变量所代表的实际意义直接去写这个for条件。

外循环是:for(count = 0; count < row;count++)
然后打印空格,那么空格是从1开始公差为1的一个等差数列
for(x=0;x<1+count;x++)
for(x=0;x 

这里条件代数和为max_num。

9.

题目:

代码一:
#include
main()
{
//换过来的汽水
	int sum = 0,money=20,bottle=0;
//买过来的汽水
	while (money > 0 || bottle > 1)
	{
		sum += money;//1块钱中的一个水
		bottle += money;//一块钱中的一个瓶
		money = bottle / 2;//两个瓶就是一块钱
		bottle-=money*2;//从总数里去掉换钱所用的瓶子
	}
	printf("%dn", sum);
}
代码二:
#include
main()
{
	int sum = 20, bottle = 20;//初始阶段把钱都换成水和瓶
	while ( bottle > 1)
	{
		int a = bottle / 2;
		//两个瓶子换一个水和瓶,a代表已有瓶子能换取的最大量
		sum += a;//水算到sum里
		if (bottle % 2 == 0)//瓶子算到bottle里
			bottle = a;
		else
			bottle = 1 + a;
	}
	printf("%dn", sum);
}
10. 题目

代码
void exchange(int arr[],int num)
{
	int i;
	for (i = 0; i < num; i++)
	{
		if (arr[i] % 2 == 0)
		{
			int tmp = arr[i];
			arr[i] = arr[5];//error
			arr[5] = tmp;
		}
	}
}
main()
{
	int arr[5] = { 1, 2, 3, 4, 5 };
	int num = sizeof(arr) / sizeof(arr[0]);
	exchange(arr, num);
	int i;
	for (i = 0; i < num; i++)
		printf("%d  ",arr[i]);
}
错误

1.下表不要写5,arr[5]越界访问。对于这个代码最大下标是num-1(也就是4)。原谅我晚上10点状态不佳。
2.我后一天又发现了一个致命的逻辑性问题,交换前面的偶数与最后一个数字的位置的时候,有一个前提条件是最后一个数字一定要是奇数,但这个前提条件是无法总是满足的。由此,这个代码需要重制。

重制代码
void exchange(int arr[],int num)
{
	int i, x = num - 1;
	//从下标为0开始一步一步排查
	for (i = 0; i < num; i++)
	{
		//x>i证明下标i后面没有奇数了,也就不用交换了
		while (x > i)
		{
			//找到数组前面的偶数元素的下标
			if (arr[i] % 2 == 0)
			{
				//在后面(要满足x>i)并且是奇数(arr[x]%2==0)
				for (; arr[x] % 2 == 0&&x>i; x--);
				int tmp = arr[i];
				arr[i] = arr[x];
				arr[x] = tmp;
			}
		}
	}
}
main()
{
	int arr[5] = { 1, 2, 3, 5, 4 };
	int num = sizeof(arr) / sizeof(arr[0]);
	exchange(arr, num);
	int i;
	for (i = 0; i < num; i++)
		printf("%d  ",arr[i]);
}
错误

函数内循环进去了就出不来。(死循环)

解决方案

1.(下策)在while内循环的最后加入break.
2.(上策)把while改成if。
总结:设置一个循环条件,条件所包含的这些变量一定要在循环里面变化,否则条件的结果恒为1或者恒为0,条件判断失去意义。

正确代码
void exchange(int arr[],int num)
{
	int i, x = num - 1;
	//从下标为0开始一步一步排查
	for (i = 0; i < num; i++)
	{
		//x>i证明下标i后面没有奇数了,也就不用交换了
		if (x > i)
		{
			//能进入这个if,就说明已经找到数组前面的偶数元素的下标
			if (arr[i] % 2 == 0)
			{
				//在后面(要满足x>i)并且是奇数(arr[x]%2==0)
				//那么如果出循环
				//要么是不满足arr[x]%2==0也就是说arr[x]%2==1,即找到后面的奇数下表x
				//要么就是不满足x>i(x=i)也就是说下标i后面元素全偶,如果出现这种情况这个数和它自己交换(等价于不交换)
				for (; arr[x] % 2 == 0&&x>i; x--);
				int tmp = arr[i];
				arr[i] = arr[x];
				arr[x] = tmp;
			}
		}
	} 
}
main()
{
	int arr[] = { 4, 6,8,1};
	int num = sizeof(arr) / sizeof(arr[0]);
	exchange(arr, num);
	int i;
	for (i = 0; i < num; i++)
		printf("%d  ",arr[i]);
}
代码优化
exchange(int arr[],int num)
{
	int left = 0;
	int right = num - 1;
	while (right > left)
	{
		for (; arr[left] % 2 == 1; left++);//在前面找偶数
		for (; arr[right] % 2 == 0; right--);//在后面找奇数
		if (right > left)
		{
			int tmp = arr[left];
			arr[left] = arr[right];
			arr[right] = tmp;
		}
	}
}
main()
{
	int arr[5] = {1,3,5,7,9};
	int num = sizeof(arr) / sizeof(arr[0]);
	exchange(arr, num);
	print1(arr,num);
}
优化代码中存在的问题

面对一个特殊情况:数组中元素全奇数,那么会出现越界访问。

解决
for (; arr[left] % 2 == 1; left++);
for (; arr[right] % 2 == 0; right--);
改为
for (; arr[left] % 2 == 1&&right>left; left++);
for (; arr[right] % 2 == 0&&right>left; right--);
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/302574.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号