直接上源码:
#include <stdio.h>
#include <stdlib.h>
char* real_mult(const char* a, const char* b) {
int i, j, k, m, n, len_a, len_b;
len_a = strlen(a);
len_b = strlen(b);
int* res_p;
char* c;
res_p = (int*)malloc((len_a + len_b) * sizeof(int));
if (!res_p) {
printf((const char*)"malloc int[%d] fail!\n", len_a + len_b);
for ( ; ; );
}
for (i = len_a + len_b - 1; i >= 0; i--) {
res_p[i] = 0;
}
for (i = 0; i < len_a; i++) {
for (j = 0; j < len_b; j++) {
k = i + j + 1;
res_p[k] += (a[i] - '0') * (b[j] - '0');
}
}
res_p[0] = 0;
for ( ; k > 0; k--) {
res_p[k - 1] += res_p[k] / 10;
res_p[k] %= 10;
}
for (j = 0; j < len_a + len_b; j++) {
if (res_p[j] != 0) {
break;
}
}
c = (char*)malloc((len_a + len_b + 1 - j) * sizeof(char));
if (!c) {
printf((const char*)"malloc char[%d] fail!\n", len_a + len_b + 1 - j);
for ( ; ; );
}
for (i = 0; i < len_a + len_b - j; i++) {
c[i] = (char)(res_p[i + j] + '0');
}
free(res_p);
c[i] = '\0';
return c;
}
char* mult1(char* a, const char* b) {
char* c = real_mult((const char*)a, b);
free(a);
return c;
}
char* order(int n) {
char temp[16];
char* res = (char*)"1";
for ( ; n > 1; n--) {
sprintf((char*)temp, "%d", n);
res = mult1(res, (const char*)temp);
}
return res;
}
int main(int argc, const char* argv[]) {
char* c;
c = order(20000);
printf("%s\n", c);
free(c);
return 0;
}
测试结果比对:
离线
咦,服务器上面跑了一下, 有错误:
root@ubuntu:/tmp# vi multi.c
root@ubuntu:/tmp# gcc -o multi multi.c
multi.c: In function ‘real_mult’:
multi.c:6:10: warning: implicit declaration of function ‘strlen’ [-Wimplicit-function-declaration]
len_a = strlen(a);
^~~~~~
multi.c:6:10: warning: incompatible implicit declaration of built-in function ‘strlen’
multi.c:6:10: note: include ‘<string.h>’ or provide a declaration of ‘strlen’
root@ubuntu:/tmp#
root@ubuntu:/tmp#
root@ubuntu:/tmp#
root@ubuntu:/tmp#
root@ubuntu:/tmp# ./multi
free(): invalid pointer
Aborted
root@ubuntu:/tmp#
离线
win系统和linux还是有些细微差异吧
离线
https://whycan.cn/files/members/3/QQ20181201093927.png
把49行注释起来, 就不会出现内存释放错误, 20000阶乘就算出来了.
------------------------
错不在这!
而是这里
改为这样:
char* order(int n)
{
char temp[16];
char* res = (char*)"1"; //删除
char* res = (char*)malloc(32); //改正后
for ( ; n > 1; n--)
{
sprintf((char*)temp, "%d", n);
res = mult1(res, (const char*)temp);
}
return res;
}
就可以了。
离线
牛, 这么叼的bug都被揪出来了.
离线
我也来一个go版本:
package main
import (
"fmt"
"strconv"
// "log"
)
//BigMulti 大数相乘
func BigMulti(a, b string) string {
if a == "0" || b == "0" {
return "0"
}
// string转换成[]byte,容易取得相应位上的具体值
bsi := []byte(a)
bsj := []byte(b)
temp := make([]int, len(bsi)+len(bsj))
//两数相乘,结果位数不会超过两乘数位数和,即temp的长度只可能为 len(num1)+len(num2) 或 len(num1)+len(num2)-1
// 选最大的,免得位数不够
for i := 0; i < len(bsi); i++ {
for j := 0; j < len(bsj); j++ {
// 对应每个位上的乘积,直接累加存入 temp 中相应的位置
temp[i+j+1] += int(bsi[i]-'0') * int(bsj[j]-'0')
}
}
//统一处理进位
for i := len(temp) - 1; i > 0; i-- {
temp[i-1] += temp[i] / 10 //对该结果进位(进到前一位)
temp[i] = temp[i] % 10 //对个位数保留
}
// a 和 b 较小的时候,temp的首位为0
// 为避免输出结果以0开头,需要去掉temp的0首位
if temp[0] == 0 {
temp = temp[1:]
}
//转换结果:将[]int类型的temp转成[]byte类型,
//因为在未处理进位的情况下,temp每位的结果可能超过255(go中,byte类型实为uint8,最大为255),所以temp选用[]int类型
//但在处理完进位后,不再会出现溢出
res := make([]byte, len(temp)) //res 存放最终结果的ASCII码
for i := 0; i < len(temp); i++ {
res[i] = byte(temp[i] + '0')
}
return string(res)
}
func main() {
x := "1"
for i := 1; i <= 20000; i++ {
x = BigMulti(strconv.Itoa(i), x)
}
fmt.Println(x)
}
结果(只贴了三行太长了):
181920632023034513482764175686645876607160990147875264891806221863456946103855753445383609582775872473917750238418991204167124538392657686572347546452493027570920462535787578952590049182341454271803607039252108504728338372929686158005240463884119952662237979106622334146339347439592562978748211316341864766545558666043618408722395194
和c对比可以发现,go编码无需担心内存出错问题,go自带gc,专心写代码逻辑即可,不用为了其它事情分心。所以go兼顾了开发效率和执行速度,迄今为止它是两者平衡最好的语言。
最近编辑记录 kekemuyu (2019-11-18 10:10:57)
离线
膜拜楼上诸位大神
离线
------------------------
错不在这!
而是这里
https://whycan.cn/files/members/334/1.png
改为这样:char* order(int n)
{
char temp[16];
char* res = (char*)"1";//删除
char* res = (char*)malloc(32); //改正后
for ( ; n > 1; n--)
{
sprintf((char*)temp, "%d", n);
res = mult1(res, (const char*)temp);
}
return res;
}就可以了。
确实是这个BUG,疏忽了
离线