c 中的 qsort 类型转换指针

发布于 2025-01-10 06:08:52 字数 1308 浏览 2 评论 0原文

这是在 C 中练习 qsort 函数的简单代码。

int compareF(const void *a, const void *b) {
    // return (*(int**)a)[0] - (*(int**)b)[0];  
    const int *pr1 = *(const int **)a;
    const int *pr2 = *(const int **)b;
    return pr1[0] - pr2[0];
}

int main() {
    int *array[] = {(int[]){2,2,3}, (int[]){1,2,1},(int[]){1,3,3},(int[]){0,2,3},(int[]){1,2,0}};
    qsort(array, 5, sizeof(int[3]), compareF);
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", array[i][j]);
        }
        printf("\n");
    }
  return (0);
}

我不明白第 3 行和第 4 行为什么用指针以这种方式进行类型转换。这是我的理解。首先,无论我们是否设置新变量来保存参数,我们如何使用语法并不重要,因为这两个返回状态是相同的。 其次,它需要进行类型区分,因为参数是 void 类型,因此函数不知道类型。第一个 * 用于解引用参数 a,以便它可以访问地址 a。我们使用 int** 因为..?

main 函数中有一个二维整数数组。根据我的理解,CompareF 函数每次仅将 array[0] 和 array[1] 作为参数。所以我不明白为什么它用两个 ** 键入。

相同的代码只修改了一行代码

int array[3][2]= {{1,4},{3,6},{2,8}};

当以这种方式定义数组时,

const int *pr1 = *(const int[])a;
const int *pr2 = *(const int[])b;

,类型转换是否以相同的方式发生?或者

const int *pr1 = (const int*)a;
const int *pr2 = (const int*)b;

第一种情况不起作用,而第二种情况则有效。但不需要 * 来取消引用吗?喜欢

const int *pr1 = *(const int*)a;
const int *pr2 = *(const int*)b;

This is a simple code to practice qsort function in C.

int compareF(const void *a, const void *b) {
    // return (*(int**)a)[0] - (*(int**)b)[0];  
    const int *pr1 = *(const int **)a;
    const int *pr2 = *(const int **)b;
    return pr1[0] - pr2[0];
}

int main() {
    int *array[] = {(int[]){2,2,3}, (int[]){1,2,1},(int[]){1,3,3},(int[]){0,2,3},(int[]){1,2,0}};
    qsort(array, 5, sizeof(int[3]), compareF);
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 3; j++) {
            printf("%d ", array[i][j]);
        }
        printf("\n");
    }
  return (0);
}

I don't grasp line 3 and 4 of why it is type-casted this way with pointers. This is my understanding. Firstly, it doesn't matter how we use syntax whether we set new variables to save parameters or not like those two return states are just same.
Secondly, it needs to be type cased since parameters are void type so function does not know the type. First * is for dereferencing parameter a so that It has an access to the address a. And we use int** because..?

There's 2d integer array in main function. CompareF function only takes array[0] and array[1] as parameter each time in my understanding. So I don't get why it is typed cased with two **.

Same code with only one line of code modified

int array[3][2]= {{1,4},{3,6},{2,8}};

when array is defined this way, is type casting happened in same way?

const int *pr1 = *(const int[])a;
const int *pr2 = *(const int[])b;

or

const int *pr1 = (const int*)a;
const int *pr2 = (const int*)b;

First case doesn't work and second one does. But doesn't it need * to dereference? like

const int *pr1 = *(const int*)a;
const int *pr2 = *(const int*)b;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦冥 2025-01-17 06:08:52

每当要比较任何两个数组元素时,都会调用传递给 qsort 的比较函数,并且它会获取每个数组元素的地址。

您有一个正在排序的 int * 数组,因此每个元素的地址都具有 int ** 类型。这与 compareF 的参数转换为的类型相匹配。取消引用这些指针会得到一个 int * 类型的值,这就是数组中实际包含的值。

另外,qsort 的第三个参数不正确。数组元素的类型不是 int[2],而是 int * 类型。如果 int 是 4 个字节,而指针是 8 个字节,那么它们恰好是相同的,但您不能依赖于此。

The compare function passed to qsort is called anytime any two array elements are to be compared, and it is taking the address of each of those array elements.

You have an array of int * that is being sorted, so the address of each of those elements has type int **. That matches the type that the parameters of compareF are casted to. Dereferencing those pointers then gives us a value of type int * which is what is actually contained in the array.

