C自定义二进制搜索不遵循元素大小的倍数规则,并且崩溃
对于前两个元素,它工作得非常好,但第三个元素会出现问题 我使用的是C自定义二进制搜索不遵循元素大小的倍数规则,并且崩溃,c,crash,binary-search,string-comparison,C,Crash,Binary Search,String Comparison,对于前两个元素,它工作得非常好,但第三个元素会出现问题 我使用的是char**,其中每个元素都是指向完整字符串的指针。 比方说 元素1指针=12273436 元素2指针=12273440 尝试使用下面的BinarySearch插入元素3时。 mid变为12273438,这看起来很好,但正如您可以看到的那样,指针遵循每个元素的4字节规则。因此,当程序尝试执行CompareFunc时,将其缩短为2个字节会导致程序崩溃 这是一个模拟。 LowerBound=12273436 上限=12273440
char**
,其中每个元素都是指向完整字符串的指针。
比方说
元素1指针=
12273436
元素2指针=
12273440
尝试使用下面的BinarySearch
插入元素3时。
mid
变为12273438
,这看起来很好,但正如您可以看到的那样,指针遵循每个元素的4字节
规则。因此,当程序尝试执行CompareFunc
时,将其缩短为2个字节会导致程序崩溃
这是一个模拟。
LowerBound=12273436
上限=12273440
ElementSize=4
mid=12273436+4*(12273440-12273436)/4/2
mid=12273438
现在
下面是一个运行的自包含代码。
这是源代码
int __cdecl BinarySearch(int ElementToFind, int Array, unsigned int TotalElements, unsigned int ElementSize, int (__cdecl *CompareFunc)(int, int), bool *IsFoundPointer)
{
int mid; // esi@1
int result; // eax@1
int LowerBound; // ebp@2
int UpperBound; // edi@2
mid = 0;
result = 0;
*IsFoundPointer = false;
if ( !TotalElements )
return result; //NULL
LowerBound = Array;
UpperBound = Array + ElementSize * (TotalElements - 1);
while ( 1 )
{
mid = LowerBound + ElementSize * (UpperBound - LowerBound) / ElementSize / 2;
result = CompareFunc(ElementToFind, mid);
if ( result < 0 )
{
if ( mid == Array )
return mid;
UpperBound = mid - ElementSize;
if ( LowerBound > UpperBound )
return mid;
}
if ( result <= 0 )
break;
LowerBound = mid + ElementSize;
if ( LowerBound > UpperBound ) {
if ( result > 0 )
mid += ElementSize;
return mid;
}
}
*IsFoundPointer = true;
if ( mid == Array ) {
return Array;
} else {
while ( 1 )
{
mid -= ElementSize;
if ( CompareFunc(ElementToFind, mid) ) //ElementToFind != mid element.
break;
if ( mid == Array )
return Array;
}
return mid + ElementSize;
}
return result;
}
int __cdecl StringCompare(int ElementString, int ArrayPointer)
{
printf("Element = %s Array = %s\n", (const char *)ElementString, *(const char **)ArrayPointer);
return stricmp((const char *)ElementString, *(const char **)ArrayPointer);
}
int\u cdecl二进制搜索(int-ElementToFind,int-Array,unsigned int-TotalElements,unsigned int-ElementSize,int(\u-cdecl*CompareFunc)(int,int),bool*IsFoundPointer)
{
int mid;//esi@1
int结果;//eax@1
int LowerBound;//ebp@2
int上限;//edi@2
mid=0;
结果=0;
*IsFoundPointer=false;
如果(!TotalElements)
返回结果;//NULL
LowerBound=数组;
上限=数组+元素大小*(TotalElements-1);
而(1)
{
mid=下界+元素大小*(上界-下界)/元素大小/2;
结果=比较函数(ElementToFind,mid);
如果(结果<0)
{
if(mid==数组)
中途返回;
上限=中间元素大小;
如果(下限>上限)
中途返回;
}
如果(结果上限){
如果(结果>0)
mid+=元素大小;
中途返回;
}
}
*IsFoundPointer=true;
if(mid==数组){
返回数组;
}否则{
而(1)
{
中等=元素大小;
if(CompareFunc(ElementToFind,mid))//ElementToFind!=mid元素。
打破
if(mid==数组)
返回数组;
}
返回mid+ElementSize;
}
返回结果;
}
int\uu cdecl StringCompare(int-ElementString,int-ArrayPointer)
{
printf(“元素=%s数组=%s\n”,(常量字符*)元素字符串,*(常量字符**)数组指针);
返回stricmp((常量字符*)元素字符串,*(常量字符**)数组指针);
}
您似乎试图将指针作为整数传递(请参见如何将ArrayPointer
声明为int
,但您将其强制转换为char**
。然后使用二进制搜索操作整数。这就是为什么会得到异常结果的原因
相反,您希望:
- 将3个参数传递给
StringCompare
:数组的地址(可以视为从BinarySearch
传递的不透明指针,以及该数组中的两个整数偏移量;或
- 将两个参数传递给
StringCompare
,每个参数都是void*
指针,BinarySearch
可以使用ElementSize
计算,指向数组的指针和偏移量
在我看来,第一个是最干净的,根本不需要您将ElementSize
传递到BinarySearch
或(依次)传递到StringCompare
,因为在每种情况下,它都可以解决这些问题
例如:
int StringCompare (int element1, int element2, void *opaque)
{
char *s1 = ((char **)opaque)[element1];
char *s2 = ((char **)opaque)[element1];
return stricmp(s1, s2);
}
修复二进制搜索是留给您的一个练习,但它根本不需要任何指针算法
编辑:
虽然指针作为整数传递(除其他外,如果您真的想这样做,请参阅int\ptr\t
)使我对代码产生了深深的怀疑,但我怀疑问题在于这一行:
mid = LowerBound + ElementSize * (UpperBound - LowerBound) / ElementSize / 2;
编译器是从左到右计算的,所以在除以它之前乘以ElementSize
尝试:
这就是BinarySearch从另一个应用程序反编译的东西,它应该按原样工作。在我看来,它应该通过指针以及在其他领域重复使用的元素来工作。为什么它会有ElementSize?这不是严格的指针大小吗?我不知道,但这一行mid=LowerBound+ElementSize*(上界-下界)/ElementSize/2;
存在严重缺陷,因为它允许mid
在(上界-下界)时指向项目的中间
是ElementSize
的一个奇怪倍数。如果你不能更改该代码,你就会被卡住。这就是我试图更改的。我发现了问题,它没有4的倍数,我不明白它以前是如何工作的。你曾经使用过IDA PRO吗?
想看看原始结果吗?这里是:@SSp请看我上面的编辑-我怀疑这就是问题的原因。但是,恕我直言,我认为这是一段非常糟糕的代码。
int midoffset = (UpperBound - LowerBound) / ElementSize / 2;
mid = LowerBound + ElementSize * midoffset;