2010-08-15 16 views
17

Angenommen, ich habe ein Array von Zeigern in C verkohlen:Wie qsort ein Array von Zeigern auf Char in C?

char *data[5] = { "boda", "cydo", "washington", "dc", "obama" }; 

Und ich möchte dieses Array sortieren qsort mit:

qsort(data, 5, sizeof(char *), compare_function); 

Ich bin nicht mit der Vergleichsfunktion zu entwickeln. Aus irgendeinem Grund funktioniert das nicht:

int compare_function(const void *name1, const void *name2) 
{ 
    const char *name1_ = (const char *)name1; 
    const char *name2_ = (const char *)name2; 
    return strcmp(name1_, name2_); 
} 

Ich habe viel von der Suche und fand, dass ich ** innerhalb von qsort verwenden musste:

int compare_function(const void *name1, const void *name2) 
{ 
    const char *name1_ = *(const char **)name1; 
    const char *name2_ = *(const char **)name2; 
    return strcmp(name1_, name2_); 
} 

Und das funktioniert.

Kann jemand die Verwendung von *(const char **)name1 in dieser Funktion erklären? Ich verstehe es überhaupt nicht. Warum der Doppelzeiger? Warum hat meine ursprüngliche Funktion nicht funktioniert?

Danke, Boda Cydo.

+2

'data' sollte' const' deklariert werden. –

+0

Billy, wenn es const ist, kann es noch sortiert werden? – bodacydo

+1

Ja. Das Array kann nicht "const" sein, aber die Zeiger in diesem Array sollten "const" sein. Es ist nicht erlaubt, Konstantenliterale für die Kompilierungszeit so zu ändern (dies ist ein undefiniertes Verhalten). Um das zu bekommen, wollen Sie 'const char * data [5]'. Wenn Sie möchten, dass das Array selbst auch konstant ist, dann würden Sie 'const char * const data [5]' machen. –

Antwort

17

Wenn es hilft, die Dinge im Kopf zu behalten, ist der Typ, auf den Sie die Zeiger in Ihrem Vergleicher werfen sollten, derselbe wie der ursprüngliche Typ des Datenzeigers, den Sie an qsort übergeben (dass die Qsort-Dokumentation base aufruft). Aber für qsort, um generisch zu sein, behandelt es einfach alles wie void*, unabhängig davon, was es "wirklich" ist.

Also, wenn Sie ein Array von Ints sortieren, dann werden Sie in einem int* übergeben (konvertiert zu void*). qsort gibt Ihnen zwei void* Zeiger auf den Komparator zurück, den Sie in int* konvertieren, und dereference, um die int Werte zu erhalten, die Sie tatsächlich vergleichen.

ersetzen Jetzt int mit char*:

wenn Sie eine Reihe von char* zu sortier, dann werden Sie in einem char** (umgerechnet auf void*) übergeben. qsort gibt Ihnen zwei void* Zeiger auf den Komparator zurück, die Sie in char** konvertieren, und dereferenzieren, um die char* Werte zu erhalten, die Sie tatsächlich vergleichen.

In Ihrem Beispiel, weil Sie ein Array verwenden, die char**, die Sie übergeben, ist das Ergebnis des Arrays von char* "Verfall" zu einem Zeiger auf sein erstes Element. Da das erste Element ein char* ist, ist ein Zeiger darauf ein char**.

3

Stellen Sie sich vor, Ihre Daten waren double data[5].

Ihre Vergleichsmethode würde Zeiger (double *, void *) an die Elemente (double) übergeben.
Ersetzen Sie nun double wieder mit char *.

2

qsort ist allgemein genug, um Arrays zu sortieren, die aus anderen Dingen als Zeigern bestehen. Deshalb ist der Größenparameter da. Es kann die Array-Elemente nicht direkt an die Vergleichsfunktion übergeben, da es zur Kompilierungszeit nicht weiß, wie groß sie sind. Daher übergibt es Zeiger. In Ihrem Fall erhalten Sie Zeiger auf char *, char **.

+0

Ich verstehe nicht, sorry. Das erste Argument für 'qsort' ist ein' * '. Ich gebe ein '**'. Was bedeutet, dass ich nur ein "*" passiere. Aber ein '*' ist genau ein 'char *'. Sehen? Deshalb bin ich verwirrt. – bodacydo

+0

@bodacydo: Der wichtige Punkt ist die Vergleichsfunktion nimmt Zeiger auf * Elemente * des Arrays. Da jedes Element Ihres Arrays ein Zeiger auf ein Char ist, arbeitet die Vergleichsfunktion mit Zeigern zu Zeigern zu Char. – jamesdlin

0

von man qsort:

The contents of the array are sorted in ascending 
order according to a comparison function pointed to by 
compar, which is called with two arguments that **point** 
to the objects being compared. 

So klingt es wie die Vergleichsfunktion Zeiger auf die Array-Elemente erhält. Nun ist ein Zeiger auf char * ein char ** (d. H. Ein Zeiger auf einen Zeiger auf ein Zeichen).

0

char *data[5] = { "boda", "cydo", "washington", "dc", "obama" };

ist eine Aussage des Compilers für eine Reihe von Größe 5 von Zeichenzeiger zu fragen. Sie haben diese Zeiger auf Zeichenfolgenliterale initialisiert, aber für den Compiler ist es immer noch ein Array von fünf Zeigern.

Wenn Sie dieses Array in qsort übergeben, zerfällt das Array von Zeigern in einen Zeiger, der auf das erste Element in Übereinstimmung mit C-Array-Parameterübergaberegeln zeigt.

Daher müssen Sie eine Ebene der Umleitung verarbeiten, bevor Sie zu den tatsächlichen Zeichenarrays gelangen, die die Konstanten enthalten.

2

Die Vergleichsfunktion nimmt Zeiger auf den Objekttyp, der sich in dem Array befindet, das Sie sortieren möchten. Da das Array char * enthält, nimmt Ihre Vergleichsfunktion Zeiger auf char *, aka char **.

0

@bodacydo hier ist ein Programm, das erklären kann, was andere Programmierer versuchen zu vermitteln, aber dies würde in Zusammenhang mit den „ganzen Zahlen“ seine

#include <stdio.h> 


int main() 
{ 
    int i , j; 
    int *x[2] = {&i, &j}; 

    i = 10; j = 20; 

    printf("in main() address of i = %p, address of j = %p \r\n", &i, &j); 

    fun(x); 
    fun(x + 1); 

    return 0; 
} 


void fun(int **ptr) 
{ 
    printf("value(it would be an address) of decayed element received = %p, double dereferenced value is %d \r\n",*ptr, **ptr); 
    printf("the decayed value can also be printed as *(int **)ptr = %p \r\n", *(int **)ptr); 
}