user-0 提问: free函数如何正确使用，求大神解答。。

回复:
user: user-0
content: 终于知道第一个free那边为什么会错了。。原来是去free了一个常量字符串，我以为malloc之后就能调free,中间指向常量0后那个malloc（2）完全就没用到了  ALNG的思路真的不错，针对题目给出了特定的省时省内存的解法，收获不少，感谢。。其实我原先写了个通用点的大数加乘法看这题有用到就拷过来用了，好了结贴了

user: user-1
content: free函数只能释放通过malloc、realloc、calloc函数开辟的内存，你的代码里sum开始是malloc的，但是你紧接着就把sum指向了“0”（这里实际上已经造成了内存泄漏），后面tp又指向了sum指向的地址即“0”，这样的地址不是通过上述三个函数分配的，所以会报错。

user: user-2
content: 闲的无聊，我实现了一遍，你先自己做在用我的对照吧。  好久不写C了，尽量按照记忆中的C写的，难保没有露马脚的地方 :)  /* It was said that when testing the first computer designed by von Neumann, people gave the  following problem to both the legendary professor and the new computer: If the 4th digit  of 2^n is 7, what is the smallest n? The machine and von Neumann began computing at the  same moment, and von Neumann gave the answer first.  Now you are challenged with a similar but more complicated problem: If the K-th digit of  M^n is 7, what is the smallest n?  Input  Each case is given in a line with 2 numbers: K and M (< 1,000).  Output  For each test case, please output in a line the smallest n.  You can assume:  The answer always exist. The answer is no more than 100. Sample Input  3 2 4 2 4 3 Sample Output  15 21 11 */  #include<stdio.h> #include<string.h> #include<stdlib.h>     int find_n(int k, int m);   int main() { 	int k,m;     while (scanf("%d %d", &k, &m) == 2)         printf("%d\n", find_n(m,k));     return 0; }  /* test if the digit'th(starting from 0) digit of num's decimal representation is 7  * return 1 when test true, false otherwise.  *  * eg. test7(157434,2) is true, while test7(157432,3) is false  *   * note: num should be between 0 and 10^9-1  *        and digit should be 0 to 8  */ int test7(long num, int digit) { 	char _[10]; 	sprintf(_,"%ld", num); 	return _[digit]=='7'; }  /* for debug only.  * I leave it behind because it sheds some light on how the large number  * should be interpreted  *  */ void dump(long * p, int cnt) { 	printf("%d", p[cnt-1]); 	for(int i=cnt-2; i>=0; --i) 		printf("%09d",p[i]); 	printf("\n"); }   void multiply(long* p, int* cnt_element, int m);  /* given integer k and m, find the smallest integer n such that  * the k'th digit of m^n (decimal representation) is 7  *  */ int find_n(int k, int m) { 	// sizeof(long) is guaranteed to be 4 	long array[34]; 	int cnt=1, // number of elements currently filled 		n=1; // the value that we are looking for 	array[0]=m; // we will put least significant int(s) in element 0  	--k; // so that first digit is the 0th digit  	while( cnt< k/9 || !test7(array[k/9], k%9) ) 	{ 		++n; 		multiply(array, &cnt, m); 	} 	return n; 	 }  /* our ad hoc large number multiplication function  * param: p: points to array of long's which represent a large number. note the least  *          significant element is the 0th element and each element should be between  *          0 and 10^9-1;  *        pcnt: points to number of elements actually used in the above array  *        m: number to multiply into the large number(no more than 100 according to problem description)     *  *  */ void multiply(long* p, int* pcnt, int m) { 	long long v=0; 	long carry=0; 	for(int i=0; i<*pcnt; ++i) 	{ 		v=carry+(long long)p[i]*m; 		p[i]=(long)(v%1000000000); 		carry=(long)(v/1000000000); 	} 	if(carry) 		p[(*pcnt)++]=carry; }

