【问题标题】:convert pointer to pointer to void pointer将指针转换为空指针
【发布时间】:2012-10-24 21:35:24
【问题描述】:

当我学习使用 qsort 对字符串数组进行排序时,有一个问题让我很困惑。 比如对下面的s进行排序

 char *s[] = {
                   "Amit",
                   "Garima",
                   "Gaurav",
                   "Vaibhav"
                };

要使用 qsort,您必须提供一个比较函数,例如 以下函数cstring_cmp 我猜在qsort 函数中,要传递给函数cstring_cmp 的参数类型是char**。如何将char** 转换为void*?为什么我们可以将char** 转换为void*

    int cstring_cmp(const void *a, const void *b)
    {
        const char **ia = (const char **)a;
        const char **ib = (const char **)b;
        return -strcasecmp(*ia, *ib);
        /* return the negative of the normal comparison */
    }

【问题讨论】:

  • qsort() 在这个例子中传递每个被检查的 char * 的 address。它们是指向指针的指针。这正是它应该的样子(在这个例子中也是如此)。 Greg 你没有错(除非我们都错了,但从 OPs 代码来看,我们没有错)。

标签: c void-pointers


【解决方案1】:

您的问题似乎有点含糊,但我还是会试一试。要回答如何,您可以通过简单的强制转换将任何指针类型转换为 C 中的任何其他指针类型。要回答为什么,这就是 C 的定义方式。

qsort() 函数需要具有给定原型(带有const void *)参数的函数。这是因为qsort() 不知道您正在排序的实际 数据类型,并且必须使用一致的函数原型进行比较回调。您的比较回调负责将 const void * 参数转换为指向数组中实际类型的指针,在您的情况下为 const char **

【讨论】:

  • +1:我离开写一个样本,回来,整个评论流都消失了,除了我对你的原始评论。我错过了什么 ? =P
  • @WhozCraig:是的,我想你做到了。 :) 在我提供了一个反例之后,建议const char * 在比较功能中就足够了的原始评论者撤回了他的 cmets。这是正常工作 - 不正确的信息被删除!
  • 我有点想通了。我在下面提供的样本正是我们(你和我)所指的。我已经用指针数组做了 无数 次这样的事情,所以我很确定我们没有产生幻觉。
【解决方案2】:

您提供的示例被设置为要求 qsort() 对 char 指针 (char *) 数组进行排序。您提供的这个比较器按地址提供了算法所需的每一“对”项目。两个字符指针。 qsort() 使用的地址基于您给它的根地址,每个“项目”添加大小字节。由于每个“item”都是一个char*,所以每个item的大小实际上就是一个指针的大小。

我已经修改了比较器以演示正在比较的内容以及传入的地址。您会看到它们都是从包含所有 char *s 的数组的基地址开始递增的。

char *mystrings[] =
{
    "This",
    "is",
    "a",
    "test",
    "of",
    "pointers",
    "to",
    "strings"
};

int cstring_cmp(const void *a, const void *b)
{
    const char **ia = (const char **)a;
    const char **ib = (const char **)b;
    printf("%p:%s - %p:%s\n", a, *ia, b, *ib);
    return -strcasecmp(*ia, *ib);
}

int main(int argc, char *argv[])
{
    printf("Base address of our pointer array: %p\n\n", mystrings);
    qsort(mystrings, sizeof(mystrings)/sizeof(mystrings[0]), sizeof(char*), cstring_cmp);
    for (size_t i=0; i<sizeof(mystrings)/sizeof(mystrings[0]);i++)
        printf("%s\n", mystrings[i]);
    return 0;

}

产生以下输出:

Base address of our pointer array: 0x100006240

0x100006240:This - 0x100006260:of
0x100006260:of - 0x100006278:strings
0x100006240:This - 0x100006278:strings
0x100006248:is - 0x100006240:strings
0x100006278:This - 0x100006240:strings
0x100006250:a - 0x100006240:strings
0x100006270:to - 0x100006240:strings
0x100006258:test - 0x100006240:strings
0x100006260:of - 0x100006240:strings
0x100006268:pointers - 0x100006240:strings
0x100006260:of - 0x100006240:strings
0x100006240:test - 0x100006248:This
0x100006248:test - 0x100006250:to
0x100006240:This - 0x100006248:to
0x100006260:of - 0x100006268:pointers
0x100006268:of - 0x100006270:a
0x100006270:a - 0x100006278:is
0x100006268:of - 0x100006270:is
to
This
test
strings
pointers
of
is
a

【讨论】:

    【解决方案3】:

    一个更不可视化的:

    int cstring_cmp(const void *a, const void *b){
        return -strcasecmp((char *)(*((char **)a)), (char *)(*((char **)b)));
    }
    

    但是你可以看到,abchar **,它们被取消引用并变成 char * 并传递给 strcasecmp


    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    int cstring_cmp(const void *a, const void *b){
        return -strcasecmp((char *)(*((char **)a)), (char *)(*((char **)b)));
    }
    
    int main(){
        char *s[] = {  "Amit",
                       "Garima",
                       "Vaibhav",
                       "Gaurav"};
        qsort(s, 4, sizeof(char *), cstring_cmp);
        printf("%s\n%s\n%s\n%s\n", s[0], s[1], s[2], s[3]);
        return 0;
    }
    

    输出:

    Vaibhav
    Gaurav
    Garima
    Amit
    

    将任何指针强制转换为char *void * 是合法的,因为void * 表示指向内存(RAM 或虚拟)字节的指针。

    【讨论】:

    • 错了。为了对int 的数组进行排序,传递给比较器函数的是int *(转换为const void *)。对于char * 的数组进行排序,传递给函数的是char **(转换为const void *)。
    • 不,此代码无效!您不是在比较字符串,而是通过将地址提供给 strcasecmp() 函数来比较地址,这是没有意义的。通过在比较函数中将ia 的值打印为字符串来检查这一点。或者看看当你交换初始数组中的两个字符串时会发生什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-12
    • 1970-01-01
    • 2021-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多