如何解决在mergesort中写外部堆
我一直在C中实现合并排序的原始版本。在排序部分本身(这是一个单独的函数)中,我通过malloc
创建了一个临时数组,如下所示:
int *tmp_arr = malloc(sizeof *tmp_arr * (end - strt));
由于某种原因,我在整个临时数组中都进行了无效的读取和写入,同时尝试在比较后用元素填充它。 int tmp_arr[end - strt];
正常。
为什么我要在堆之外写东西(如果我目前的理解不正确,会发生什么情况?)
以下是使用malloc
的函数,从valgrind输出中提取的信息以及执行时遇到的确切错误。我没有忘记free
的东西。
我想对原始数组进行硬编码,因为我想写东西,然后再打扰输入。
这个特定的数组{ 8,1,10,54,2,-3,5,70,60,11,4 }
具有我可以运行我的程序的最大长度(如果更长)-程序崩溃,并出现了帖子结尾处描述的错误。 Valgrind的输出原则上总是相同的,数组越长,我得到的读写错误就越多。
程序:
#include <stdio.h>
#include <stdlib.h>
void merge_sort(int *arr,int strt,int end);
void merge(int *arr,int mid,int end);
void print_arr(int *arr,int arr_len);
int main(void) {
int arr[] = { 8,4 };
int arr_len = sizeof(arr) / sizeof(arr[0]);
print_arr(arr,arr_len);
merge_sort(arr,arr_len - 1);
print_arr(arr,arr_len);
}
void print_arr(int *arr,int arr_len) {
for (int i = 0; i < arr_len; i++) {
printf("%i ",arr[i]);
}
printf("\n");
}
void merge_sort(int *arr,int end) {
if (strt < end) {
int mid = (end + strt) / 2;
merge_sort(arr,strt,mid);
merge_sort(arr,mid + 1,end);
merge(arr,mid,end);
}
}
void merge(int *arr,int end) {
int *tmp_arr = malloc(sizeof *tmp_arr * (end - strt));
//int tmp_arr[end - strt];
int i = strt;
int j = 0;
int k = mid + 1;
while ((i <= mid) && (k <= end)) {
if (arr[i] < arr[k]) {
tmp_arr[j] = arr[i];
i++;
j++;
}
else {
tmp_arr[j] = arr[k];
k++;
j++;
}
}
while(i <= mid) {
tmp_arr[j] = arr[i];
j++;
i++;
}
while (k <= end) {
tmp_arr[j] = arr[k];
j++;
k++;
}
for (int m = 0; m < j; m++) {
arr[strt + m] = tmp_arr[m];
}
free(tmp_arr);
}
从valgrind输出中提取上面带有硬编码的数组:
valgrind ./main==355== Memcheck,a memory error detector
==355== Copyright (C) 2002-2017,and GNU GPL'd,by Julian Seward et al.==355== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright inf
o
==355== Command: ./main==355==
8 1 10 54 2 0 -3 5 70 60 11 4 ==355== Invalid write of size 4
==355== at 0x108A40: merge (in /home/runner/MiniatureEarnestSecurity/main)
==355== by 0x108917: merge_sort (in /home/runner/MiniatureEarnestSecurity/main)
==355== by 0x1088EB: merge_sort (in /home/runner/MiniatureEarnestSecurity/main)
==355== by 0x1088EB: merge_sort (in /home/runner/MiniatureEarnestSecurity/main)
==355== by 0x1088EB: merge_sort (in /home/runner/MiniatureEarnestSecurity/main)
==355== by 0x108823: main (in /home/runner/MiniatureEarnestSecurity/ma
in)
==355== Address 0x522d484 is 0 bytes after a block of size 4 alloc'd==355== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-
amd64-linux.so)==355== by 0x108943: merge (in /home/runner/MiniatureEarnestSecurity/m
ain)
==355== by 0x108917: merge_sort (in /home/runner/MiniatureEarnestSecur
ity/main)
==355== by 0x1088EB: merge_sort (in /home/runner/MiniatureEarnestSecur
ity/main)
==355== by 0x1088EB: merge_sort (in /home/runner/MiniatureEarnestSecur
ity/main)
==355== by 0x1088EB: merge_sort (in /home/runner/MiniatureEarnestSecur
ity/main)
==355== by 0x108823: main (in /home/runner/MiniatureEarnestSecurity/ma
in)
==355==
==355== Invalid read of size 4
==355== at 0x108AC8: merge (in /home/runner/MiniatureEarnestSecurity/m
ain)
==355== by 0x108917: merge_sort (in /home/runner/MiniatureEarnestSecur
ity/main)
==355== by 0x1088EB: merge_sort (in /home/runner/MiniatureEarnestSecurity/main)
==355== by 0x1088EB: merge_sort (in /home/runner/MiniatureEarnestSecurity/main)
==355== by 0x1088EB: merge_sort (in /home/runner/MiniatureEarnestSecurity/main)
==355== by 0x108823: main (in /home/runner/MiniatureEarnestSecurity/main)
==355== Address 0x522d484 is 0 bytes after a block of size 4 alloc'd
==355== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==355== by 0x108943: merge (in /home/runner/MiniatureEarnestSecurity/main)
==355== by 0x108917: merge_sort (in /home/runner/MiniatureEarnestSecurity/main)
==355== by 0x1088EB: merge_sort (in /home/runner/MiniatureEarnestSecurity/main)
==355== by 0x1088EB: merge_sort (in /home/runner/MiniatureEarnestSecurity/main)
==355== by 0x1088EB: merge_sort (in /home/runner/MiniatureEarnestSecurity/main)
==355== by 0x108823: main (in /home/runner/MiniatureEarnestSecurity/main)
==355==
//repeating till the end
-3 0 1 2 4 5 8 10 11 54 60 70
==355==
==355== HEAP SUMMARY:
==355== in use at exit: 0 bytes in 0 blocks
==355== total heap usage: 12 allocs,12 frees,156 bytes allocated
==355==
==355== All heap blocks were freed -- no leaks are possible
==355==
==355== For counts of detected and suppressed errors,rerun with: -v
==355== ERROR SUMMARY: 22 errors from 16 contexts (suppressed: 0 from 0)
我在执行时犯了错误:
main:malloc.c:2401:sysmalloc:断言`(old_top == initial_top (av)&& old_size == 0)|| ((无符号长)(old_size)> = MINSIZE && prev_inus e(old_top)&&((无符号长)old_end&(页面大小-1))== 0)'失败。退出,中止
解决方法
问题在于要排序的切片的长度不是end - strt
而是end - strt + 1
,因为您使用的是容易出错的约定来包含end元素。
分配应为int *tmp_arr = malloc(sizeof *tmp_arr * (end - strt + 1));
代码似乎可以与自动存储在本地声明的数组一起工作的原因纯属偶然。在将数据存储到tmp_arr[end - strt]
时,您仍然有未定义的行为,但是恰好它似乎没有任何不利的副作用,而当您对分配的对象这样做时,您可能会破坏{ {1}}跟踪分配的块,该块由分配例程或valgrind执行的一致性检查检测到。
在切片中包含最后一个元素的索引非常容易出错。我希望这种废话不会在任何基于0的数组索引的语言的编程类中教授。它需要在代码中进行许多令人困惑的malloc()
/ +1
调整,而在最后一个元素之后使用元素的索引可以简化代码。
这是修改后的版本:
-1
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。