超大整数相加

输入
第一个数字M代表接下来有几组数据;

接下来每一组数据包含两个数据,数字很大哦;
确保没有前缀0,数据很大;

输出
输出计算后的结果,每个结果占一行;

样例输入
3
123 456
1234567890987654321 9876543210123456789
11111111111111111111111111111 111111111111111111111111111111
样例输出
579
11111111101111111110
122222222222222222222222222222
*/

/* 解决这个问题需要处理的小问题:
1.如何存储很长的数字(类型的变量存不了几十位长的整数!)
2.如何将存储的数据以合适的方法取出来,进行计算
/
/
下面用的方法是啰嗦的,但是明确了:往字符数组里填充某个整数,该整数会被视为某个字符的ascii码值.
而往整形数组里填充整数,那促进去的就是整数本省(吗?)
探究了如何从整数存到字符数组,如何从字符数组提取出一位(叫数码吗?)整数(0~9范围的)(相差48/‘0’)
对与0有关的数组的初始化往往会漏带掉导致随机值的莫名其妙
同一数组使用strcpy是十分不建议的. */

#include <stdio.h>
#include <string.h>

// 返回字符串?/指向字符串的指针? char strlonger();
int main(){
    
//printf("test_4\n");
    int n;
    while(scanf("%d",&n) != EOF)
    {
        for(int i = 0;i<n;i++)
        {
            char recieve_big_number_1[10000];//数组不够大可能无法输出结果/
            char recieve_big_number_2[10000];
            char sum_up[10000];
            scanf("%s%s",recieve_big_number_1,recieve_big_number_2);/* 暂且 将输入大数视为字符串 存入字符数组. */

            int dif;/*差值difference */

            char *big;
            char *small;//char (*small)[100];small = recievi_big_number_1,到底哪种形式可行呢?

            int len_small;
            int len_big;
            int up = 0;
            /* 判断那个数大 ,使用abs的话会简洁些*/
            if(  ( dif =  strlen(recieve_big_number_1) - strlen(recieve_big_number_2) )  >= 0)
            {
                big = recieve_big_number_1;
                len_big = strlen(big);
                small = recieve_big_number_2;
                len_small = strlen(small);
            }    
            else
            {
                big = recieve_big_number_2;
                len_big = strlen(big);
                small = recieve_big_number_1;
                len_small = strlen(small);
                dif = -dif;
            }

            strcpy(&sum_up[1],big);/* 试图空出sum_up[0]这个可能的最高位. (该操作确实可行) */
            /* 当然,这样sum_up[0]的值是随机的,你以选择初始化,当然这题不必须,因为输出的为可能1.从[1]开始输出;2.[0]会被进位值覆盖(为1) */
            
            /* 位置对齐(其实这件事并不必要
            ,当然,它对于连锁进位还是提供了方便):
            但还可以调整填入sum_up的顺序来(高位往后填充,再逆序从高到低输出.)这就无需对齐
            事实上,逆(反)序填充,正序输出的手段可以减少很多的不必要的工作量(输出方式是很灵活的),
            考试的话前者的定位更合适,平时我们正序排列还正序输出只是为了试验某些知识点,检验思维漏洞(这还未必能办到,就不要死磕)*/
           /* 版本一有巨大缺陷 */
           
            // if(dif > 0)
            // {
            //     int j = 0;
            //     for(int i = 0;i<len_small;i++)
            //     {
            //         // 调试时,若看指针的话,只能看到首地址对应元素的变化,更应该观察的是指针所指的源数组的被间接改变的结果 
            //         /*考虑dif== 0, */
            //         small[i+dif] = small[i];
            //         //small[i] = '0';这么些的话,前面一串都被赋值为0.考虑另用一个互不干扰的变量
            //         if(j<dif)
            //             small[j++] ='0';//'0'就是48啦.(int)
                
            //     } 
            //     small[len_small] = '0';  //这句话有待商榷:          
            // }
            /* 版本2 */
            //

           // strcpy(small[len_big - len_small],small);这里是为什么?处理较长的的输入是就会报错segmentation fault
            /* 在同一个字符串中使用strcpy有哪些风险? */
            for(int i = 0;i<len_small;i++)
            {
                /* 如同交换两个变量的值,为了避免重叠的问题,还应开一个buf // 或者考虑从后面的字符开始挪,可以避免重叠造成覆盖,数据丢失*/
                /* 值得一提的是,类似的操作再不同的顺序安排下可能产生巨大的不同 */
                 small[len_small - 1 - i+dif] = small[len_small -1 -i] ;
            }
            for(int i = 0;i<len_big -len_small;i++)//可以考虑使用字符串函数.
            {
                small[i] = '0';
            }
            /* 打个补丁 */
            small[len_big] = '\0';
            /* 对齐后刷新len_small */
            len_small = strlen(small);
            

        /* 将字符转化为数字 */
        /* int big_last;
            big_last = (int)big[len_big-1] - 48; */
            //test将会是存入的数字字符的ASCII值,然而,
            //由于ASCII值具有良好的递增规律,-48就可以转换为输入的数字大小了
            //printf("%d",test);

            /* 小学的按位加法(及进位) */
            
            for(int i = 0;i<len_big /* && i<len_small */;i++)/*   i 类似(前移)改变量 */
            {   /* 以下可以得到迭代 */
                
                int signal_add_i = 0;
                /* signal_add_i本身不依赖于对齐 */
                
                signal_add_i = (int)big[len_big-1 - i ] - 48  +  (int)small[len_small-1 -i] - 48 + up ;
                up = 0;/* 加完进位,使得进位记录器up归零,否则up回不去了 */
                /* 如果发生进位 */
                if( signal_add_i >= 10)
                    {
                        up = 1;
                        /* int fill_sum_up;
                        fill_sum_up = (char)(signal_add_i / 10) + 48;
                        sum_up[len_big - i ] = fill_sum_up; */
                        int fill_sum_up;
                        fill_sum_up = (signal_add_i % 10) + '0';
                        sum_up[len_big - i ] = fill_sum_up;


                    }
                    /* 若不发生进位 */
                else
                    sum_up[len_big - i ] = signal_add_i + '0';
                
            }
            //
            if(up == 1) /* 我竟然写成了赋值号 =  */
            {
                sum_up[0] = '1';
                printf("%s\n",sum_up);
                //printf("\n out1 :    %s\n",sum_up);//更清楚输出
                
            }
            
                //if(up = 1) sum_up[len_big - len_small - 1] +=  1;
                /* 打印的时候分个类(首位是否被进位) */
            else 
                printf("%s\n",&sum_up[1]);   /* 非首地址,需& */
                //printf("\n out2:       %s\n",&sum_up[1]);
        }
    
    }
    return 0;
} 