Also, the third parameter to qsort is not correct. The array elements do not have type int[2] but instead have type int *. If an int is 4 bytes and a pointer is 8 bytes then they happen to be the same, but you can't depend on that.

猫性小仙女 2025-01-17 06:08:52

对于初学者来说,qsort: 的调用

qsort(array, 5, sizeof(int[2]), compareF);

是不正确的。第三个参数是数组元素的大小。由于数组元素的类型为 int *,因此第三个参数必须为 sizeof( int * ) 或相同的 sizeof( *array )< /code>:

qsort(array, 5, sizeof( *array ), compareF);

函数qsort 将指向数组元素的指针作为const void * 类型的指针传递给比较函数compareF

如果数组的元素类型为 int *,则指向数组元素的指针的类型为 int **

因此,在函数compareF中,您需要将const void *类型的指针转​​换为const int **类型。取消引用这样的指针:

const int *pr1 = *(const int **)a;

您将获得原始数组的一个元素。

由于数组的元素指向类型为 int[3] 的复合文字的第一个元素,因此,例如比较函数中的表达式 pr1[0] 给出:复合文字的第一个元素,表达式 pr1[1] 给出复合文字的第二个元素,依此类推。

一般来说,使用此 return 语句:

return pr1[0] - pr2[0];

是不正确的,因为所提供的表达式可能会导致有符号整数类型 int 溢出。

比较复合文字的所有元素对原始数组的元素(指向复合文字的第一个元素的指针)进行排序更有趣。

这是一个演示程序:

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

enum { M = 3 };

int compareF( const void *a, const void *b ) 
{
    const int *pr1 = *( const int ** )a;
    const int *pr2 = *( const int ** )b;
    
    size_t i = 0;
    while ( i != M && pr1[i] == pr2[i] ) ++i;
    
    return i == M ? 0 : ( pr2[i] < pr1[i] ) - ( pr1[i] < pr2[i] );
}

int main(void) 
{
    int * array[] = 
    {
        (int[M]){2,2,3}, 
        (int[M]){1,2,1},
        (int[M]){1,3,3},
        (int[M]){0,2,3},
        (int[M]){1,2,0}
    };
    
    const size_t N = sizeof( array ) / sizeof( *array );
    
    qsort( array, N, sizeof( *array ), compareF );
    
    for ( size_t i = 0; i < N; i++ )
    {
        for ( size_t j = 0; j < M; j++ )
        {
            printf( "%d ", array[i][j] );
        }
        
        putchar( '\n' );
    }
}

程序输出如下

0 2 3 
1 2 0 
1 2 1 
1 3 3 
2 2 3 

正如您所看到的,如果两个复合文字的第一个元素彼此相等,则比较第二个元素,依此类推。

如果您有一个像这样声明的二维数组

int array[3][2]= {{1,4},{3,6},{2,8}};

,则意味着元素类型又是数组类型int[2]。因此函数调用将类似于 指向

qsort(array, sizeof( array ) / sizeof( *array ), sizeof( int[2] ), compareF);

数组元素的指针将具有 int ( * )[2] 类型。
因此,在比较函数中取消引用指针,您将获得一个 int[2] 类型的数组(原始数组的一个元素),用作表达式的数组将隐式转换为指向其第一个元素的指针。

这是一个演示程序。

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

enum { M = 2 };

int compareF( const void *a, const void *b ) 
{
    const int *pr1 = *( const int ( * )[M] )a;
    const int *pr2 = *( const int ( * )[M] )b;
    
    size_t i = 0;
    while ( i != M && pr1[i] == pr2[i] ) ++i;
    
    return i == M ? 0 : ( pr2[i] < pr1[i] ) - ( pr1[i] < pr2[i] );
}

int main(void) 
{
    int array[][M] = 
    {
        { 1, 4 }, { 3, 6 }, { 2, 8 }
    };
    
    const size_t N = sizeof( array ) / sizeof( *array );
    
    qsort( array, N, sizeof( *array ), compareF );
    
    for ( size_t i = 0; i < N; i++ )
    {
        for ( size_t j = 0; j < M; j++ )
        {
            printf( "%d ", array[i][j] );
        }
        
        putchar( '\n' );
    }
}

程序输出为:

1 4 
2 8 
3 6 

