Soy un principiante en C y estoy tratando de entender la función de comparación necesarios para la función qsort.

Parte Uno: La Sintaxis De

Una simple uso sugerido es esto (he incluido algunas main() código para imprimir los resultados así):

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

int values[] = { 40, 10, 100, 90, 20, 25, 12, 13, 10, 40 };

int compare(const void *a, const void *b)
{
    const int *ia = (const int *)a; //casting pointer types 
    const int *ib = (const int *)b;
    return *ia  - *ib; 
}

int main()
{
    int n;
    for (n=0; n<10; n++)
    {
        printf("%d ",values[n]);
    }
    printf("\n");
    qsort(values, 10, sizeof(int), compare);
    for (n=0; n<10; n++)
    {
        printf("%d ",values[n]);
    }
    printf("\n");
    system("pause");
    return 0;
}

No entiendo por qué tenéis necesidad de todas las cosas adicionales en la función comparar lo he simplificado a este:

int compare (int *a, int *b)
    {
        return *a-*b; 
    }

Esto todavía funciona, y produce los mismos resultados. ¿Alguien puede explicar a mí lo que me quitaron, y por qué aún funciona?

Parte Dos: ¿Por Qué Los Punteros?

Además, ¿es realmente necesario el uso de punteros? ¿Por qué no puedo comparar «a» y «b» directamente como de forma (NO de trabajo):

int compare (int a, int b)
        {
            return a-b; 
        }

Por alguna razón, con una matriz multidimensional, yo era capaz de salirse con la NO utilización de punteros y por alguna razón no funcionó! ¿Qué está pasando? (Código de ejemplo de ordenación de una matriz multidimensional por el 2º elemento en cada uno de los subsectores de la matriz):

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

int values[7][3] = { {40,55}, {10,52}, {100,8}, {90,90}, {20,91}, {25,24} };

int compare(int a[2], int b[2])
{
    return a[1] - b[1];
}

int main()
{
    int n;
    for (n=0; n<6; n++)
    {
        printf("%d,",values[n][0]);
        printf("%d ",values[n][1]);
    }
    printf("\n");
    qsort(values, 6, sizeof(int)*3, compare);
    for (n=0; n<6; n++)
    {
        printf("%d,",values[n][0]);
        printf("%d ",values[n][1]);
    }
    printf("\n");
    system("pause");
    return 0;
}

Estoy muy contento de la matriz multidimensional de la clasificación es trabajo, es mi objetivo final de todos modos, pero no tengo idea de cómo me las arreglé para conseguir que funcione (aparte de mala suerte y cortar el código) así que realmente me gustaría alguna explicación de por qué algunos de los ejemplos que me daban trabajo, y por qué algunos no!

OriginalEl autor Dlinet | 2012-12-27

