Frage

Ich Schreibe C für nur wenige Wochen und haben nicht die Zeit genommen, um sorgen zu viel über mich malloc().Vor kurzem, obwohl, ein Programm von mir zurückgegebenen string glückliche Gesichter anstelle von true/false Werte, die ich hatte erwartet, dass es.

Wenn ich eine Struktur wie diese:

typedef struct Cell {
  struct Cell* subcells;
} 

und später dann initialisieren Sie es wie folgt

Cell makeCell(int dim) {
  Cell newCell;

  for(int i = 0; i < dim; i++) {
    newCell.subcells[i] = makeCell(dim -1);
  }

  return newCell; //ha ha ha, this is here in my program don't worry!
}

Bin ich bis zu Ende gehen den Zugriff auf glückliche Gesichter im Speicher abgelegt, irgendwo, oder vielleicht schreiben über die zuvor vorhandenen Zellen, oder was?Meine Frage ist, wie C-Speicher, wenn ich habe nicht wirklich malloc()ed, die richtige Menge an Speicher?Was ist der Standard?

War es hilfreich?

Lösung

Es gibt keinen Standardwert für den Zeiger.Ihre Zeiger, um was auch immer es Geschäfte derzeit.Als Sie noch nicht initialisiert ist es, die Zeile

newCell.subcells[i] = ...

Effektiv greift auf die unsicheren Teil des Speichers.Denken Sie daran, dass subcells[i] ist äquivalent zu

*(newCell.subcells + i)

Wenn auf der linken Seite enthält einige Müll, werden Sie am Ende hinzufügen i um eine garbage-Wert und Zugriff auf den Speicher an, der unsicheren Lage.Wie Sie richtig gesagt haben, müssen Sie initialisiert den Zeiger auf Punkt, um einige gültigen Speicherbereich:

newCell.subcells = malloc(bytecount)

Nachdem, welche Linie Sie Zugriff auf viele bytes.Mit Bezug auf andere Quellen von Speicher, es sind verschiedene Art von Speicher, der alle haben Ihren nutzen.Was die Art, die Sie erhalten, hängt davon ab, welche Art von Objekt Sie haben, und die Speicherklasse Sie dem compiler zu verwenden.

  • malloc gibt einen Zeiger auf ein Objekt, mit keine geben.Sie können einen Zeiger zeigen auf, dass die region von Speicher und die Art des Objekts effektiv werden die Art der Spitzen Objekt zu geben.Der Speicher wird nicht initialisiert, alle Wert-und der Zugang ist normalerweise langsamer.Objekte, die so gewonnen werden genannt allocated objects.
  • Sie können Objekte weltweit.Ihr Speicher wird auf null initialisiert.Für Punkte, erhalten Sie NULL-Zeiger, für Schwimmer-Sie bekommen einen ordentlichen null zu.Vertrauen Sie auf eine korrekte anfängliche Wert.
  • Wenn Sie lokale Variablen verwenden, aber die static storage class specifier, dann haben Sie die gleichen Anfangswert Regel für Globale Objekte.Der Speicher in der Regel zugeordnet ist, die gleiche Weise, wie Globale Objekte, aber das ist in keiner Weise eine Notwendigkeit.
  • Wenn Sie lokale Variablen ohne storage-class-specifier oder mit auto, dann die Variablen werden auf dem Stapel reserviert (obwohl nicht so definiert werden, die von der C dies ist, was Kompiler praktisch natürlich).Sie können nehmen Sie die Adresse in diesem Fall der compiler weglassen Optimierungen-so wie man es in Registern natürlich.
  • Lokale Variablen, die mit den storage-class specifier register, markiert sind in einer besonderen Lagerung.Als Ergebnis, werden Sie nicht nehmen, seine Adresse nicht mehr.In den letzten Compiler, gibt es normalerweise keine Notwendigkeit zu verwenden register mehr wegen Ihrer anspruchsvollen Optimierer.Wenn Sie wirklich Experte, dann erhalten Sie möglicherweise einige Leistung, wenn Sie es verwenden, obwohl.