版本_2:(简)

#include <stdio.h>
 #include <string.h>
 int main()
 {
     int n;
     /*      这块代码不可放在外部(测试多组数据时,有残留)
             char s1[100], s2[100];

             再开一对整形数组,存储接受的字符串所转化成的整形数据,即提取各位上的数码,便于运算.而且不会破坏输入数据
             int num1[31], num2[31], len1, len2, i, j;
             */
     while (scanf("%d",&n) != EOF)
     {

         for (int i = 0; i < n; i++)
         {
             char s1[10000], s2[10000];/*允许近万位数相加*/

             //再开一对整形数组,存储接受的字符串所转化成的整形数据,即提取各位上的数码,便于运算.而且不会破坏输入数据
             int num1[10000] = { 0 },/*每一位都初始化为0.*/
                 num2[10000] = { 0 },
                 len1, len2, i, j;

             scanf("%s%s", s1, s2);/*%s来读取输入*/

             len1 = strlen(s1);
             len2 = strlen(s2);

             /* 两个控制变量,使得字符转数字的填充过程中,低位填在前,高位向后填,方便数位对齐相加*/
             i = len1 - 1;/*从最低为起往高位(向前)*/
             j = 0;/*从最高位往低位(向后)*/
			 for (; i >= 0; )
             {
                 num1[j] = s1[i] - 48; //从字符到整数的转换(0~9),并且填充到整形数组
                 j++; 
                 i--;
             }
             /*处理第二个操作数*/
             for (i = len2 - 1, j = 0; i >= 0; i--)
             {

                 num2[i] = s2[j] - 48;
                 j++;
             }
             /* (len2 > len1 ? len2 : len1)的运算结果是len2和len1的较大值,十分紧凑 */
             for (i = 0; i < (len2 > len1 ? len2 : len1); i++)
             {
                 /* 将相加(第i位)的结果保存到num1[i]里 */
                 num1[i] += num2[i];/*相加结果<=9,直接保存(最理想)*/

                 /* 如果需进位(>9):可以表示位10+k (0<=k<=9) */
                 if (num1[i] > 9)
                 {/*向高一位进位+1 */
                     num1[i + 1] ++; /* 迭代高一位的数码,让其+1 */
                     /*继续处理当前位:*/
                     num1[i] -= 10;    /* 留下个位,放在当其位置 */
                 }

             } //for(本循环无法判断最高位;两个数相加,若数量级增大,则最高位必为1)

             /* 最高位的情况(是否进位,以及填充到适当的位置 还需单独判断下: */

             /* 上头的i++在跳出for是已经移位都最高位(如果进位的话) */
             /* 最低位放在num1数组的最前面,这样方便处理未知的最高位,届时逆序输出即可
             (从后往前打印(高位-->低位)) */

             /*如果进位*/
             if (num1[i]) /* 最高位是否1(此时的num1[i]只为1/0 (1是低位进上去的;0则是之前memset()初始化的值,且没有进位)) */
             {
                 for (j = i; j >=0 ; j--) /* 或说:j >= 0 */
                     printf("%d", num1[j]);
                 printf("\n");
             }
             /*不进位:  */
             else
             {

                 for (j = i - 1; j > -1; j--)
                     printf("%d", num1[j]);
                 printf("\n");
             }

         }
     }

     return 0;
 }
posted @ 2022-11-25 19:56  xuchaoxin1375  阅读(19)  评论(0)    收藏  举报  来源