1.更加安全的自定义strlen函数:
在之前的博客中,我写过自定义strlen函数。今天来写一个更加安全的版本:
#include<stdio.h>
#include<assert.h>
int my_strlen(const char* a) //只需要利用a数组的首地址来求出字符串长度,*a不应该被改变
{
assert(a != NULL); //a数组的首地址不应该是一个空指针,如果是的话就报警告
int count = 0;
while (*a != '\0')
{
count++;
a++;
}
return count;
}
int main()
{
char a[10] = { 0 };
gets(a);
int ret = my_strlen(a);
printf("%d", ret);
return 0;
}
2.有关指针的强制类型转换:
看下面的代码:
#include<stdio.h>
int main()
{
int a[5] = { 1,2,3,4,5 };
short* p = (short*)a;
int i = 0;
for (i = 0;i < 4;i++)
{
*(p + i) = 0;
}
for (i = 0;i < 5;i++)
{
printf("%d ", a[i]);
}
return 0;
}
下面这行代码我使用了强制类型转换,a数组的首地址本来是int*类型的指针,被强制转换成了short*类型。
short* p = (short*)a;
在第一个for循环中,循环内部执行了4次。
但值得注意的是 “p+i” 。p每次只向后移动2个字节,而数组里的数每个都占4个字节,比如说 a[0]=1,占4个字节就是 00 00 00 01(16进制码),而内存中是倒着储存的。
即:01 00 00 00 02 00 00 00 03 00 00 00....
p每次向右移动两个字节,并且*(p+i)被赋为0,所以经过4次循环:
01 00 00 00 02 00 00 00 会变成 00 00 00 00 00 00 00 00
当最后用for循环输出a数组时,得到的结果就是:0 0 3 4 5。
再来看下面的代码:
#include<stdio.h>
int main()
{
int a = 0x11223344;
short* p = (short*)&a;
*p = 0;
printf("%x", a);
return 0;
}
我以16进制的形式初始化a,然后取a的地址,强制性转换成short*类型 ,再存到p里面。
此时我让*p=0,其实就是使其前2个字节为0,11223344 在内存中以 44 33 22 11 存储,相当于把“44 33”变成“00 00”。
所以当我以16进制的形式输出a时,结果是11220000。
3.用递归实现“2+22+222+2222+........”(不一定是2):
先来用简单的方法做:
#include<stdio.h>
int main()
{
int a = 0, n = 0;
scanf("%d %d", &a, &n);
int i = 0, ret = 0, sum = 0;
for (i = 0;i < n;i++)
{
ret = ret * 10 + a; //得出算式中每一个加数
sum += ret; //求和
}
printf("%d", sum);
return 0;
}
为了锻炼递归的思维能力,尝试用递归解题:
2+22+222+2222+22222
可以看作:前4个加数+最后1个加数
而前4个加数又可以看作:前3个加数+当前最后1个加数
.......
不断的拆分前 n 个加数,直到n 等于1,返回2。
这似乎是一个递归的思路。
那么问题来了,每一次拆分的最后1个加数该怎么求?
尝试拆解2222,发现:
2222=222*10+2;
222=22*10+2;
22=2*10+2;
直到只剩下1位时,返回2。
所以我们应该构造两个递归,一个用来求每一个加数,一个用来求和。
代码如下:
#include<stdio.h>
int find(int a, int n)
{
if (n == 1)
{
return a;
}
return 10 * find(a, n - 1) + 2; 计算n>1的每一个加数
}
int finding(int a, int n)
{
if (n == 1)
{
return a;
}
return finding(a, n - 1) + find(a, n); 前n个加数+第n个加数
}
int main()
{
int a = 0, n = 0;
scanf("%d %d", &a, &n);
int ret = finding(a, n);
printf("%d", ret);
return 0;
}
4.超级水仙花数:
求出1到10000内,假设a是一个n位数,如果a的每一位的n次方相加的和等于a,a就是超级水仙花数。
先梳理一下思路:
在遍历1到10000时,首先要判断此时的 i 是几位数,从而确定 n。
再把a的每一位求出来,看n次方相加的和是否等于 i 。
代码如下:
#include<stdio.h>
int my_pow(int a, int n)
{
if (n == 1)
{
return a;
}
return a * my_pow(a, n - 1);
}
int main()
{
int i = 0;
for (i = 1;i <= 10000;i++)
{
int tmp = i, sum = 0, n = 1; ; // i 至少是一个一位数
while (tmp > 9) //当tmp是一位数时,跳出循环
{
n++;
tmp /= 10;
}
tmp = i;
while (tmp)
{
sum += my_pow(tmp % 10, n); //自定义函数算每一位的n次方
tmp /= 10;
}
if (sum == i)
{
printf("%d\n", i);
}
}
return 0;
}