【问题标题】:Odd point issue by null pointer空指针的奇点问题
【发布时间】:2017-02-07 07:37:46
【问题描述】:

我正在使用 C 语言进行代码练习。

如下代码,

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define _CRT_SECURE_NO_WARNINGS

int ACDSort(const void *p1, const void *p2);
int Compare(const void *pKey, const void *pValue);
int main(void)
{
    char * strAry[4] = {"Hardware","Cookie","Boy","Power"};
    char * destStr = "Cookie";

    //qsort((void*)strAry, sizeof(strAry) / sizeof(char*), sizeof(char*), ACDSort);

    char **ptrAdr = (char**)bsearch((void*)destStr, strAry, sizeof(strAry) / sizeof(char*), sizeof(char*), Compare);

    printf("%s\n", *ptrAdr);
}

int Compare(const void *pKey, const void *pValue) {
    char *key = ((char*)pKey);
    char *value = *((char**)pValue);
    return strcmp(key, value);
}

int ACDSort(const void *p1, const void *p2) {

    char * n1 = *((char**)p1);
    char * n2 = *((char**)p2);
    int ret;

    if (strlen(n1) > strlen(n2))
        ret = 1;
    else if (strlen(n1) < strlen(n2))
        ret = -1;
    else
        ret = 0;
    return ret;
}

我打电话给bsearch 来查找cookie 的字符串。 问题是当我删除 // 以便根据字符串长度对数组进行排序时发生错误。 我不知道为什么会执行错误,因为我认为 qsort 无法对我的代码产生重大影响。

你能告诉我擦除//时返回空指针错误的原因吗?

附言。我用qsortbsearch来熟悉指针变量。

【问题讨论】:

  • bsearch 仅在数组已排序时有效
  • 请注意,您通常应该对qsort()bsearch() 使用相同的比较函数。如果你必须使用不同的功能,那你就做错了。
  • 为什么qsort()bsearch() 使用不同的函数?
  • @JonathanLeffler 在这种情况下不是。查看答案。

标签: c bsearch


【解决方案1】:

bsearch 使用二进制搜索,这就是原因。二进制搜索需要对数据进行排序。按字母顺序对字符串数组进行排序,它将起作用。

作为旁注,您需要摆脱所有那些多余的演员表,他们所做的只是隐藏潜在的错误。

修复和清理后的工作程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int compare (const void* p1, const void* p2);

int main (void)
{
    const char* strAry[4] = {"Boy", "Cookie", "Hardware", "Power"};
    const char* key = "Cookie";

    char** ptrAdr = bsearch(key, 
                            strAry, 
                            sizeof(strAry)/sizeof(*strAry), 
                            sizeof(*strAry), 
                            compare);

    printf("%s\n", *ptrAdr);
}

int compare (const void* p1, const void* p2) 
{
  const char* s1 = p1;
  const char* s2 = *(const char* const*)p2;

  return strcmp(s1, s2);
}

p2 最终会得到一个指向 const char*const void 指针,这就是为什么我们在争取 const 正确性时会得到看起来很奇怪的演员表。

【讨论】:

    【解决方案2】:

    destStr 的类型可以更改为与strAry 的类型相同,例如:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int Compare(const void *pKey, const void *pValue)
    {
        char *key = *((char**)pKey);
        char *value = *((char**)pValue);
        return strcmp(key, value);
    }
    
    int main(void)
    {
        char * strAry[4] = { "Hardware", "Cookie", "Boy", "Power" };
        char * destStr[1] = { "Cookie" }; // Type changing
    
        qsort(strAry, sizeof(strAry) / sizeof(char*), sizeof(char*), Compare);
    
        char **ptrAdr = (char**)bsearch((void*)destStr, strAry, sizeof(strAry) / sizeof(char*), sizeof(char*), Compare);
    
        printf("%s\n", *ptrAdr);
    }
    

    另外,如果您使用 C 语言(和编译器),请考虑直接使用 strcmp 作为比较两个元素的回调函数。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    /*int Compare(const void *pKey, const void *pValue)
    {
        char *key = *((char**)pKey);
        char *value = *((char**)pValue);
        return strcmp(key, value);
    }*/
    
    int main(void)
    {
        char * strAry[4] = { "Hardware", "Cookie", "Boy", "Power" };
        char * destStr[1] = { "Cookie" }; // Type changing
    
        //qsort(strAry, sizeof(strAry) / sizeof(char*), sizeof(char*), Compare);
        qsort(strAry, sizeof(strAry) / sizeof(char*), sizeof(char*), strcmp);
    
        //char **ptrAdr = (char**)bsearch((void*)destStr, strAry, sizeof(strAry) / sizeof(char*), sizeof(char*), Compare);
        char **ptrAdr = (char**)bsearch(destStr, strAry, sizeof(strAry) / sizeof(char*), sizeof(char*), strcmp);
    
        printf("%s\n", *ptrAdr);
    }
    

    注意:

    此解决方案有一个缺点,表现为 ...

    警告:从不兼容的指针类型传递“bsearch”的参数 5 [默认启用]

    但它有效(我已尝试使用 GCC 版本 4.8.2 和 MS Visual Studio 12.0)

    【讨论】:

    • 它可能在测试时工作,但它仍然是非法的,因为编译器试图告诉你。当简单的包装器修复它时,无需引入可能的问题。由于 C 中的未定义行为,您永远不能仅使用测试来确定某事是否正常。
    • 是的,这就像一个把戏......所以,我留下了可以使用的注释代码。
    • int (*)(const char*)(const char*)int (*)(const void*)(const void*) 的指针转换会调用未定义的行为。如果两者之间碰巧没有调用约定差异,如果void*char* 具有相同的表示并且如果代码中没有指针别名优化,它会“工作”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-17
    • 2011-03-09
    • 2018-11-19
    • 1970-01-01
    • 2015-09-27
    • 1970-01-01
    • 2016-03-27
    相关资源
    最近更新 更多