注意,当两个比较元素相等时,比较函数应返回0。相对于函数compareF,这意味着循环之后:

    size_t i = 0;
    while ( i != M && pr1[i] == pr2[i] ) ++i;

i将等于M,因为比较的一维数组的所有元素都是彼此平等。

For starters this call of qsort:

qsort(array, 5, sizeof(int[2]), compareF);

is incorrect. The third parameter is the size of elements of the array. As the type of elements of the array is int * then the third parameter must be sizeof( int * ) or that is the same sizeof( *array ):

qsort(array, 5, sizeof( *array ), compareF);

The function qsort passes pointers to elements of the array to the comparison function compareF as pointers of the type const void *.

As the elements if the array have the type int * then a pointer to an element of the array has the type int **.

So within the function compareF you need to cast the pointers of the type const void * to types const int **. Dereferencing such a pointer like:

const int *pr1 = *(const int **)a;

you will get an element of the original array.

As the elements of the array point to first elements of compound literals that have the type int[3] then for example the expression pr1[0] within the comparison function gives the first element of a compound literal, the expression pr1[1] gives the second element of the compound literal and so on.

In general using this return statement:

return pr1[0] - pr2[0];

is incorrect because the supplied expression can produce an overflow for the signed integer type int.

It is more interesting to sort the elements (pointers to first elements of compound literals) of the original array comparing all elements of compound literals.

Here is a demonstration program:

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

enum { M = 3 };

int compareF( const void *a, const void *b ) 
{
    const int *pr1 = *( const int ** )a;
    const int *pr2 = *( const int ** )b;
    
    size_t i = 0;
    while ( i != M && pr1[i] == pr2[i] ) ++i;
    
    return i == M ? 0 : ( pr2[i] < pr1[i] ) - ( pr1[i] < pr2[i] );
}

int main(void) 
{
    int * array[] = 
    {
        (int[M]){2,2,3}, 
        (int[M]){1,2,1},
        (int[M]){1,3,3},
        (int[M]){0,2,3},
        (int[M]){1,2,0}
    };
    
    const size_t N = sizeof( array ) / sizeof( *array );
    
    qsort( array, N, sizeof( *array ), compareF );
    
    for ( size_t i = 0; i < N; i++ )
    {
        for ( size_t j = 0; j < M; j++ )
        {
            printf( "%d ", array[i][j] );
        }
        
        putchar( '\n' );
    }
}

The program output is

0 2 3 
1 2 0 
1 2 1 
1 3 3 
2 2 3 

As you can see if first elements of two compound literals are equal each other then second elements are compared and so on.

If you have a two-dimensional array declared like

int array[3][2]= {{1,4},{3,6},{2,8}};

then it means that the element type is in turn array type int[2]. So the function call will look like

qsort(array, sizeof( array ) / sizeof( *array ), sizeof( int[2] ), compareF);

And pointer to an element of the array will have the type int ( * )[2].
So dereferencing the pointer within the comparison function you will get an array of the type int[2] (an element of the original array) that that used as an expression is converted implicitly to pointer to its first element.

Here is a demonstration program.

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

enum { M = 2 };

int compareF( const void *a, const void *b ) 
{
    const int *pr1 = *( const int ( * )[M] )a;
    const int *pr2 = *( const int ( * )[M] )b;
    
    size_t i = 0;
    while ( i != M && pr1[i] == pr2[i] ) ++i;
    
    return i == M ? 0 : ( pr2[i] < pr1[i] ) - ( pr1[i] < pr2[i] );
}

int main(void) 
{
    int array[][M] = 
    {
        { 1, 4 }, { 3, 6 }, { 2, 8 }
    };
    
    const size_t N = sizeof( array ) / sizeof( *array );
    
    qsort( array, N, sizeof( *array ), compareF );
    
    for ( size_t i = 0; i < N; i++ )
    {
        for ( size_t j = 0; j < M; j++ )
        {
            printf( "%d ", array[i][j] );
        }
        
        putchar( '\n' );
    }
}

The program output is:

1 4 
2 8 
3 6 

Pay attention to that the comparison function shall return 0 when two compared elements are equal each other. Relative to the function compareF it means that after the loop:

    size_t i = 0;
    while ( i != M && pr1[i] == pr2[i] ) ++i;

i will be equal to M because all elements of the compared one-dimensional arrays are equal each other.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文