Objekte verbunden, Lagerzeiten, die verwendet werden können, zeigen die verschiedenen Initialisierung Regeln (formal, Sie nur festlegen, wie lange mindestens der Objekte live).Objekte deklariert mit auto und register haben automatische Speicherdauer und sind nicht initialisiert.Sie müssen explizit initialisiert, wenn Sie Sie möchten, dass Sie enthalten einen bestimmten Wert.Wenn Sie das nicht tun, Sie enthalten, was der compiler nach Links auf den stack, bevor Sie begann Lebensdauer.Objekte, die verteilt werden, sind durch malloc (oder eine andere Funktion, die Familie, wie calloc) allokiert Speicher-Dauer.Ihre Lagerung ist nicht initialisiert, entweder.Eine Ausnahme ist, wenn mit calloc, in diesem Fall wird der Speicher auf null initialisiert ("echte" null.ich.e alle bytes 0x00, ohne Rücksicht auf eine NULL-Zeiger-Darstellung).Objekte, die deklariert sind, mit static und Globale Variablen statische Speicherdauer.Ihre Lagerung ist initialisiert auf null geeignete, für den jeweiligen Typ.Beachten Sie, dass ein Objekt nicht zu geben, aber der einzige Weg, um eine Typ-weniger-Objekt zugewiesenen Speicher.(Ein Objekt in C ist eine "region der Lagerung").

Also, was ist was?Hier ist die Feste code.Denn sobald Sie reserviert einen Speicherblock Sie können nicht mehr zurück, wie viele Elemente, die Sie zugewiesen, am besten ist es, immer zu speichern, die zählen irgendwo.Ich habe eingeführt übertragen dim die Struktur, dass wird die Zählung gespeichert.

Cell makeCell(int dim) {
  /* automatic storage duration => need to init manually */
  Cell newCell;

  /* note that in case dim is zero, we can either get NULL or a 
   * unique non-null value back from malloc. This depends on the
   * implementation. */
  newCell.subcells = malloc(dim * sizeof(*newCell.subcells));
  newCell.dim = dim;

  /* the following can be used as a check for an out-of-memory 
   * situation:
   * if(newCell.subcells == NULL && dim > 0) ... */
  for(int i = 0; i < dim; i++) {
    newCell.subcells[i] = makeCell(dim - 1);
  }

  return newCell;
}

Jetzt sehen die Dinge, wie dies für dim=2:

Cell { 
  subcells => { 
    Cell { 
      subcells => { 
        Cell { subcells => {}, dim = 0 }
      }, 
      dim = 1
    },
    Cell { 
      subcells => { 
        Cell { subcells => {}, dim = 0 }
      }, 
      dim = 1
    }
  },
  dim = 2
}

Beachten Sie, dass in C der Rückgabewert einer Funktion nicht benötigt wird, um ein Objekt sein.Keine Lagerung ist erforderlich, um zu existieren.Folglich sind Sie nicht erlaubt, es zu ändern.Beispielsweise ist Folgendes nicht möglich:

makeCells(0).dim++

Benötigen Sie eine "freie Funktion", die kostenlos ist der reservierte Speicher wieder.Da der Speicher der zugeteilten Objekte wird nicht automatisch freigegeben.Sie müssen rufen free zu befreien, dass der Speicher für jedes subcells Zeiger in Ihrem Baum.Es ist Links als übung für Sie zu schreiben, dass Sie sich :)

Andere Tipps

Kurze Antwort: Es ist für Sie nicht zugewiesen

.

Etwas längere Antwort: Der subcells Zeiger ist nicht initialisiert und zeigen kann überall . Das ist ein Fehler, und Sie sollte es nie zulassen.

längere Antwort noch: Automatische Variablen wird auf dem Stack zugeordnet werden globale Variablen vom Compiler zugewiesen und besetzen oft ein spezielles Segment oder im Heap sein. Globale Variablen werden standardmäßig auf Null initialisiert. Automatische Variablen hat keinen Standardwert (sie einfach den Wert im Speicher gefunden erhalten) und der Programmierer ist dafür verantwortlich, dass sie gute Startwerte haben (obwohl viele Compiler Hinweis versuchen Sie, wenn Sie vergessen).

Die newCell Variable in Sie funktionieren automatisch, und ist nicht initialisiert. Sie sollten diese pronto beheben. Entweder gibt newCell.subcells einen sinnvollen Wert sofort, oder es an NULL Punkt, bis Sie einen Platz für sie zuordnen. Auf diese Weise werden Sie eine Segmentierungsverletzung auslösen, wenn Sie zu dereferenzieren es versuchen, bevor etwas Speicher für sie zugeordnet werden.

