大数相加c语言实现

c语言中int类型是有一定的范围的,例如在32位的情况下可以表示的最大整数是2^31 – 1 = 2147483647 。

如果想要进行更多位数的整数加法,可以用数组,分别对每个位进行计算。

合法数字检查

输入的时候应检查输入的是否是合法的数字,若不是则应进行处理。

分配空间

本文中的程序可以接收任意多位数的输入,因为采用的是运行时根据输入的位数分配空间的。

存放结果的数组,比两个数组中位数最多的那个位数还要多2,一个用来保存可能的进位(例如9+9 两个一位数结果是二位数),另一个用来保存表示字符串结束的空字符’\0′

输入54321和192后,在内存中是这样表示的

scrn20141114141038

个位对齐

数字按照字符的形式存入数组后,进行运算的时候还需要从个位开始算起,所以应该将num2向右移动,让个位对齐。

也可以将各个位数字逆序,这样从下标0开始,就是对齐的个位数字。

逆序的过程可以顺便把字符变为对应十进制数字,只需要减去’0’即可。

本程序中对齐后效果如下

scrn20141114141501

n1和n2分配空间大小是最长数字的位数+1 ,最高位后面全部置0.这样是为了计算时候的方便。

这样下标0是个位 下标1是十位 下标2是百位……

计算

scrn20141114142205

c语言代码

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

#define INIT_LENGTH 20	//数字位数的起始大小

char * inputBigNum(void);	//接收标准输入的数字 存入内存后返回地址 返回的地址需要free
char * bigNumAdd(const char *num1, const char *num2);	//计算num1+num2 结果是一个指针 用完后需要free

int main(void)
{
	char *num1;	//数字1指针
	char *num2;	//数字2指针
	char *res;	//存放结果的指针

	printf("Input the first num:\n");
	num1 = inputBigNum();
	while (num1 == NULL)	//判断非法数字
	{
		printf("Invalid num, please input again:\n");
		num1 = inputBigNum();
	}

	printf("Input the second num:\n");
	while ((num2 = inputBigNum()) == NULL)	//判断非法数字
	{
		printf("Invalid num, please input again:\n");
		num2 = inputBigNum();
	}

	res = bigNumAdd(num1, num2);	//计算

	printf("num1: %s\n", num1);
	printf("num2: %s\n", num2);
	printf("res: %s\n", res);

	free(num1);
	free(num2);
	free(res);

	return 0;
}

/*
 * 根据输入数字个数分配内存(采用翻倍增加空间的方式 有效利用率大于50%)
 * 如果输入中有非数字 返回NULL
 * 如果输入是合法数字 返回一个存放该数字字符串的指针 
 * 返回有效指针时,记得用完后释放内存
*/
char * inputBigNum(void)
{
	char *p;
	int i = 0;
	int current_capacity = INIT_LENGTH;
	char ch;
	int ok = 1;

	if ((p = (char *)malloc(INIT_LENGTH * sizeof(char))) == NULL)
		exit(-1);

	while ((ch = getchar()) != '\n')
	{
		p[i++] = ch;
		if (ch < '0' || ch > '9')
		{
			ok = 0;
		}
		//已经写入了i个数字
		if (i+1 == current_capacity)
		{
			if ((p = (char *)realloc(p, current_capacity * 2 * sizeof(char))) == NULL)
				exit(-1);
			current_capacity *= 2;
		}
	}
	p[i] = '\0';

	if (ok == 0)
	{
		free(p);
		return NULL;
	}
	else
	{
		return p;
	}
}

/*
 * 计算num1 + num2 结果是字符串形式 
 * 返回存放结果的字符串地址,记得用完后free
*/
char * bigNumAdd(const char *num1, const char *num2)
{
	int i;

	int num1_len;	//num1的数字位数
	int num2_len;	//num2的数字位数
	int res_len;	//计算结果的数字位数 包括最后的空字符'\0'

	char *n1;	//临时存放num1
	char *n2;	//临时存放num2
	char *res;	//存放结果

	int c = 0;	//每一位上的进位 个位上的进位初始时是0

	//计算长度
	num1_len = strlen(num1);
	num2_len = strlen(num2);
	res_len = num1_len > num2_len ? num1_len : num2_len;

	//分配内存 两个加数最高位的更高一位设置为0 结果包含可能的进位和空字符'\0'
	if ((n1 = (char *)malloc(res_len * sizeof(char) + 1)) == NULL)
		exit(-1);
	if ((n2 = (char *)malloc(res_len * sizeof(char) + 1)) == NULL)
		exit(-1);
	if ((res = (char *)malloc(res_len * sizeof(char) + 2)) == NULL)
		exit(-1);
	memset(n1, 0, res_len * sizeof(char) + 1);
	memset(n2, 0, res_len * sizeof(char) + 1);
	memset(res, 0, res_len * sizeof(char) + 2);
	
	//将原加数按照逆序存入n1和n2 同时转换为数字
	for (i = 0; i < num1_len; ++i)
	{
		n1[i] = num1[num1_len-i-1] - '0';
	}
	for (i = 0; i < num2_len; ++i)
	{
		n2[i] = num2[num2_len-i-1] - '0';
	}

	//按位进行加运算
	for (i = 0; i < res_len + 1; ++i)
	{
		res[res_len-i] = ((n1[i] + n2[i] + c) % 10) + '0';	//结果最高位是个位
		c = (n1[i] + n2[i] + c) / 10;	//进位
	}
	res[res_len+1] = '\0';	//设置末尾的空字符

	//释放临时内存
	free(n1);
	free(n2);

	return res;
}

 

如果文章对你有帮助,欢迎点赞或打赏(金额不限)。你的打赏将全部用于支付网站服务器费用和提高网站文章质量,谢谢支持。

版权声明:

本文由 原创,商业转载请联系作者获得授权。
非商业转载请注明作者 雅乐网 ,并附带本文链接:
https://www.yalewoo.com/c_big_number_add.html

上一篇:

下一篇:

我要评论

验证码*: 7 + 1 =