4 Comentarios

  1. 12

    Esto todavía funciona, y produce los mismos resultados. ¿Alguien puede explicar a mí lo que me quitaron, y por qué aún funciona?

    Va a invocar un comportamiento indefinido en C. Ver C99 6.3.2.3 Punteros/8:

    Un puntero a una función de un tipo puede ser convertido a un puntero a una función de la otra
    el tipo y la espalda de nuevo; el resultado se compara igual a la original puntero. Si un convertido
    puntero se utiliza para llamar a una función cuyo tipo no es compatible con la punta para escribir,
    el comportamiento es indefinido.

    En C++, este programa es de plano mal formado: http://ideone.com/9zRYSj

    Todavía «pasa a trabajar» porque el compare función espera un par de punteros; y en su plataforma sizeof(void*) es el mismo que sizeof(int*), por lo que llamar a un puntero a función del tipo de int(void *, void *) que en realidad contiene un puntero a una función de tipo int(int *, int *) es efectivamente el mismo que el tipo de puntero yesos en su plataforma en este punto particular en el tiempo.

    Además, ¿es realmente necesario el uso de punteros? ¿Por qué no puedo comparar «a» y «b» directamente como de forma (NO de trabajo):

    Porque qsort toma una comparación general de la función para cualquiera de los dos tipos; no sólo int. Así que no sé de qué tipo, para que el puntero se eliminan las referencias.

    Por alguna razón, con una matriz multidimensional, yo era capaz de salirse con la NO utilización de punteros y por alguna razón no funcionó! qué está pasando!

    Esto es debido a los siguientes prototipos son los mismos:

    1. int foo(int *a, int *b);
    2. int foo(int a[], int b[])

    Que es, una matriz decae en un puntero cuando se pasa a una función. La especificación explícita de la longitud de la matriz a como se hizo:

    int foo(int a[2], int b[2])

    hace que el compilador para hacer sizeof y otro tiempo de compilación bits para tratar el tema como una de dos elementos de la matriz; pero la función acepta un par de punteros cuando se llega al nivel de la máquina.

    En cualquiera de estos casos, pasando de una función de comparación que no tiene que tener un par de void *s resultados en un comportamiento indefinido. Un resultado válido de «un comportamiento indefinido» es «sólo parece funcionar». Otro resultado válido sería «funciona los martes» o «formatea el disco duro». No confíe en este comportamiento.

    Es interesante que las matrices se descomponen en los punteros. Es esto algo para ser invocado, o es que hay un error inherente en esto así? ¿Cómo sugieren la modificación de la clasificación multidimensional para hacer que sea fiable?
    Siempre hacer su función de comparación de tomar const void*. Yeso que se puntero a const int*. A continuación, utilice operator[] como normalmente lo haría.
    Gracias, voy a probar eso!

    OriginalEl autor Billy ONeal

  2. 2

    No entiendo por qué tenéis necesidad de todas las cosas adicionales en comparación
    función, así que me simplificado para este

    Si utiliza const calificador. Se espera que usted no modifique los valores en el comparador. Pero es posible desechar la const y romper la promesa que usted hace para el compilador.


    qsort espera un puntero a función que toma dos const void * como los parámetros de lo que es la razón por la punteros se pasan por la función de comparación:

       void qsort(void *base, size_t nmemb, size_t size,
                      int(*compare)(const void *, const void *));

    Por lo que pasa a y b llevaría a la interpretación de la valores como punteros que es obviamente erróneo.


    Funciona sin pasar punteros para matrices multidimensionales porque cuando pasa de las matrices, se pudren en los punteros. Por lo que la siguiente comparación que tiene es aceptar.

    int compare (int a[2], int b[2])
    {
        return a[1] - b[1];
    }

    OriginalEl autor P.P.

  3. 0

    La respuesta es muy simple : Desde el manual de qsort http://pubs.opengroup.org/onlinepubs/009695399/functions/qsort.html el prototipo de la función de puntero es :

    int comp(const void *a, const void *b)

    El typedef asociados con este prototipo puede ser declarada de esta manera

    typedef int (*comp_qsort_funct_t) ( const void *, const void * )

    Donde comp_qsort_funct_t es el tipo de la función de puntero

    El prototipo de la función de comparación de qsort es el uso de const variable debido a que esta es una buena práctica de diseño, ya que los datos no va a ser modificado.

    Usando un tipo diferente de prototipo puede conducir a resultados inesperados en función del compilador /plataforma. O simplemente un error de compilación, ejemplo de comentario : http://ideone.com/9zRYSj

    De modo que usted no podrá utilizar otro prototipo.

    Esta es la C, no C++. En C++ esto es completamente ilegal; no sólo la «mala práctica de diseño» ideone.com/9zRYSj
    Yo solo estaba explicando por qué el prototipo es el uso de const variable… no entiendo tu punto acerca de C++ aquí … por Favor explique
    En C, este código es un comportamiento indefinido. En C++, este código es plana mal formado. La referencia es a una fuente de C++, pero usted está hablando acerca de C. Sírvanse aclarar que la diferencia y la voy a cambiar el -1 a +1.
    El enlace que se proporciona es acerca de C y no C++… Lo que usted acaba de leer el dominio de la URL ? Y el código proporcionado es no mal formada, esta es la forma en que un prototipo de función es declarada en C
    El prototipo no está mal formada; la llamada a qsort es. Usted señaló en una página que dice «Referencia de C++» en el título y el contenido de la página, pero esta es un área donde C y C++ difieren significativamente; por lo que sólo aparecen en una referencia de C++ puede ser confuso para los lectores.

    OriginalEl autor benjarobin

  4. 0

    Me gustaría confirmar las observaciones de Dlinet que pidió a la pregunta original.

    El compilador de C de hecho va a aceptar todas las formas de la función de comparación, incluso sin const, e incluso el uso de int * en lugar de * vacío. Sin embargo, mi compilador de C++ rechaza las variaciones y sólo acepta la const void * formulario.

    El compilador de C acepta incluso el int, formulario no usar punteros a todos. He comprobado y se encontró que la int forma de comparar la función es recibir puntero valores, no los enteros de la matriz. Y el resultado es que la matriz no está ordenada, pero permanece en el mismo orden. Y yo creo que todo esto es lo que cabría esperar.

    Por lo tanto, parece que usted podría usar int * en lugar de * vacío en la definición de la función, y entonces no sería necesario lanzar dentro de la función.

    Si esto es una buena práctica de programación es discutible, con algunos programadores diciendo que sí y algunos diciendo que no. Me parece una buena programación o no, la reducción de desorden sería un punto a favor del uso de int * en lugar de * vacío. Pero entonces, un compilador de C++ no permite hacer eso.

    No entiendo cómo esta última respuesta recibí un upvote; esto es completamente erróneo. Compiladores de C aceptan todo tipo de código que es ilegal. El código C en cuestión provoca un comportamiento indefinido. Este es no buena práctica de programación, y nadie que sepa cómo programar en C se dice que es.

    OriginalEl autor Indinfer

Dejar respuesta

Please enter your comment!
Please enter your name here