【发布时间】:2017-03-05 23:51:58
【问题描述】:
免责声明,这是对学校作业的帮助。话虽这么说,我的问题只发生在大约 50% 的时间里。这意味着如果我编译并运行我的代码而不进行编辑,有时它会一直运行到最后,有时它不会。通过使用多个打印语句,我确切地知道问题发生在哪里。问题出现在我对 hugeDestroyer 的第二次调用中(就在打印 354913546879519843519843548943513179 部分之后),更确切地说是在免费(p->digits)部分。
我已经尝试了此处的建议 (free a pointer to dynamic array in c),并在没有运气的情况下将指针设置为 NULL。
通过一些挖掘和灵魂搜索,我从 (How do malloc() and free() work?) 了解了更多关于免费工作原理的信息,我想知道我的问题是否源于用户 Juergen 在他的回答中提到的内容以及我正在“覆盖”管理数据免费列表。
要清楚,我的问题有两个。
free(p->digits) 在语法上是否正确,如果正确,为什么我在运行代码时会遇到一半的问题?
其次,如何在我的函数中防范这种行为?
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
typedef struct HugeInteger
{
// a dynamically allocated array to hold the digits of a huge integer
int *digits;
// the number of digits in the huge integer (approx. equal to array length)
int length;
} HugeInteger;
// Functional Prototypes
int str2int(char str) //converts single digit numbers contained in strings to their int value
{
return str - 48;
}
HugeInteger *parseInt(unsigned int n)
{
int i = 0, j = 0;
int *a = (int *)calloc(10, sizeof(int));
HugeInteger *p = (HugeInteger *)calloc(1, sizeof(HugeInteger));
if(n == 0)
{
p->digits = (int *)calloc(1, sizeof(int));
p->length = 1;
return p;
}
while(n != 0)
{
a[i] = n % 10;
n = n / 10;
i++;
}
p->length = i;
p->digits = (int *)calloc(p->length, sizeof(int));
for(i = 0; i <= p->length; i++, j++)
p->digits[j] = a[i];
return p;
}
HugeInteger *parseString(char *str) //notice datatype is char (as in char array), so a simple for loop should convert to huge int array
{
int i = 0, j = 0;
HugeInteger *p = (HugeInteger *)calloc(1, sizeof(HugeInteger));
if(str == NULL)
{
free(p);
p = NULL;
return p;
}
else
{
for(i=0; str[i] != '\0'; i++)
;
p->length = i;
p->digits = (int *)calloc(p->length, sizeof(int));
for(; i >= 0; i--)
p->digits[j++] = str2int(str[i - 1]);
}
return p;
} //end of HugeInteger *parseString(char *str)
HugeInteger *hugeDestroyer(HugeInteger *p)
{
//printf("No problem as we enter the function\n");
if(p == NULL)
return p;
//printf("No problem after checking for p = NULL\n");
if(p->digits == NULL)
{
free(p);
p = NULL;
return p;
}
//printf("No Problem after checking if p->digits = NULL\n");
//else
//{
free(p->digits);
printf("We made it through free(p->digits)\n");
p->digits = NULL;
printf("We made it through p->digits = NULL\n");
free(p);
printf("We made it through free(p)\n");
p = NULL;
printf("We made it through p = NULL\n");
return p;
//}
//return NULL;
}//end of HugeInteger *hugeDestroyer(HugeInteger *p)
// print a HugeInteger (followed by a newline character)
void hugePrint(HugeInteger *p)
{
int i;
if (p == NULL || p->digits == NULL)
{
printf("(null pointer)\n");
return;
}
for (i = p->length - 1; i >= 0; i--)
printf("%d", p->digits[i]);
printf("\n");
}
int main(void)
{
HugeInteger *p;
hugePrint(p = parseString("12345"));
hugeDestroyer(p);
hugePrint(p = parseString("354913546879519843519843548943513179"));
hugeDestroyer(p);
hugePrint(p = parseString(NULL));
hugeDestroyer(p);
hugePrint(p = parseInt(246810));
hugeDestroyer(p);
hugePrint(p = parseInt(0));
hugeDestroyer(p);
hugePrint(p = parseInt(INT_MAX));
hugeDestroyer(p);
//hugePrint(p = parseInt(UINT_MAX));
//hugeDestroyer(p);
return 0;
}
【问题讨论】:
-
你试过使用调试器吗?
-
for(; i >= 0; i--)循环比您分配的空间多写一位(例如,如果p->digits == 1则您为 1 个 int 分配空间,但此循环运行两次,i == 1然后i == 0第二次迭代写入p->digits[1],超出范围) -
我已经使用了带有 codeBlocks 的调试器并产生了一些效果,这就是导致我进入 free(p->digits) 部分的原因,但它只是有一个内存地址作为指向该行的注释并且是除了向我展示这一点之外,并没有什么帮助。我确实将您指出的 sn-p 更改为 for(; i - 1>= 0; i--) 现在让我在段错误之前降到 INT_MAX 部分,所以这绝对是进步。似乎我的问题可能与免费无关,但超出了界限。
-
你只需要释放p,如果你已经完成p那么就不需要释放p->digits
-
如果你在linux上你可以使用valgrind来调试这类问题