2010-02-09 16 views
8

Ich versuche, Objekte für ein Hausaufgabe-Problem zu vertauschen, die Void-Zeiger verwendet, um Objekte zu tauschen. Die Erklärung meiner Funktion muss sein:Austauschen von Objekten mithilfe von Zeigern

void swap(void *a, void *b, size_t size); 

Ich bin nicht für den genauen Code suchen, wie es zu tun, so kann ich es selbst herausfinden, aber ich bin nicht sicher, ob ich es richtig verstehen. Ich habe festgestellt, dass ein Problem dabei besteht:

void *temp; 
temp = a; 
a = b; 
b = temp; 

ändert nur, worauf die Zeiger zeigen. Ist das korrekt? Wenn es richtig ist, warum ändert der Zeiger nicht wirklich den Inhalt zwischen * a und * b. Denn wenn Ihr Zeiger auf etwas anderes zeigt, könnten Sie das nicht dereferenzieren und die Objekte wären jetzt anders?

ähnlich Schalen nur die Werte wie:

void *temp; 
*temp = *a; 
*a = *b; 
*b = *temp; 

Ist auch nicht richtig, was ich bin nicht sicher, warum. Denn wieder scheint mir der Inhalt vertauscht zu sein.

Bedeutet das Tauschen von Objekten das vollständige Austauschen von Speicher und den Wert dessen, auf was ein Zeiger zeigt?

So scheint es, dass ich malloc verwenden muss, um genügend Platz für meinen Swap zuzuweisen. Wenn ich genug Speicher für ein Objekt zugebe, unter der Annahme, dass sie die gleiche Größe haben, sehe ich nicht wirklich, wie es sich von den anderen beiden oben genannten Methoden unterscheidet.

void *temp = malloc(sizeof(pa)); 
// check for null pointer 
temp = a; 
// do something I'm not sure of since I don't quite get how allocating space is any 
// different than the two above methods??? 

Vielen Dank!

+1

Sie nah dran sind. Die Angabe eines 'void *' ist jedoch nicht erlaubt. Denken Sie über andere Möglichkeiten nach, wie Sie die Informationen verschieben können, denken Sie insbesondere an den Parameter "Größe" und welche Auswirkungen dies auf Ihren Algorithmus hat. –

+0

Das Ändern der Zeiger ist ein schöner Versuch, aber wird nicht funktionieren, weil sie nach Wert übergeben wurden. Somit hat der Anrufer den gleichen Wert in den Zeigern, bevor der Anruf getätigt wurde. –

Antwort

19

Swapping Zeiger ändert nicht die spitzen-Werte. Wenn dies der Fall wäre, wäre das so, als würde man Adressaufkleber auf Umschlägen vertauschen, die mich in Ihr Haus und Sie in mein Haus bringen.

Sie fast da waren:

void swap(void *a, void *b, size_t size) { 
    char temp[size]; // C99, use malloc otherwise 
    // char serves as the type for "generic" byte arrays 

    memcpy(temp, b, size); 
    memcpy(b, a, size); 
    memcpy(a, temp, size); 
} 

Die memcpy Funktion kopiert Speicher, die die Definition von Objekten in C ist (. Genannt POD oder Daten ‚plain ol in C++, vergleichen) Auf diese Weise memcpy ist, wie Sie Zuordnung tun, ohne über die Art des Objekts zu kümmern, und man konnte sogar andere Aufgaben als memcpy schreiben statt:

int a = 42, b = 3, temp; 

temp = b; 
b = a; 
a = temp; 
// same as: 
memcpy(&temp, &b, sizeof a); 
memcpy(&b, &a, sizeof a); 
memcpy(&a, &temp, sizeof a); 

das ist genau das, was die oben funktioniert, da kann man nicht Zuordnung verwenden, wenn Sie tun kenne den Typ des Objekts nicht und v oid ist der Typ, der für "unbekannt" steht. (Es bedeutet auch "nichts", wenn es als Funktionsrückgabetyp verwendet wird.)


Als eine Kuriosität, eine andere Version, die malloc gemeinsam Fällen vermeidet und verwendet keine C99 des VLAs:

void swap(void *a, void *b, size_t size) { 
    enum { threshold = 100 }; 
    if (size <= threshold) { 
    char temp[threshold]; 

    memcpy(temp, b, size); 
    memcpy(b, a, size); 
    memcpy(a, temp, size); 
    } 
    else { 
    void* temp = malloc(size); 
    assert(temp); // better error checking desired in non-example code 

    memcpy(temp, b, size); 
    memcpy(b, a, size); 
    memcpy(a, temp, size); 

    free(temp); 
    } 
} 
+1

Richtig, aber es ist memcpy (dest, src, size); –

+0

+1 um die Versuchungen von 'alloca' zu vermeiden! –

+0

@Earwicker: Wenn ich etwas nicht in C89 verwende, würde ich lieber C99 als alloca sein.:) –

0

Um den Zeiger innerhalb und außerhalb zu ändern, müssen Sie den Zeiger durch Verweis oder einen Doppelzeiger übergeben.

Wenn Ihre Funktion muss sein wie:

void swap(void *a, void *b, size_t size); 

Ich nehme an, dass Sie so etwas wie implementieren:

void * temp; 
temp = malloc(size); 
memcpy(temp,a,size); 
memcpy(a,b,size); 
memcpy(b,temp,size); 
free(temp); 
1

Zunächst einmal beachten Sie, dass alle Änderungen an den Zeiger innerhalb der Funktion wird nicht außerhalb der Funktion weitergegeben. Du musst also die Erinnerung verschieben.

