简体   繁体   English

将指针转换为指向void指针的指针

[英]convert pointer to pointer to void pointer

When I'm learning to use qsort to sort an array of string, there is a question puzzled me. 当我学习使用qsort对字符串数组进行排序时,有一个问题困惑我。 For example, to sort the following s 例如,下面的排序s

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

To use the qsort, you must provide a comparison function like the following function cstring_cmp I guess in the qsort function, the type of parameter to be passed to the function cstring_cmp is char** . 要使用qsort,你必须提供一个比较函数,如下面的函数cstring_cmp我想在qsort函数中,要传递给函数cstring_cmp的参数类型是char** How to convert a char** to a void* ? 如何将char**转换为void* Why can we convert a char** to a 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 */
    }

Your question seems a bit vague but I'll give it a go anyway. 你的问题看起来有点模糊,但无论如何我都会试一试。 To answer how , you can convert any pointer type to any other pointer type in C by simply casting. 要回答如何 ,您可以通过简单转换将任何指针类型转换为C中的任何其他指针类型。 To answer why , well that's how C is defined. 要回答原因 ,那就是C的定义方式。

The qsort() function requires a function with the given prototype (with const void * ) parameters. qsort()函数需要一个具有给定原型(带有const void * )参数的函数。 This is because qsort() is unaware of the actual data type you are sorting, and must use a consistent function prototype for the comparison callback. 这是因为qsort()不知道您正在排序的实际数据类型,并且必须使用一致的函数原型进行比较回调。 Your comparison callback is responsible for converting the const void * parameters to pointers to the actual types in your array, in your case const char ** . 您的比较回调负责将const void *参数转换为指向数组中实际类型的指针,在您的示例中为const char **

The example you provide is being setup to ask qsort() to sort an array of char pointers (char *). 您提供的示例是设置为要求qsort()对char指针数组(char *)进行排序。 This comparator you're providing is given each 'pair' of items the algorithm needs, by address . 您提供的这个比较器按地址给出算法所需的每对“项目”。 two char pointers. 两个char指针。 the address qsort() uses is based on the root address you give it, adding size-bytes per "item". qsort()使用的地址是基于你给它的根地址,每个“item”添加size-bytes。 Since each "item" is a char*, the size of each item is, in fact, the size of a pointer. 由于每个“item”都是char *,因此每个项目的大小实际上是指针的大小。

I've modified the comparator to demonstrate what is being compared, and what the addresses are that are being passed in. you will see they are all increments off the base address of the array containing all the char *s. 我已经修改了比较器以演示正在进行比较的内容,以及传入的地址是什么。您将看到它们都是包含所有char *的数组基址的增量。

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;

}

produces the following output: 产生以下输出:

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

A even less visualized one: 一个更不可视化的:

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

But you can see , a and b are char ** , and they are dereferenced and become char * and passed to strcasecmp . 但你可以看到, 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;
}

Output: 输出:

Vaibhav
Gaurav
Garima
Amit

It is legal to cast any pointer to char * or void * because void * means a pointer to a memory (RAM or virtual) byte. 将任何指针转换为char *void *是合法的,因为void *表示指向内存(RAM或虚拟)字节的指针。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM