c - malloc() 和 realloc() 函数的奇怪行为导致分段错误
问题描述
我有一个名为 的函数num_to_binary
,用于转换以数组形式存储的十进制数。该函数的原型num_to_binary
如下:
void num_to_binary(int *number_b, int size_of_number);
这里:
number_b
是指向存储我的号码的数组的指针。例如,如果我想将数字 12345 转换为二进制,那么我将存储 12345,number_b
如下所示:
number_b[0] = 1
number_b[1] = 2
number_b[2] = 3
number_b[3] = 4
number_b[4] = 5
此外,size_of_number
是数字中的位数(或者它是数组中的元素数number_b
)。因此对于数字 12345,size_of_number
其值为 5。
下面是函数的完整声明num_to_binary
:
void num_to_binary(int *number_b, int size_of_number)
{
int *tmp_pointer = malloc(1 * sizeof(int));
int curr_size = 1;
int i = 0;
while(!is_zero(number_b,size_of_number))
{
if(i != 0)
{
curr_size += 1;
tmp_pointer = realloc(tmp_pointer, curr_size * sizeof(int));
}
if(number_b[size_of_number - 1] % 2 == 1)
{
tmp_pointer[i] = 1;
divide_by_2(number_b,size_of_number);
i = i + 1;
}
else
{
tmp_pointer[i] = 0;
divide_by_2(number_b,size_of_number);
i = i + 1;
}
}
int *fin_ans;
fin_ans = malloc(curr_size * sizeof(int));
for(int j = 0 ; j < curr_size; j++)
{
fin_ans[curr_size-1-j] = tmp_pointer[j];
}
}
在上述函数中:
tmp_pointer
:它最初malloc()
是使用 分配一些内存,用于存储存储在number_b
curr_size
:它存储当前的大小tmp_pointer
。它最初设置为 1。
i
:用于跟踪while
循环。它也用于重新分配目的,我稍后会解释。
is_zero(number_b, size_of_number)
:它是一个函数,1
如果存储的数字number_b
为0,则返回,否则返回1。
divide_by_2(number_b, size_of_number)
:它将存储的数字number_b
除以 2。它不会改变数组的大小number_b
。
fin_ans
: 它是一个整数指针。由于存储在数组tmp_pointer
中的二进制表示将与数字的实际二进制表示相反,因此fin_ans
将通过反转 的内容来存储数字的正确二进制表示tmp_pointer
。
以下是此功能的工作原理:
- 首先,
tmp_pointer
分配的内存等于 1 int 的大小。所以,现在tmp_pointer
可以存储一个整数。 - 我们现在进入
while
循环。仅当存储的数字number_b
等于 0 时,循环才会终止。 - 现在,我们检查是否
i
等于 0。如果它不等于 0,那么这意味着循环至少运行了一次,为了存储下一个二进制数字,我们调整分配的内存大小,tmp_pointer
以便它可以存储下一位。 - 如果数字的最后一位是奇数,则意味着相应的二进制数字将为 1,否则将为 0。and
if
条件else
执行此任务。i
每次执行其中一个时,它们也会递增 ,并将数字除以 2。 - 现在,我们脱离了循环。是时候反转存储的二进制数
tmp_pointer
以获得最终答案了。 - 为此,我们创建一个名为 的新指针
fin_ans
,并为其分配内存,用于存储数字的正确二进制表示。 - 最后一个
for
循环用于反转二进制表示并将正确的二进制表示存储在fin_ans
.
问题:
该代码对 123 等小数运行,但对于 1234567891 等大数,它会给出分段错误错误。这可以通过尝试打印存储在fin_ans
.
我尝试使用 GDB Debugger,并了解到 Segmentation Fault 的原因在于while
循环。我确信这些功能并不是分段错误的原因,因为我已经对它们进行了彻底的测试divide_by_2
。is_zero
我还使用了 DrMemory,这表明我正在尝试访问(读取或写入)尚未分配的内存位置。不幸的是,我无法弄清楚错误在哪里。
我怀疑realloc()
是分段错误的原因,但我不确定。
但是,对于这么长的问题,我深表歉意,我将非常感谢为我提供此代码的任何帮助。
提前感谢您帮助我!
解决方案
代码中存在多个问题:
- 你不检查内存分配失败
tmp_pointer
您在离开该功能之前忘记释放。- 您分配一个新数组
fin_ans
来保留该数组tmp_pointer
并执行相反的操作,但是您没有将此数组返回给调用者,也没有办法返回其大小。您应该更改原型以返回此信息。 - 如果数字为零,则转换后的数字可能应该有 1 位初始化为 0,但您使用
malloc
的不会初始化它分配的数组,因此tmp_pointer[0]
未初始化。 - 您没有提供
is_zero()
nor的代码divide_by_two()
。这些函数中的错误可能会导致分段错误,特别是如果循环未达到零并且内存最终在此无限循环期间耗尽。
这是修改后的版本:
int *num_to_binary(int *number_b, int size_of_number, int *binary_size) {
int i, j, curr_size;
int *p, *newp;
curr_size = 1;
p = malloc(1 * sizeof(int));
if (p == NULL)
return NULL;
p[0] = 0;
for (i = 0; !is_zero(number_b, size_of_number); i++) {
if (i != 0) {
curr_size += 1;
newp = realloc(p, curr_size * sizeof(int));
if (newp == NULL) {
free(p);
return NULL;
}
p = newp;
}
p[i] = number_b[size_of_number - 1] % 2;
divide_by_2(number_b, size_of_number);
}
for (i = 0, j = curr_size; i < j; i++)
int digit = p[--j];
p[j] = p[i];
p[i] = digit;
}
*binary_size = curr_size;
return p;
}
推荐阅读
- r - 通过 RVest 抓取数据
- python - 批量重命名df中的列
- mysql - 如何在mysql表中搜索json数组字段中的字段?
- azure-logic-apps - 逻辑应用 - CurrentTime - 如何仅选择时间 (hh:mm:ss)
- docker - 网络主机中的 Docker 绑定端口
- javascript - date-fns formatRelative RangeError: Invalid time value when using basic new Date() js function
- php - 在一定时间后注销用户
- php - 未定义属性:App\Http\Controllers\UserController::$user
- git - 从 VSCode 中清理已删除的文件
- php - 随机问候生成器