【算法】【指针的妙用】自然数求和1+2+3+..+n,不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)

题目描述

求1+2+3+…+n,

要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

样例输入
3
5
样例输出
6
15

使用等差数列公式n(1+n)/2怎么按照条件来实现算法呢?

#include <stdio.h>
#include <stdint.h>

int sum(int n)
{
    return (uintptr_t)( ( &((uint8_t (*) [n])0)[1+n][0]) ) >> 1;
}

int main()
{
    printf("%d\n",sum(5));//sum(5)=15
    return 0;
}

具体解释如下,有点儿类似kernel里面使用container_of的感觉,但是这个(uint8_t (*) [n])0更加的精妙和讨巧,实在是高。

(uintptr_t)((&((uint8_t (*) [n])0)[1+n][0]))  

分别来拆解

1.(uint8_t () [n])0),我们知道(uint8_t ())0)这个是将0转化为uint8_t 数据类型,并且sizeof(uint8_t) = 1,那么(uint8_t () [n])0)表示就是申明为一个数组指针并且每行数据相比前一行数据长度要多n*sizeof(uint8_t),内存起始地址为0,每列数据地址长度增加一个sizeof(uint8_t).实际就是行地址间隔从原来的sizeof(uint8_t)变成n*sizeof(uint8_t)
代码验证如下

for(i = 0; i < 5; i++) {  
    for(j = 0;j < 5 ;j++) {  
        printf("%4lu",(uintptr_t)(&((uint8_t (*)[5])0)[i][j]));  
    }  
    printf("\n");  
}  

打印结果如下:

 0   1   2   3   4  
 5   6   7   8   9  
10  11  12  13  14  
15  16  17  18  19  
20  21  22  23  24 

如果是uint16_t的话,由于sizeof(uint16_t)=2,所以上面每列地址数值相差2,每行相差10,如下:

 0   2   4   6   8  
10  12  14  16  18  
20  22  24  26  28  
30  32  34  36  38  
40  42  44  46  48  

对于(uintptr_t)((&((uint8_t (*) [n])0)[i]),(i=0~5,n=5):

 0  
 5  
10  
15  
20  

对于(uintptr_t)((&((uint8_t (*))0)[i]),(i=0~5,n=5),最常用的:

0  
1  
2  
3  
4  

所以推理出了(uint8_t (*) [n])0,将行地址间隔增大了n*sizeof(uint8_t)。

2.&((uint8_t (*) [n])0)[1+n][0]) 相对0地址,偏移(1+n)*n地址长度,(1+n)*1是个数,如果[1+n][1],则(1+n)*2个数。

3.(uintptr_t)( ( &((uint8_t () [n])0)[1+n][0]) ) 将偏移地址转化为可以输出的实际数值,即n(1+n),然而n(n+1)/2,就是1+2+3+…+n之和,问题得解。

4.所以能够知道[1+n][0]就是n=5,就是第6行第1列的数据为30,除以2就是sum(5)=15的数值了。

5.(uintptr_t)( ( &((uint8_t (*) [n])0)[1+n][0]) ) >> 1就是(1+n)*n/2就是1+2+3+….+n之和。

绝对是妙不可言啊!!!上面是&((type () [n])0)的妙用,同时明白更加常用的&((type ())0)

6.下面也是一个函数指针的递归调用,完美的解决了题目所需的要求:

typedef unsigned int(*fun)(unsigned int);
unsigned int Solution(unsigned int n)
{
    return 0;
}

unsigned int Sum_Solution(unsigned int n)
{
    static fun f[2] = { Solution, Sum_Solution };
    return n + f[!!n](n - 1);
}

世上无难事只怕有心人,更怕脑容量不够,不肯思索!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值