Noch schlimmer ist, Sie sind wieder einen Cell nach Wert, sondern um es zu einem Cell * zuweisen, wenn Sie versuchen, das subcells Array zu füllen. Entweder einen Zeiger auf einen Objektspeicher zugeordnet oder den Wert auf eine lokal zugewiesene Objekt zuordnen.

Eine übliche Idiom hierfür wäre die Form so etwas wie

haben
Cell* makeCell(dim){
  Cell *newCell = malloc(sizeof(Cell));
  // error checking here
  newCell->subcells = malloc(sizeof(Cell*)*dim); // what if dim=0?
  // more error checking
  for (int i=0; i<dim; ++i){
    newCell->subCells[i] = makeCell(dim-1);
    // what error checking do you need here? 
    // depends on your other error checking...
  }
  return newCell;
}

obwohl ich links Sie ein paar Probleme .. zu schmieden

Und beachten Sie, dass Sie den Überblick über alle Bits des Speichers zu halten haben, die schließlich ausgeplant werden müssen ...

Alles, was nicht auf dem Heap (über malloc und ähnliche Anrufe) zugeordnet ist, auf dem Stapel zugeordnet, statt. Dieser Grund, in einer bestimmten Funktion erstellt alles ohne malloc'd wird zerstört werden, wenn die Funktion beendet. Dazu gehören Objekte zurückgegeben; wenn der Stapel Objekt abgewickelt wird, die zurückgegeben nach einem Funktionsaufruf, um Platz für sie auf dem Stapel durch die CLIP-Funktion aufgehoben kopiert wird.

Achtung: Wenn Sie ein Objekt zurückgeben möchten, die Zeiger auf andere Objekte darin hat, stellen Sie sicher, dass die Objekte auf dem Heap erstellt werden aufgezeigt, und noch besser, erstellen das Objekt auf die Haufen auch wenn es nicht beabsichtigt ist nicht die Funktion, in der, um zu überleben sie erstellt wird.

  

Meine Frage ist, wie funktioniert C Speicher zuweisen, wenn ich nicht wirklich malloc () haben ed die entsprechende Menge an Speicher? Was ist der Standard?

Um keinen Speicher zu reservieren. Sie müssen es explizit erstellen, die auf dem Stapel oder dynamisch.

In Ihrem Beispiel Unterzellen deuten auf einen undefined Standort, der ein Fehler ist. Ihre Funktion einen Zeiger auf eine Zelle Struktur irgendwann zurückkehren sollte.

  

Werde ich glückliche Gesichter im Speicher landen Zugriff irgendwo, oder vielleicht über bereits vorhandene Zellen zu schreiben, oder was?

Sie haben Glück, dass Sie ein glückliches Gesicht. )

; An einem dieser unglücklichen Tage, könnte es Ihr System sauber gewischt haben
  

Meine Frage ist, wie funktioniert C Speicher zuweisen, wenn ich nicht wirklich malloc () haben ed die entsprechende Menge an Speicher?

Es ist nicht. Doch was geschieht, wenn Sie definieren Sie newCell Zelle, die Subzellen Zeiger auf Müll Wert initialisiert wird. Welche a 0 sein kann (in diesem Fall, dass Sie einen Absturz bekommen würden) oder eine ganze Zahl groß genug, um es wie eine tatsächliche Speicheradresse zu suchen. Der Compiler, auf einem solchen Fall würde gerne holen, was Wert dort aufhält und es dir bringen.

  

Was ist der Standard?

Dies ist die Verhalten, wenn Sie Ihre Variablen nicht initialisiert werden. Und Ihre makeCell Funktion sieht ein wenig unterentwickelt.

Es gibt wirklich drei Abschnitte, in denen die Dinge zugeordnet werden können -. Daten, Stapel und Haufen

Im Fall, dass Sie erwähnen, wäre es auf dem Stapel zugeordnet werden. Das Problem mit etwas auf dem Stapel Zuweisung ist, dass sie für die Dauer der Funktion nur dann gültig sind. Sobald Ihre Funktion zurückkehrt, ist, dass der Speicher freigegeben. Also, wenn Sie einen Zeiger auf etwas auf dem Stapel reserviert zurückkehren, wird der Zeiger ungültig. Wenn Sie das eigentliche Objekt obwohl (keinen Zeiger) zurückkehren, wird eine Kopie des Objekts wird automatisch vorgenommen werden, um die anrufende Funktion zu verwenden.