Der einfachste Weg, dies zu tun, ist mit memcpy - einen Puffer auf den Stapel zuzuteilen, memcpy die entsprechende Größe von a hinein, von memcpyb zu a, und eine letzte memcpy von Temp in b.

0

Um einen wirklichen Effekt haben, können Sie das Äquivalent des zweiten Blocks tun müssen, die Sie erwähnt:

void *temp; 
*temp = *a; 
*a = *b; 
*b = *temp; 

Das Problem hierbei ist, dass ‚Leere‘ nicht eine Größe haben, so dass Sie nicht Weisen Sie 'void' so zu, wie sie steht. Sie müssen Platz für temp zuweisen, um darauf zu zeigen, dann kopieren Sie die Werte mit etwas wie memcpy().

+0

cant deref void * – pm100

+0

@ pm100 - er erklärt das tatsächlich in der Antwort. –

+1

@ pm100: Im Gegensatz zu einem Compiler wird erwartet, dass Sie sowohl auf den Code * als auch auf die Kommentare achten! –

2

Parameter sind wie lokale Variablen, in die Werte kopiert werden, bevor die Funktion gestartet wird. Dieser Prototyp:

void swap(void *a, void *b, size_t size); 

Bedeutet, dass die beiden Adressen in neue Variablen kopiert werden a und b genannt. Also, wenn Sie ändern, was in a und b gespeichert ist, wird nichts, was Sie tun, eine beliebige Wirkung haben, nachdem swap zurückgibt.

1

Wenn Sie eine Funktion schreiben, um zwei Ganzzahlen zu vertauschen, geben Sie Zeiger auf sie, Ihre Lösung des Tauschens der Werte, auf die gezeigt wird, würde funktionieren. Allerdings betrachten die Situation mit

struct { 
    int a; 
    int b; 
} a, b; 

swap(&a, &b, sizeof(a)); 

Sie müssen einen Weg, um herauszufinden, den Inhalt jeder Wert ohne Kenntnis weitergegeben zu tauschen, was sie tatsächlich bestehen.

3

Ihre erste Frage zu beantworten, lassen Sie sich in einigen Werten füllen, um zu sehen, was passiert:

void* a = 0x00001000; // some memory address 
void* b = 0x00002000; // another memory address 
/* Now we'll put in your code */ 
void* temp; // temp is garbage 
temp = a; // temp is now 0x00001000 
a = b; // a is now 0x00002000 
b = temp; // b is now 0x00001000 

So am Ende dieser Anweisungen, die Werte des Zeigers vertauscht worden sind, das heißt, was auch immer a hinwies auf wird nun von b hingewiesen, und umgekehrt. Die Werte von was diese Zeiger zeigen, sind unverändert, es ist nur, dass jetzt ihre Speicheradressen von anderen Zeigern gehalten werden.

Um Ihre zweite Frage zu beantworten, können Sie keine void* dereferenzieren. Der Grund dafür ist, dass void keine Größe hat, also zu versuchen und zu dereferenzieren oder etwas zuzuordnen, das keine Größe hat, ist unsinnig. void* ist also eine Möglichkeit zu garantieren, dass Sie auf etwas zeigen können, aber Sie werden nie wissen, was etwas ist ohne weitere Informationen (daher die size Parameter für Ihre Routine).

Von dort können Sie mit dem Zeiger und der Größe der Daten, auf die der Zeiger zeigt, eine Routine wie memcpy verwenden, um die Daten, auf die ein Zeiger zeigt, in die Position zu verschieben, auf die ein Zeiger zeigt.

1

Sie sind in der Nähe.

Das Problem ist: Sie „Swapping“ nur Zeiger ein und b werden, die in der Funktion lokale Variablen sind.

Ich gehe davon außerhalb der Funktion Sie einige Variablen haben, nennen wir sie:

void *x = ...; 
void *y = ...; 

Wenn Sie anrufen:

swap(x, y, some_size); 

ein und b Punkte auf die gleichen Objekte wie x und y. Nun, wenn Sie tauschen, was ein und b Punkte zu, x und y noch zeigen auf, was sie wo vorher zeigen.

zu ändern, was Speicher x und y Punkte Sie einen Zeiger auf die x Variable passieren würde, so einen Zeiger auf einen Zeiger :)

Da Sie keine Funktionsdeklaration ändern Sie können nur den Inhalt des Speichers, wo x (und ein) und y (und b) Punkte tauschen. Einige Lösungen sind in anderen Antworten :) Im Allgemeinen memcpy ist was du willst.

2

Ich hatte eine ähnliche Frage für meine C-Kurs. Ich denke, memcopy ist wahrscheinlich am besten, aber Sie können dies auch versuchen:

typedef unsigned char * ucp; 

    void swap(void *a, void *b, int size){ 
     ucp c=(ucp)a; 
     ucp d=(ucp)b; 
     for(int i=0; i<size; i++){ 
     int temp=(int)c[i]; 
    c[i]=(int)d[i]; 
    d[i]=temp; 
     } 

    } 

Im Grunde, was das bedeutet gegossen wird, um beiden Zeiger auf einen unsigned char Zeigertyp. Dann inkrementieren Sie den Zeiger, der bei einem Zeichen ohne Vorzeichen jeweils um ein BYTE erhöht wird. Dann kopieren Sie im Grunde den Inhalt jedes einzelnen Bytes im Speicher. Wenn jemand dies korrigieren oder klären möchte, würde ich es auch schätzen.

0

Wir verwenden müssen nicht Memcpy für zwei Zeiger tauschen, Code folgende funktioniert gut (getestet für int * und char Swapping * Strings):

void swap(void **p, void **q) 
{ 
    void *t = *p; 
    *p = *q; 
    *q = t; 
} 
Verwandte Themen