Frage

Das wird wie eine dumme Frage klingen, aber ich bin immer noch C zu lernen, so wenden Sie sich bitte mit mir tragen. :)

Ich bin auf Kapitel 6 von K & R (structs) und damit weit über das Buch hat großen Erfolg gesehen. Ich beschloss, mit structs ziemlich schwer zu arbeiten, und deshalb viel Arbeit früh im Kapitel mit den Punkt und rect Beispiele taten. Eines der Dinge, die ich war die Änderung der canonrect Funktion ausprobieren wollte (2. Auflage, S. 131) arbeiten über Zeiger und daher zurückkehren void.

Ich habe diese Arbeit, sondern lief in einem Schluckauf Ich hatte gehofft, euch mir helfen könnte aus mit. Ich wollte ein temporäres Rechteck-Objekt erstellen canonRect, führen seine Änderungen, dann neu zuweisen den Zeiger in das temporäre Rechteck übergeben wird, wodurch der Code vereinfacht.

Allerdings, wenn ich das tun, wird das rect nicht ändern. Stattdessen finde ich mich manuell die Felder der rect repopulating ich in vergangen bin, die Arbeit macht.

Der Code folgt:

#include <stdio.h>

#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))

struct point {
    int x;
    int y;
};

struct rect {
    struct point lowerLeft;
    struct point upperRight;
};

// canonicalize coordinates of rectangle
void canonRect(struct rect *r);

int main(void) {
    struct point p1, p2;
    struct rect r;

    p1.x = 10;
    p1.y = 10;
    p2.x = 20;
    p2.y = 40;
    r.lowerLeft = p2; // note that I'm inverting my points intentionally
    r.upperRight = p1;

    printf("Rectangle, lower left: %d, %d; upper right: %d %d\n\n", 
        r.lowerLeft.x, r.lowerLeft.y, r.upperRight.x, r.upperRight.y);

    // can't pass a pointer, only a reference. 
    // (Passing pointers results in illegal indirection compile time errors)
    canonRect(&r); 
    printf("Rectangle, lower left: %d, %d; upper right: %d %d\n\n", 
        r.lowerLeft.x, r.lowerLeft.y, r.upperRight.x, r.upperRight.y);    
}

void canonRect(struct rect *r) {
    struct rect temp;
    temp.lowerLeft.x = min(r->lowerLeft.x, r->upperRight.x);
    temp.lowerLeft.y = min(r->lowerLeft.y, r->upperRight.y);
    temp.upperRight.x = max(r->lowerLeft.x, r->upperRight.x);
    temp.upperRight.y = max(r->lowerLeft.y, r->upperRight.y);

    r = &temp; // doesn't work; my passed-in rect remains the same

    // I wind up doing the following instead, to reassign all 
    // the members of my passed-in rect
    //r->lowerLeft = temp.lowerLeft;
    //r->upperRight = temp.upperRight;
}

Also hier sind die Fragen:

  1. Warum r = &temp; nicht? (I denken ist dies, weil ich in einem Referenz anstelle eines Zeigers übergeben;? Bin ich richtig in der Annahme, dass Verweise nicht veränderbar sind, aber Zeiger sind)
  2. Warum kann ich ein illegalen indirection Fehler bei der Kompilierung, wenn ich versuche, in einem Zeiger zu übergeben canonRect? (IE, wenn ich hatte canonRect(*r); in main().)

Ich vermute, ich weiß schon die Antwort auf # 1, aber # 2 perplex ich - ich dachte, es war legal Zeiger passiert um

.

Wie auch immer ... Sie bitte die C newb vergeben.

War es hilfreich?

Lösung

Ich denke, was Sie tun möchten, ist dies:

void canonRect(struct rect *r) {
    struct rect temp;
    temp.lowerLeft.x = min(r->lowerLeft.x, r->upperRight.x);
    temp.lowerLeft.y = min(r->lowerLeft.y, r->upperRight.y);
    temp.upperRight.x = max(r->lowerLeft.x, r->upperRight.x);
    temp.upperRight.y = max(r->lowerLeft.y, r->upperRight.y);

    *r = temp; 
}

In dem obigen Code, den Sie * r setzen die vom Typ rect zu Temp ist die vom Typ rect ist.

Re 1: Wenn Sie ändern möchten, welche r zeigen werden Sie einen Zeiger auf einen Zeiger verwenden müssen. Wenn das wirklich das, was Sie wollen (siehe oben, es ist nicht wirklich das, was Sie wollen), dann würden Sie machen müssen, um sicher, dass es etwas auf dem Heap zu verweisen. Wenn Sie es etwas nicht erstellt mit ‚neuen‘ oder malloc zeigen, dann wird es außerhalb des Bereichs fallen, und Sie werden in den Speicher gerichtet sein, die nicht mehr für diese Variable verwendet wird.

