从这里开始记录下学期C语言的作业
题目一:大整数运算
- 涉及知识点:数组、流程控制、函数等
- 要求:用整型数组表示10进制大整数(超过2^32的整数),数组的每个元素存储大整数的一位数字,实现大整数的加减法。
后来老师在题目里也给了很明确的思路:
- 倒序储存大整数,更加符合我们从左到右访问数组的习惯
- 从数组第一位开始加减,直到最后一位
- 最后将结果倒序输出就完事了
有几个需要注意的地方
- 数字的正负号最好单独存放
- 在实现减法的时候,用 绝对值大的数 减 绝对值小的数,这样在计算结果里不会出现负数的情况
- 无论什么时候,结果的正负号都是与绝对值大的数的符号相同
- 输出时记得去掉多余的0
- 还有计算时的两种特殊情况:当某一位结果是0又要想下借1时,当结果是9又要加1时
本人莫名其妙地选用了可变数组(傻傻的),被老师说效率低
其实用链表写更好
下面就直接贴上代码和注释了
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<stdbool.h>
typedef struct { //定义一个可变数组,避免整数过大导致数组越界
int *array; //数组,用于存放大整数
int size; //数组大小
int num; //整数的位数
int symbol; //正负号
} Array;
Array Array_create(int size); //创建一个可变数组
void init(int *a, int t, int size); //初始化数组
int Array_num(Array a); //获取整数的位数
int* Array_symbol(Array* a); //获取整数的符号,并且可以修改
int* Array_indexof(Array *a, int index); //获取下标所在的元素,并且可以修改
void Array_free(Array *a); //销毁数组,释放内存
void Array_expand(Array *a, int more_size); //扩大数组
void Num_input(Array *a); //输入大整数
void Order_re(Array *a); //将输入的数字倒序
void Calculate(Array a, int s, Array b, Array *c);
int toNum(char c); //将字符转化为数字
void swap(int *a, int *b); //交换两个数
int main(int argc, char const *argv[]) {
Array num1 = Array_create(40); //初始大小为40
Array num2 = Array_create(40);
bool isinput1, isinput2, isinputs; //记录两个整数、加/减号是否输入
isinput1 = isinput2 = isinputs = false; //默认为false
int symbol; //记录加减号
char c;
//此处为输入部分
printf("请输入“整数 加/减号 整数”的形式\n");
while(isinput2 == false) { //如果第二个整数已输入,则输入部分完成
if(isinput1 == false) { //如果第一个整数没有输入
Num_input(&num1);
Order_re(&num1);
isinput1 = true;
}
else if(isinputs == false) {//如果加减号没有输入
scanf("%c ", &c);
symbol = ',' - c;
isinputs = true;
/*
在ASCII表中'+' ',' '-'按从小到大顺序依次排列
如果c是'+',symbol == 1
如果c是'-',symbol == -1
*/
}
else { //第一个整数和加减号都输入完后
Num_input(&num2);
Order_re(&num2);
isinput2 = true;
}
}
int the_bigger = 1; //比较两个数的绝对值更大,默认为第一个数
if(Array_num(num1) < Array_num(num2)) { //先比较两个数的位数
the_bigger = 2;
}
else if(Array_num(num1) == Array_num(num2)) { //若位数相同,则从高位到低位比较
for(int i = Array_num(num1) - 1; i >= 0; i --) {
if(*Array_indexof(&num1, i) > *Array_indexof(&num2, i)) {
break;
}
else if(*Array_indexof(&num1, i) < *Array_indexof(&num2, i)) {
the_bigger = 2;
break;
}
}
}
Array num3; //创建结果数组
if(the_bigger == 1){ //最大长度是较大整数的位数 + 1
num3 = Array_create(Array_num(num1) + 1);
}
else {
num3 = Array_create(Array_num(num2) + 1);
}
/*
下面是计算过程
如果三个符号之积为1,为整数相加
如果三个符号之积为-1,为整数相减
*/
int s = *Array_symbol(&num1) * symbol * *Array_symbol(&num2);
if(the_bigger == 1) { //若num1的绝对值较大,则|num3| = |num1| ± |num2|
Calculate(num1, s, num2, &num3);
*Array_symbol(&num3) = *Array_symbol(&num1); //结果的符号与第一个整数的符号相同
}
else { //若num1的绝对值较大,则|num3| = |num2| ± |num1|
Calculate(num2, s, num1, &num3);
*Array_symbol(&num3) = *Array_symbol(&num2) * symbol; //结果的符号与第二个整数的符号相同
}
Order_re(&num3);
//下面输出结果
if(*Array_symbol(&num3) == -1)
printf("-");
int t = 0;
for(int i = 0; i < Array_num(num3); i ++) {
if(*Array_indexof(&num3, i) == 0 && t == 0 && i != 0) { //输出前检查,是否有多余的0
continue;
}
printf("%d", *Array_indexof(&num3, i));
t = 1;
}
return 0;
}
Array Array_create(int size) {
Array a;
a.array = (int*) malloc(sizeof(int) * size);
init(a.array, 0, size);
a.size = size;
a.num = 0;
a.symbol = 1; //默认符号为正数
return a;
}
void init(int *a, int t, int size) {
for(int i = 0; i < size; i ++) {
a[i] = t;
}
}
int Array_num(Array a) {
return a.num;
}
int* Array_symbol(Array *a) {
return &(a->symbol);
}
int* Array_indexof(Array *a, int index) { //获取下标对应的数字
if(index >= a->size) {
Array_expand(a, 10); //若下标超过数组大小,增长10个元素
}
return &(a->array[index]);
}
void Array_free(Array *a) {
free(a->array);
a->array = NULL;
a->size = 0;
}
void Array_expand(Array *a, int more_size) { //扩大数组
int *p = (int*)malloc(sizeof(int) * (a->size + more_size));
for (int i = 0; i < a->size; i++) {
p[i] = a->array[i];
}
free(a->array);
a->array = p;
a->size += more_size;
init(a->array, 0, a->size);
}
void Num_input(Array *a) {
char c;
do {
scanf("%c", &c);
if(c == '+' || c == '-') {
a->symbol = ',' - c;
/*
在ASCII表中'+' ',' '-'按从小到大顺序依次排列
如果c是'+',symbol == 1
如果c是'-',symbol == -1
*/
}
else if(c >= '0' && c <= '9') {
*Array_indexof(a, a->num) = toNum(c);
a->num ++;
}
}while(c != ' ' && c != '\n'); //当输入了空格或回车时,结束输入
}
void Order_re(Array *a) { //将数组倒序
for(int i = 0; i < (a->num / 2); i ++) {
swap(Array_indexof(a, i), Array_indexof(a, a->num - i -1));
}
}
void Calculate(Array a, int s, Array b, Array *c) { //最重要的计算部分
int t;
int reminder = 0; //记录向上借一或加一
for(int i = 0; i < c->size - 1; i ++) {
t = *Array_indexof(&a, i) + *Array_indexof(&b, i) * s;
if(t == 0 && reminder == -1) { //特殊情况,当这位为0,且还要向下借走1时
*Array_indexof(c, i) = 10 + reminder;
reminder = -1;
}
else if(t >= 0) {
if(t % 10 + reminder == 10) { //特殊情况, 当9 + reminder == 10时,需要向上加一
*Array_indexof(c, i) = 0;
reminder = 1;
}
else {
*Array_indexof(c, i) = t % 10 + reminder;
reminder = t / 10;
}
}
else { //此时t < 0,需要向上借1
*Array_indexof(c, i) = 10 + t + reminder;
reminder = -1;
}
c->num ++;
if( i == c->size - 2 && reminder > 0) {
c->array[i + 1] = reminder;
c->num ++;
}
}
}
int toNum(char c) { //偷懒,直接写个函数将字符数字转化为整型数字
return (int)(c - '0');
}
void swap(int *a, int *b) {
int t = *a;
*a = *b;
*b = t;
}