Wenn Sie es als eine globale Variable erklärt hatten (zum Beispiel in einer Header-Datei oder außerhalb einer Funktion), es würde in dem Datenspeicherabschnitt zugeordnet werden. Der Speicher in diesem Abschnitt wird automatisch zugewiesen, wenn Ihr Programm startet und freigegeben automatisch, wenn es fertig ist.

Wenn Sie etwas auf dem Heap mit malloc () zuweisen, dass der Speicher gut ist, so lange wie Sie wollen, es zu benutzen - bis Sie kostenlos () aufrufen, an welcher Stelle es freigegeben wird. Dies gibt Ihnen die Flexibilität zuweisen und Speicher freigeben, wie Sie es brauchen (im Gegensatz zu mit Globals Gegensatz, wo alles nach vorne zugeordnet ist, und erst dann freigegeben, wenn Ihr Programm beendet).

Lokale Variablen werden „zugeordnet“ auf dem Stapel. Der Stapel ist eine vorab zugeordneten Speichermenge dieser lokalen Variablen zu halten. Die Variablen verlieren ihre Gültigkeit, wenn die Funktion beendet und wird von überschrieben werden, was auch immer als nächstes kommt.

In Ihrem Fall ist der Code, nichts zu tun, da es nicht Ihr Ergebnis zurückgibt. Außerdem ist ein Zeiger auf ein Objekt auf dem Stapel wird auch, wenn der Bereich verläßt ihre Gültigkeit, so dass ich denke, in Ihrem genauen Fall (Sie scheint eine verknüpfte Liste zu tun), müssen Sie malloc () verwenden.

Ich werde so tun, als ich den Computer hier bin, diesen Code zu lesen ...

typedef struct Cell {
  struct Cell* subcells;
}

Das sagt mir:

  • Wir haben einen Strukturtyp namens Zelle
  • Sie enthält einen Zeiger namens Subzellen
  • Der Zeiger auf etwas vom Typ struct Zelle sein sollte

Es ist mir nicht sagen, ob der Zeiger auf eine Zelle oder eine Anordnung von Zellen geht. Wenn eine neue Zelle durchgeführt wird, ist der Wert dieses Zeigers undefiniert, bis ein Wert zugewiesen wird. Es ist Bad News Zeiger zu verwenden, bevor sie zu definieren.

Cell makeCell(int dim) {
  Cell newCell;

Neue Zelle Struktur, mit einem undefinierten Subzellen Zeiger. All dies tut, ist einen kleinen Teil des Speichers reservieren werden newCell genannt, die die Größe einer Zelle Struktur ist. Es ist nicht die Werte ändern, die in diesem Speicher waren -. Sie könnte alles sein

  for(int i = 0; i < dim; i++) {
    newCell.subcells[i] = makeCell(dim -1);

Um newCell.subcells zu bekommen [i], eine Berechnung durchgeführt wird aus Subzellen von i zu kompensieren, dann ist das dereferenzierte . Konkret bedeutet dies, wird der Wert aus dieser Speicheradresse gezogen wird. Nehmen wir zum Beispiel, i == 0 ... Dann würden wir die Subzellen Zeiger selbst werden dereferencing (kein Offset). Da Subzellen nicht definiert ist, könnte es alles sein. Buchstäblich alles! So würde dies irgendwo für einen Wert bitten, von völlig zufällig im Speicher. Es gibt keine Garantie für irgendetwas mit dem Ergebnis. Es kann etwas drucken, kann es zum Absturz bringen. Es sollte auf jeden Fall nicht durchgeführt werden.

  }

  return newCell;
}

Jedes Mal, wenn Sie mit einem Zeiger arbeiten, ist es wichtig, sicherzustellen, dass es auf einen Wert, bevor Sie dereferenzieren eingestellt wird. Ermutigen Sie Ihre Compiler Sie alle Warnungen zu geben, es kann viele moderne Compiler diese Art der Sache zu fangen. Sie können auch Zeiger cutesy Standardwerte wie 0xDEADBEEF geben (yup! Das ist eine Zahl in Hexadezimal, es ist nur auch ein Wort, so sieht es komisch), so dass sie abheben. (Das% p-Option für printf ist hilfreich für die Zeiger angezeigt wird, als eine grobe Form von Debugging. Debugger-Programme auch sie ganz gut zeigen kann.)

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