arrays - C - 递归函数丢失数组地址的轨道?
问题描述
我正在实现二进制搜索。我似乎已经解决了我的问题,但我想了解发生了什么。
这是我最初为搜索所做的:
void find_index(double *list, int val, int low, int high, int *target)
{
int mid;
if (list[low] == val)
{
target[0] = low;
return;
}
if (list[high] == val)
{
target[0] = high;
return;
}
mid = (int)((double)(low + high) / 2.0);
if (list[mid] == val || mid == low || mid == high)
{
target[0] = mid;
return;
}
if (list[low] < val && val < list[mid])
{
high = mid;
find_index(list, val, low, high, target);
}
if (list[mid] < val && val < list[high])
{
low = mid;
find_index(list, val, low, high, target);
}
return;
}
在上面的代码中,list 是一个有序的双精度数组。我主要动态分配它,
double *list = malloc((N+1)*sizeof(double));
并且val
是要搜索的值(保证在 中list
)。主叫func1
,哪个叫find_index
。这是故事:
- 最初我静态分配了一个 size1 数组,
int target[1]
并将func1
其传递给find_index
. 我遇到了分段错误。使用 valgrind 跟踪错误的根源,我发现在 中func1
,我使用了未初始化的值,并且在 中创建了未初始化的值func1
。target
是我在此类函数中分配的唯一数组,所以它必须是它。 - 我更改了
find_index
. 具体来说,我int *target
似乎int target[1]
从这个问题中了解到这是传递静态分配数组的正确方法(尽管它处理二维数组)。我再次收到分段错误和来自 valgrind 的相同消息。 - 我
target
在 mainint *target = malloc(1*sizeof(int));
中动态声明,将其传递给func1
然后传递给find_index
. 我将它传递给两个函数的方式与我最初的方式相同,即两个函数都将 a 作为参数int *target
。它奏效了,valgrind 没有抱怨。
但是我现在很怀疑,所以我决定更改 to 的类型find_index
并将其int
声明target
为find_index
本身的标量。根据我对递归的理解,它应该是安全的。
但是,我不明白步骤 1-3 中发生了什么,我想这样做,以防止将来出现错误。我唯一的猜测是,在实现的众多递归调用中find_index
,它丢失了我最初分配的数组的地址。这是可能发生的事情吗?在什么情况下?它可能与我如何将数组传递给函数和/或我最初声明的位置有关吗?
我已经搜索但找不到真正相关的问题。
编辑:最小的可重现示例表明情况更复杂
我可以构建的最小可重现示例如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <time.h>
void func1(double **list, double **another_list, int N);
void func2(double **list, double **another_list, int N);
void find_index(double *list, int val, int low, int high, int *target);
void q_sort_with_doublelst(double *ary,double *lst,int low,int high);
int q_partition_with_doublelst(double *ary,double *lst,int low,int high);
void swap_with_doublelst(double *ary,double *lst,int i,int j);
////////////////////////////////////////////////////////////////////////
// quick sort
void q_sort_with_doublelst(double *ary,double *lst,int low,int high)
{
int pivotloc;
if(low<high)
{
pivotloc=q_partition_with_doublelst(ary,lst,low,high);
q_sort_with_doublelst(ary,lst,low,pivotloc-1);
q_sort_with_doublelst(ary,lst,pivotloc+1,high);
}
}
int q_partition_with_doublelst(double *ary,double *lst,int low,int high)
{
int i,pivotloc;
int pivotkey;
swap_with_doublelst(ary,lst,low,(low+high)/2);
pivotkey=ary[low];
pivotloc=low;
for(i=low+1;i<=high;i++)
{
if(ary[i]<pivotkey) swap_with_doublelst(ary,lst,++pivotloc,i);
}
swap_with_doublelst(ary,lst,low,pivotloc);
return pivotloc;
}
void swap_with_doublelst(double *ary,double *lst,int i,int j)
{
int tmp_ary;
double tmp_lst;
tmp_ary=ary[i]; tmp_lst=lst[i];
ary[i]=ary[j]; lst[i]=lst[j];
ary[j]=tmp_ary; lst[j]=tmp_lst;
}
////////////////////////////////////////////////////////////////////////
void func2(double **list, double **another_list, int N)
{
int i, j;
double x;
for(i=0; i<=N; i++)
{
j = (int) lrand48()%(N+1);
x = lrand48();
list[0][i] = j;
list[1][i] = x;
j = (int) lrand48()%(N+1);
x = lrand48();
another_list[0][i] = j;
another_list[1][i] = x;
}
}
void func1(double **list, double **another_list, int N)
{
int i, j;
int binary_index[1];
double x, y;
for(i=0; i<=N; i++)
{
find_index(list[0], i, 0, N, binary_index);
j = binary_index[0];
x = another_list[0][j];
y = another_list[1][j];
}
return;
}
void find_index(double *list, int val, int low, int high, int *target)
{
int mid;
if (list[low] == val)
{
target[0] = low;
return;
}
if (list[high] == val)
{
target[0] = high;
return;
}
mid = (int)((double)(low + high) / 2.0);
if (list[mid] == val || mid == low || mid == high)
{
target[0] = mid;
return;
}
if (list[low] < val && val < list[mid])
{
high = mid;
find_index(list, val, low, high, target);
}
if (list[mid] < val && val < list[high])
{
low = mid;
find_index(list, val, low, high, target);
}
return;
}
int main (int argc, char **argv)
{
int i, N;
int seed=time(0);
srand48(seed);
N = 1000000;
double **list = (double **)malloc(2*sizeof(double *));
list[0] = (double *)malloc((N+1)*sizeof(double)); // contains only ints
list[1] = (double *)malloc((N+1)*sizeof(double)); // contains double
double **another_list = (double **)malloc(2*sizeof(double *));
another_list[0] = (double *)malloc((N+1)*sizeof(double)); // contains only ints
another_list[1] = (double *)malloc((N+1)*sizeof(double)); // contains double
for(i=0; i<=N; i++) list[0][i] = i;
while(1 < 2)
{
func2(list, another_list, N);
q_sort_with_doublelst(list[0], list[1], 0, N);
func1(list, another_list, N);
}
free(list[0]);
free(list[1]);
free(list);
free(another_list[0]);
free(another_list[1]);
free(another_list);
return 0;
}
我试图通过list[0]
在主程序(第 173 行)中确定性地填充 for 循环来重现错误,以便对其进行排序。事实证明它不会崩溃。我发布的代码与我的真实代码更相似,但现在我担心(正如评论所暗示的那样)我遇到了递归问题。最小示例所做的摘要(与我的代码非常相似):
list[0]
在 [0, N] 中填充随机整数。用随机双精度填充列表1 。- 以同样的方式填写
another_list
。 list[0]
通过保留与 的关系进行排序list[1]
。- 二进制搜索
list[0]
并使用找到的索引从list[1]
和中获取值another_list
。
此示例与我的真实代码之间存在差异:此处list[0]
不保证包含我正在搜索的值。此外,此处list[0]
可能包含重复项。原则上,搜索是根据搜索的值不需要存在以及没有重复的想法编写的。因此,我会说如果该值不存在,搜索应该给我找到的最接近的值,但我不知道如果有重复会发生什么。我想它应该给我一个可能重复的索引,但我绝对不确定。在我的原始代码中没有重复。
我担心目前的代码会因为存在重复而崩溃。不过,如果有人能找出不同的问题,那就太好了。让我强调一下 valgrind 给了我同样的确切信息:错误应该是target
,因为它是唯一分配在func1
.
解决方案
推荐阅读
- amazon-web-services - 如何为我的 EKS 服务分配静态 IP?
- r - 如何让 R 将 diff(x) 格式化为行?
- service-worker - 如何调试/记录生产服务工作者安装的错误
- php - 来自 URL 的 file_get_contents 仅适用于本地服务器
- python - Python 中的 Perl pack('H*', $value)
- python - XYZ/RGB 中的颜色校正矩阵不起作用
- prestashop-1.7 - Prestashop 邮件确认布局
- javascript - Javascript 相当于 excel 中的 FLOOR,值为 0.5
- c++ - C++ & Esp8266 LoadStoreAlignmentCause 与指针
- azure - Ontotext GraphDb 多租户和云托管查询