Warum funktioniert der Code Arbeit mit r = & Temp?

Da r von rect * Typ ist. Das bedeutet, dass r eine Variable, die eine Speicheradresse hält, wer Speicher eine rect enthält. Wenn Sie ändern, was r zeigen, das ist in Ordnung, aber das bedeutet nicht die in Variable übergeben ändern.

Re 2: * wenn nicht in einer Typdeklaration ist der dereferenzieren unärer Operator. Dies bedeutet, dass es Nachschlag, was in der Adresse des Zeigers ist. Also von * r vorbei Sie übergeben keinen Zeiger überhaupt. In Gesicht da r ist kein Zeiger, dass ungültige Syntax ist.

Andere Tipps

Es ist auch erwähnenswert, Ihre Variable ‚struct rec Temp‘ out of scope gehen wird, sobald diese Methode canonRect beendet und Sie werden zeigen Speicher auf ungültig.

Es klingt wie Sie den 'dereferenzieren' Operator (*) mit der 'Adresse' Operator (&) sind verwirrend.

Wenn Sie schreiben &r, die die Adresse von r und gibt einen Zeiger auf r bekommt (ein Zeiger ist nur eine Speicheradresse einer Variablen). So sind vorbei Sie wirklich einen Zeiger in die Funktion.

Wenn Sie *r schreiben, versuchen Sie zu dereferenzieren r. Wenn r ein Zeiger ist, dass der Wert wird wieder, dass r zeigt. Aber r ist kein Zeiger, es ist ein rect, so dass Sie einen Fehler.

Um die Dinge noch verwirrender zu machen, wird der * Charakter auch verwendet, wenn die Maus Variablen zu deklarieren. In dieser Funktion Erklärung:

void canonRect(struct rect *r) {

r deklariert einen Zeiger auf eine struct rect zu sein. Dies ist ganz anders als mit * wie folgt aus:

canonRect(*r); 

In beiden Fällen das Zeichen * bedeutet etwas ganz anderes.

Zuerst K & R c kein Konzept der „Referenzen“ hat, nur Zeiger. Der & Operator bedeutet "nehmen Sie die Adresse".


Zweitens ist die r in cannonRect() eine lokale Variable, und ist nicht die r in main(). Ändern, wo die lokalen r Punkte beeinflussen nicht die r in der Aufruf-Routine.


Schließlich, wie bereits erwähnt die lokale struct rect auf dem Stapel zugeordnet ist, und geht out-of-scope am Ende Klammer,

Sie möchten vielleicht auf die verschiedenen Möglichkeiten lesen, Parameter können (konzeptuell) an Funktionen übergeben werden. C ist Call-by-Wert , so dass, wenn Sie Ihren Pass Zeiger auf eine rect in die Funktion eine Kopie des Zeigers ist vorbei. Alle Änderungen, die Funktion auf den Wert r macht direkt (nicht indirekt) werden den Anrufer nicht sichtbar sein.

Wenn Sie die Funktion die Anrufer mit einer neuen Struktur zu schaffen, dann gibt es zwei Möglichkeiten, es zu tun:   1. Sie können eine rect zurück:   2. Sie können einen Zeiger auf einen Zeiger auf eine rect passieren in:

Der erste Weg wäre natürlich:

struct rect* canonRect(struct rect* r)
{
  struct rect* cr = (struct rect*) malloc(sizeof(struct rect));
  ...
  return cr;
}

Der zweite Weg wäre:

void canonRect(struct rect** r)
{
  *r = (struct rect*) malloc(sizeof(struct rect));
}

und der Anrufer würde dann verwendet werden:

   canonRect(&r);

Aber verliert der Anrufer ursprüngliche Zeiger hatten, und man würde vorsichtig sein, nicht structs undicht wird.

Unabhängig davon, welche Technik Sie verwenden, müssen die Funktionsspeicher für die neue Struktur auf dem Heap malloc zuzuweisen. Sie können den Platz auf dem Stapel nicht zuordnen, indem nur eine Struktur erklärt, weil das Speicher ungültig wird, wenn die Funktion zurückgibt.

  

2.Why könnte ich einen illegalen indirection Compiler-Fehler, wenn ich in einem Zeiger auf canonRect passieren versuchen? (IE, wenn ich habe canonRect (* r.), In main ())

Da ist es nicht der Zweck der Zeiger .

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top