以下C程序将大量数字乘以字符串。对于正数,它可以很好地工作,但是对于大数,将使用过多的内存。如何改善它以减少内存使用量?
我的程序:
char *strrev(char *str) {
char *p1, *p2;
if(!str || !*str)
return str;
for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2) {
*p1 ^= *p2;
*p2 ^= *p1;
*p1 ^= *p2;
}
return str;
}
char* addNumbers(char* c1, char* c2) {
char *m1;
char *m2;
if (strlen(c1) >= strlen(c2)) {
m1 = malloc(sizeof(c1));
m2 = malloc(sizeof(c2));
strcpy(m1, c1);
strcpy(m2, c2);
} else {
m1 = malloc(sizeof(c2));
m2 = malloc(sizeof(c1));
strcpy(m1, c2);
strcpy(m2, c1);
}
strrev(m1);
strrev(m2);
int lm1 = strlen(m1);
int lm2 = strlen(m2);
//char *w = malloc(1000000);
char its;
int jd = 0;
for (int l = 0; l < lm1; l++) {
int w1 = strToInt(m1[l]);
int w2;
if (l < strlen(m2)) {
w2 = strToInt(m2[l]);
} else {
w2 = 0;
}
int w3 = w1 + w2 + jd;
if (w3 > 9) {
jd = 1;
w3 = w3 % 10;
} else {
jd = 0;
}
its = w3 + 48;
m1[l] = its;
}
if (jd > 0) {
char its2[12];
sprintf(its2, "%d", jd);
strcat(m1, its2);
}
return strrev(m1);
}
int main(int argc, char* argv[]) {
char *c1;
char *c2;
if (strlen(argv[1]) > strlen(argv[2])) {
c1 = malloc(sizeof(argv[1]));
c2 = malloc(sizeof(argv[2]));
strcpy(c1, argv[1]);
strcpy(c2, argv[2]);
} else {
c1 = malloc(sizeof(argv[2]));
c2 = malloc(sizeof(argv[1]));
strcpy(c1, argv[2]);
strcpy(c2, argv[1]);
}
char counter[sizeof(c2)];
sprintf(counter, "%d", 0);
char one[2];
sprintf(one, "%d", 1);
char *w = malloc(100);
while (strcmp(counter, c2) != 0) {
strcpy(counter, addNumbers(counter, one));
strcpy(w, addNumbers(w, c1));
}
printf("%s\n%s\n", c1, c2);
free(c1);
free(c2);
printf("Result: %s,%ld\n\n", w,sizeof(w));
free(w);
}
我知道存在更好的算法,但是我必须使用addNumbers()
函数。
答案 0 :(得分:3)
如何改进它以节省内存?
如所写,您的帖子包含多次调用calloc()
的实例,每个实例都创建堆内存,但是创建的所有内存都没有被释放,从而导致内存泄漏。至少,对于您的问题的答案是,对于每次对free()
的调用,只需对malloc()
进行相应的调用。
顺便说一句,关于何时,何地以及如何使用动态分配的内存 here 和 here 进行了很好的讨论。 >
以下是addNumbers
函数的简化,同时保留了其原始原型。根据注释中的要求,它使用没有其他库的ANSIC。除其他功能外,它还具有集成的字符串反转功能(消除了strrev()
函数),仅使用了一个动态分配的内存实例,并且没有泄漏任何实例。
注意,该示例使用硬编码的输入进行说明,但是通过取消注释scanf()
函数并添加命令行输入,可以轻松地将其转换为符合您的需求的输入。
char* addNumbers(char* s1, char* s2) ;
int main(int argc, char *argv[])
{
char s1[101] = {"150353265326"};
char s2[101] = {"22055653351"};
// Expect: 3316139500221184007426
//scanf(" %s",s1);
//scanf(" %s",s2);
char * result = addNumbers(s1, s2);
printf("%s\n", result);
free(result);
return 0;
}
char* addNumbers(char* s1, char* s2)
{
int i=0, j=0, tmp;
int l1 = strlen(s1);
int l2 = strlen(s2);
int a[100]={0},b[100]={0};
int ans[200] = {0};
char *result = calloc(l1+l2+1, 1);
for(i = l1-1,j=0;i>=0;i--,j++)
{
a[j] = s1[i]-'0';
}
for(i = l2-1,j=0;i>=0;i--,j++)
{
b[j] = s2[i]-'0';
}
for(i = 0;i < l2;i++)
{
for(j = 0;j < l1;j++)
{
ans[i+j] += b[i]*a[j];
}
}
for(i = 0;i < l1+l2;i++)
{
tmp = ans[i]/10;
ans[i] = ans[i]%10;
ans[i+1] = ans[i+1] + tmp;
}
for(i = l1+l2; i>= 0;i--)
{
if(ans[i] > 0)
break;
}
for(j=i;j >= 0;j--)
{
result[i-j] = (char)('0' + ans[j]);
}
return result;
}
使用命令行输入进行了测试:
注意:这种改编归功于 this implementation.
答案 1 :(得分:0)
您正在通过分配而不是释放它来消耗大量内存。即使您释放了它,也有大量的分配,复制和取消分配。
与其这样做,不如为结果分配空间,然后累积相同的结果,直到产品完成为止。
由于您的输入可以是const字符串,因此您应该只针对main()函数中的一个malloc来分配结果空间,然后其余部分就地进行修改。如果您需要反转输入字符串,那么您将需要几个分配,仅此而已。我不会在字符串中进行加法运算,而是使用uint_8数组,并在开始时对每个输入执行一次strToInt转换,而不是在循环中进行多次。