我最近开始学习 C 编程(我在 Python 方面有一些中级水平的经验(?))。我在 LeetCode 上看到了这个名为“两个排序数组的中位数”的问题,我想我可以尝试使用 C 实现该代码。该代码由三个函数组成,因为问题在于整个代码,特别是内存管理(?如果还有其他人请帮忙),我将发布整个内容。
int* insert(int* arr, int n, int x)
{
int *ret = (int *) calloc(n+1,sizeof(int)), cont = 0;
for(int i = 0; i<n && *(arr+i) < x; i++)
{
*(ret + i) = *(arr + i);
cont++;
}
*(ret+cont) = x;
for(int i = cont; i < n; i++)
{
*(ret+i+1) = *(arr + i);
}
return ret;
}
int* merge(int* arr1, int len1, int* arr2, int len2)
{
int *ret = (int *) calloc(len1 + len2, sizeof(int)), **temp = (int **) malloc((len2+1)*sizeof(int *));
for(int i = 0; i < len1; i++)
{
*(ret+i) = *(arr1+i);
}
*temp = ret;
for(int i = 0; i < len2; i++)
{
*(temp+i+1) = insert(*(temp+i),len1+i, *(arr2+i));
}
for(int i = 0; i < len1+len2; i++)
{
*(ret + i) = *(*(temp+len2-1)+ i);
}
for(int i = 0; i < len2; i++)
{
free(*(temp+i));
}
free(temp);
return ret;
}
double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size)
{
int *arr = merge(nums1, nums1Size, nums2, nums2Size), len = nums1Size+ nums2Size;
double mid;
if(len % 2 == 1)
{
mid = *(arr + len/2);
}
else
{
mid = (*(arr+len/2)+*(arr+len/2+1))/2.0;
}
free(arr);
return mid;
}
合并和插入算法我相信插入排序的实现(?),我知道代码可以提高很多效率。但我的问题出在其他地方(?),LeetCode 上弹出以下错误消息:
=================================================================
==22==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000054 at pc 0x56200c01d257 bp 0x7fffc24d3340 sp 0x7fffc24d3330
READ of size 4 at 0x602000000054 thread T0
#2 0x7f623c602082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082)
0x602000000054 is located 4 bytes inside of 12-byte region [0x602000000050,0x60200000005c)
freed by thread T0 here:
#0 0x7f623d010537 in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:127
#4 0x7f623c602082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082)
previously allocated by thread T0 here:
#0 0x7f623d010a57 in __interceptor_calloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:154
#4 0x7f623c602082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082)
Shadow bytes around the buggy address:
0x0c047fff7fb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c047fff8000: fa fa 00 fa fa fa 04 fa fa fa[fd]fd fa fa fd fd
0x0c047fff8010: fa fa 00 04 fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==22==ABORTING
我认为这表明内存泄漏,尽管我根本不熟悉所以不能肯定地说。请查看代码和错误并建议如何克服这个问题。
我已经多次尝试纠正我认为的问题(例如最初只是
*temp
而不是**temp = (int **) malloc((len2+1)*sizeof(int *))
,这是不可能解除分配的。但是问题仍然存在,我不知道该怎么办或搜索。任何帮助将不胜感激。谢谢!
*(ret + i) = *(*(temp + len2 - 1) + i);
中的 merge
函数访问数组越界`。它的作用与:
*( temp[len2 - 1] + i )
也就是说,它从
temp
数组中位置 len2 - 1
处获取值,并将其用作添加 i
的地址,然后取消引用。这具有未定义的行为,您的程序可能会崩溃,甚至更糟。
建议修复直接进行合并,而不必调用
insert
:
int* merge(int arr1[], int len1, int arr2[], int len2) {
int * const ret = malloc((len1 + len2) * sizeof(int));
int *wr = ret;
// merge the two arrays while they both have values
for(;len1 && len2; ++wr) {
if(*arr1 < *arr2) {
*wr = *arr1++;
--len1;
} else {
*wr = *arr2++;
--len2;
}
}
// here either len1 or len2 or both are zero
// fill with any residue from arr1
for(;len1; --len1) *wr++ = *arr1++;
// fill with any residue from arr2
for(;len2; --len2) *wr++ = *arr2++;
return ret;
}
我还想总体上推广
pointer[index]
而不是*(pointer + index)
。示例:
double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size) {
int *arr = merge(nums1, nums1Size, nums2, nums2Size),
len = nums1Size + nums2Size;
double mid;
if (len % 2 == 1) {
mid = arr[len / 2];
} else {
mid = (arr[len / 2] + arr[len / 2 + 1]) / 2.0;
}
free(arr);
return mid;
}