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;