user: user-2
content: 讨厌的CSDN不许连续回复超过3次！  回到这题，如果没有聪明的方法(估计有), 就用你的暴力法，那你的乘法实现还是太低效率了，即使写对了也10有8、9会timeout. 其实根本不需要那么多次动态分配内存，  已知M<1000, n<100, 所以M^n不大于10^300， 你直接在堆上开一个300的数组，就对它操作，这样一次malloc和free都不用，会大大提高你的程序的效率。  还可以再提高，你用一个字符来表示一个十进制的数位，这当然可以得到正确的结果，但效率还可以提高。 可以相信目标机器不会低于32位处理器，更准确的说法应该是目标机器上的c编译器的sizeof(int)不会低于4. 你完全可以用size_t或者int数组(instead of char[]), 在int间用10^9进位，每个int降级到10^9进位，即如果一个整数存的是10^9-1， 对它increment后，它会归0，而高位整数进一......希望你听懂了我的意思。这样的好处是计算更紧凑而保留了快速检查第k位是否为7的能力......   如果你能看懂我上面的意思，建议你用那个思路再实现一遍，甚至对比实现一遍，比较两者的效率，假定可以通过ACM的机器检测。  哦，你没必要定义乘法(*)，定义自乘(*=)就好了。形如:  void multiply_by(int self[], int num);  其中的self是一个足够装下10^300次方，成员间10^9进位的整型数组（啰嗦一下，每个成员装10^9, 10^300需要34个这样的int, 可以想一下你原来用成员用char，成员间10进位的方案要用300个元素, 哪一个会更快？)  你先试试，搞不定再问吧。

user: user-3
content: 第一次进循环的时候，sum="0",tp=sum，这时候tp指向了常量字符串“0”，这种怎么能free呢？

user: user-0
content: 引用 1 楼 ALNG 的回复:     char *sum = malloc(2);     char *tp;     sum = "0";     for (i = 0; i < l2; i++)     {         tp = sum;         t = multiplyHelper(s1, *(s2 + l2 - 1 - i) - '0');         zt = appendTailZero(t, i);         sum = add(tp, zt);         free(t);         free(zt);         free(tp);//假设在这free     }     return sum; }  tp就是sum, 循环体第二次再进入时那个指针就已经free掉了， tp和sum都指向未定义的内存位置了。不可以在循环体内free. 又因为你把返回值放在那里，如果你在本函数结束前free掉tp(亦即sum），调用函数使用返回值的时候又会发生访问错误，所以应该由调用者free. 谢谢你的解答，下面两个回复我能理解，这里还不是很清楚，以我的理解，在第一次进入循环开始，tp和sum都指向0字符串，而经过加和以后，sum指向add函数返回的新的内存区域，而我没有再tp=sum,这时候tp应该还是指向0字符串啊？难道这时tp和sum都是指向add后的新的内存区域，我free(tp)把加和的结果free掉了？

user: user-2
content: 说一说你的multiply的设计，每一个函数原型都是一份合同，你的mutiply函数这份合同是这样的: s1指向乘数1字符数组的指针，s2指向乘数2字符数组的指针； 返回指向存放两者相乘的运算结果的字符数组的指针，这个字符数组是动态用malloc从堆中分配的，在使用完毕后free之是调用者的责任.  再看你的代码          while (strlen(r) < k)         {             r = multiply(r, m);             count++;         }  第一遍的时候r就是m, 等于计算m的平方，这个确实不需要free, 第二遍的时候那个r已经是动态分配的了，你如果不free掉它就直接把multiply的运算结果(一个新的动态分配的内存指针)赋给r, 那么前一次分配的内存就泄露了，如此反复，除了最后一个有用，之前的都泄露了......

user: user-2
content: int main() {     int k;     char m[5];     while (scanf("%d %s", &k, m) != EOF)     {         char *r = m;         int count = 1;         while (strlen(r) < k)         {             char * tmp=multiply(r, m);             if(r!=m)                 free(r);             r = tmp;             count++;         }         r += strlen(r) - k;         while (*r != '7')         {             char *tmp=multiply(r, m);             if(r!=m) // you should be able to skip this line!!                 free(r);             r=tmp;             r += strlen(r) - k;             count++;         }         printf("%d\n", count);     }     return 0; }  对应的， main应该做如上修改。没有查你的程序的逻辑和其他问题，不保证能通过。

user: user-2
content: char *sum = malloc(2);     char *tp;     sum = "0";     for (i = 0; i < l2; i++)     {         tp = sum;         t = multiplyHelper(s1, *(s2 + l2 - 1 - i) - '0');         zt = appendTailZero(t, i);         sum = add(tp, zt);         free(t);         free(zt);     }     return sum; }  tp就是sum, 循环体第二次再进入时那个指针就已经free掉了， tp和sum都指向未定义的内存位置了。不可以在循环体内free. 又因为你把返回值放在那里，如果你在本函数结束前free掉tp(亦即sum），调用函数使用返回值的时候又会发生访问错误，所以应该由调用者free.