2010-11-21 15 views
21

ich immer in Java programmiert haben, was wahrscheinlich ist, warum ich so verwirrt bin dies etwa:ich über malloc sehr verwirrt bin() und calloc() auf C

In Java erkläre ich einen Zeiger:

int[] array 

und initialisieren oder es etwas Speicher zuweisen:

int[] array = {0,1,0} 
int[] array = new int[3] 

nun in C, es ist alles so verwirrend. Zuerst dachte ich, es war so einfach wie erklärt es:

int array[] 

und es zu initialisieren oder es etwas Speicher zuweisen:

int array[] = {0,1,0} 
int array[] = malloc(3*sizeof(int)) 
int array[] = calloc(3,sizeof(int)) 

Es sei denn, ich bin falsch, alle der oben genannten entspricht Java-C , Recht?

Dann habe ich heute traf einen Code, in dem ich folgendes gefunden:

pthread_t tid[MAX_OPS]; 

und einige Zeilen darunter, ohne jede Art von Initialisierung ...

pthread_create(&tid[0],NULL,mou_usuari,(void *) 0); 

Überraschenderweise (zumindest Ich), der Code funktioniert! Zumindest in Java würde das eine nette "NullPointerException" ergeben!

Also, um:

  1. Am korrigiere ich mit all den Java-C "Übersetzungen"?

  2. Warum funktioniert dieser Code?

  3. Gibt es einen Unterschied zwischen der Verwendung von malloc(n*sizeof(int)) und calloc(n,sizeof(int))?

Vielen Dank im Voraus

Antwort

32

Sie können einem Array keinen Speicher zuweisen. Ein Array hat eine feste Größe für die gesamte Lebensdauer. Ein Array kann niemals null sein. Ein Array ist kein Zeiger.

malloc gibt die Adresse an einen Speicherblock zurück, der für das Programm reserviert ist. Sie können das Array (das ist der Speicherblock) nicht "zuweisen", aber Sie können die Adresse dieses Speicherblocks in einem Zeiger speichern: Zum Glück wird Array-Subskription durch Zeiger definiert - so können Sie "Zeiger wie Arrays" verwenden , z.B

int *ptr = malloc(5 * sizeof *ptr); 
ptr[2] = 5; // access the third element "of ptr" 
free(ptr); // always free at the end 

Wenn Sie ein Array ohne eine Größe (d.h. array[]) erklären, bedeutet es einfach, die Größe der Anordnung von der Initialisiererliste bestimmt wird. Das ist

int array[] = {1, 2, 3, 4, 5}; // is equal to 
int array[5] = {1, 2, 3, 4, 5}; 

Der Versuch, ein Array ohne eine Größe und ohne einen Initialisierer zu deklarieren, ist ein Fehler.


Der Code pthread_t tid[MAX_OPS]; deklariert ein Array tid vom Typ namens pthread_t und der Größe MAX_OPS.

Wenn das Array über automatischen Speicher verfügt (d. H. Deklaration ist innerhalb einer Funktion und nicht statisch, nicht global), dann hat jedes der Array-Elemente einen unbestimmten Wert (und es würde zu undefiniertem Verhalten führen, einen solchen Wert zu lesen). Glücklicherweise führt der Funktionsaufruf nur die Adresse des ersten Elements des Arrays als ersten Parameter aus und initialisiert sie wahrscheinlich (das Element) innerhalb der Funktion.


Die Differenz von calloc und malloc ist, dass der Speicherblock, calloc kehrt auf Null initialisiert wird.Das ist;

int *ptr = calloc(5, sizeof *ptr); 
// is somewhat equal to 
int *ptr = malloc(5 * sizeof *ptr); 
memset(ptr, 0, 5 * sizeof *ptr); 

Der Unterschied zwischen

int *ptr = malloc(5 * sizeof *ptr); 
// and 
int array[5]; 

ist, dass array dynamischen Speicher hat, (wird auf dem Stapel gespeichert ist), und wird „freigegeben“, nachdem es den Bereich verläßt. ptr jedoch (wird auf Heap gespeichert), wird dynamisch zugewiesen und muss vom Programmierer free d sein.

+1

Der 1. Absatz hat einige gefährlich zweideutige Behauptungen. Der OP versuchte nicht, Speicher einem Array zuzuordnen, er versuchte, ein (void *), die Rückkehr von malloc() zu einem Array zuzuweisen, und wenn dieses Array ein int * Array [i] gewesen wäre, wahrscheinlich in einem Für {} -Schleife würde es gut funktionieren und ist die Grundlage dafür, wie dynamische, mehrdimensionale Arrays vom Heap zugewiesen werden. Außerdem unterstützt C99 Arrays variabler Größe, die vom Stack zugewiesen wurden, eine Funktion, die einige C-Programmierer verwenden, am liebsten alloca(), mich eingeschlossen. http://stackoverflow.com/q/1018853/2548100 – user2548100

+1

calloc() ist ziemlich genau memset (malloc (n * mysize), 0, (n * mysize)). Insbesondere weil C nullterminierte Strings verwendet, ist calloc() sehr nützlich, besonders beim Anzeigen von Strings in einem Debugger, der die Zeichenfolge normalerweise nur bis zum Nullterminator anzeigt. Wenn Sie nur mit C auskommentieren, verwenden Sie Calloc anstelle von malloc, es wird Sie davor bewahren, eine Menge nicht abgeschlossener C-String-Fehler zu machen, die Ihr Programm zum Absturz bringen können und wahrscheinlich zum Absturz bringen werden. Verwenden Sie calloc() nur für Produktion/Release-Code, wenn Sie den Puffer/Array/Vektor tatsächlich zu (_int8) 0 initialisieren müssen. – user2548100

+7

Um nur die Dinge zu ergänzen, und ein Array-IS ist ein Zeiger. Tatsächlich ist jeder Array-Name in C genau, genau ein Zeiger auf die Basis des ersten Bytes des ersten Objekts im Array, und nichts mehr. Für Leute, die aus Java kommen.Net usw. ist es hilfreich zu wissen, dass C den Typ der Objekte/Variablen vollständig getrennt von dem Speicher hält, der ihnen zugewiesen wurde. Aus diesem Grund können Sie einen Zeiger als int darstellen, UNIONs erstellen usw. Sehr, sehr flexibel, aber gefährlich für Anfänger. Wenn Sie ein int-Array zuweisen, wird nur Speicherplatz an einem Speicherort verwendet. Sie können alles, was Sie mögen, in diesen Speicher legen. – user2548100

-2

Ich finde es hilfreich, wenn Sie in C programmieren (im Gegensatz zu C Gegensatz ++) * array, um anzuzeigen, ausdrücklich, sich daran zu erinnern, dass es ein Zeiger ist, die bewegt werden kann. So würde Ich mag durch Umformulierung Ihrem Beispiel zu starten, wie:

int array[] = {0,1,2}; 
int *array = malloc(3*sizeof(int)); 
int *array = calloc(3,sizeof(int)); 

Die erste deutlich macht, dass es etwas namens Array ist, die zu einem Speicherblock zeigt, der eine 0, 1 und 2. Array enthält, kann‘ Man darf nicht irgendwohin versetzt werden.

Ihr nächster Code: pthread_t tid [MAX_OPS];

in der Tat dazu führen, einen Array mit sizeof (pthread_t) * MAX_OPS zugeordnet werden. Aber es weist keinen Zeiger namens * tid zu. Es gibt eine Adresse der Basis des Arrays, aber Sie können sie nicht anderswo verschieben.

Der Typ pterad_t ist eigentlich eine Abdeckung für einen Zeiger. So tid oben ist eigentlich ein Array von Zeigern. Und sie sind alle statisch zugewiesen, aber sie sind nicht initialisiert.

Die pthread_create übernimmt die Position am Anfang des Arrays(), die ein Zeiger ist, und reserviert einen Speicherblock, um die PThread-Datenstruktur zu halten. Der Zeiger wird gesetzt, um auf die neue Datenstruktur zu zeigen, und die Datenstruktur wird zugewiesen.

Ihre letzte Frage --- der Unterschied zwischen malloc(n*sizeof(int)) und calloc(n,sizeof(int)) ist, dass die später jedes Byte auf 0 initialisiert, während die erste nicht.

+0

Also, wenn ich erkläre: int array [] es hat seinen Speicher bereits zugeordnet? Es ist dann dasselbe als den Zeiger zu deklarieren und dann malloc zu benutzen? danke nochmal – bluehallu

+0

@Hallucynogenyc: Nein, es ist nicht das Gleiche. int array [size] wird vom Stapel zugewiesen. int array [] = malloc() steht auf dem Heap. – Puppy

+2

In C ist die erste dieser 3 Zeilen einfach * nicht gültig *. Es wird nicht kompiliert. –

0

2 - Dieses Array-Deklaration ist statisch:

pthread_t tid[MAX_OPS]; 

Wir brauchen keine Speicherblock, statt dynamische Zuordnung zuzuordnen:

pthread_t *tid = (pthread_t *)malloc(MAX_OPS * sizeof(pthread_t)); 

Vergessen Sie nicht, den Speicher frei:

3 - Der Unterschied zwischen malloc und calloc besteht darin, dass calloc einen Speicherblock für ein Array reserviert und initialisiert alle seine Bits auf 0.

+0

Also, was wäre der Unterschied zwischen dem ersten und dem zweiten? Und warum werfen Sie einen Zeiger auf die zweite Zeile? Entschuldigung, wenn ich mich dumm anführe, aber das ist alles neu für mich ... – bluehallu

+0

Ok, ich habe gerade gesehen warum du Casting machst. Gibt es noch einen praktischen Unterschied zwischen der ersten und der zweiten Zeile, von der Sie den Zeiger auf alles verschieben können, was Sie wollen? – bluehallu

+0

Eine statische Deklaration ist sicherer als eine dynamische, aber Sie können Ihren Speicherblock nicht neu zuweisen, um seine Größe zu ändern. –

1

C bietet statische Speicherzuweisung sowie dynamische - Sie können Arrays aus dem Stapel oder im ausführbaren Speicher (verwaltet vom Compiler) zuordnen. Dies ist genauso wie in Java, Sie können einen Int auf dem Stapel oder einen Integer auf dem Heap zuweisen. Arrays in C sind genau wie jede andere Stack-Variable - sie gehen außerhalb des Gültigkeitsbereichs usw. In C99 können sie auch eine variable Größe haben, obwohl sie nicht in der Größe geändert werden können. Der Hauptunterschied zwischen {} und malloc/calloc besteht darin, dass {} -Arrays statisch zugewiesen werden (müssen nicht freigegeben werden) und automatisch für Sie initialisiert werden, während malloc/calloc-Arrays explizit freigegeben werden müssen und Sie sie initialisieren müssen ausdrücklich. Aber natürlich gehen Malloc/Calloc-Arrays nicht außerhalb des Geltungsbereichs und Sie können (manchmal) sie realloc().

+1

Die Arrays sind nur statisch, wenn sie außerhalb einer Funktion oder explizit als statisch markiert sind. ansonsten sind sie automatisch –

3

Sie fehlen drei sehr einfach und zu straffen C Themen (und irreführend!):

  • der Unterschied zwischen Arrays und Zeiger
  • der Unterschied zwischen statischen und dynamischen Zuordnung
  • die Differenz von Variablen deklarieren auf dem Stapel oder auf dem Heap

Wenn Sie int array[] = malloc(3*sizeof(int)); schreiben Sie würde einen Kompilierungsfehler erhalten (so etwas wie 'Bezeichner': Array-Initialisierung benötigt geschweifte Klammern).

Dies bedeutet, dass ein Array erklärt erlaubt nur statische Initialisierung:

  • int array[] = {1,2,3}; dass 3 zusammenhängende ganze Zahlen auf dem Stapel behält;
  • int array[3] = {1,2,3}; das ist das gleiche wie das vorherige;
  • int array[3];, die noch drei zusammenhängende Zahlen auf dem Stapel behält, sie jedoch nicht initialisiert werden (der Inhalt zufällige Müll sein)
  • int array[4] = {1,2,3}; wenn die Initialisiererliste nicht alle Elemente initialisieren, der Rest auf 0 gesetzt (C99 §6.7.8/19): in diesem Fall werden Sie bekommen 1,2,3,0

Beachten Sie, dass diese Fälle in alles, was Sie sind nicht neue Zuweisung von Speicher, den Sie verwenden nur die Erinnerung bereits an den Stack gebunden. Sie würden ein Problem nur ausführen, wenn der Stapel voll ist (rate mal, es wäre ein Stapelüberlauf). Aus diesem Grund wäre die Deklaration int array[]; falsch und bedeutungslos.

Um malloc zu verwenden, müssen Sie einen Zeiger deklarieren: int* array.

Wenn Sie schreiben int* array = malloc(3*sizeof(int)); Sie tatsächlich tun, drei Operationen:

  1. int* array teilt dem Compiler einen Zeiger auf den Stapel (eine Integer-Variable, die eine Speicheradresse enthält) zu reservieren
  2. malloc(3*sizeof(int)) auf dem Heap reserviert 3 zusammenhängende ganze Zahlen und gibt die Adresse der ersten
  3. = weist Kopien, die Rückgabewert (die Adresse der ersten Ganzzahl, die Sie zugewiesen haben) auf Ihre Zeigervariable

Also, zu kommen auf Ihre Frage zurück:

pthread_t tid[MAX_OPS]; 

ist ein Array auf dem Stapel, so braucht es nicht zugeteilt werden (wenn MAX_OPS ist, sagen wir, 16 dann auf dem Stack wird Die Anzahl der zusammenhängenden Bytes, die für 16 pthread_t benötigt werden, ist reserviert. Der Inhalt dieses Speichers ist Müll (Stapelvariablen werden nicht auf Null initialisiert), aber pthread_create gibt einen Wert in seinem ersten Parameter zurück (einen Zeiger auf eine Variable pthread_t) und ignoriert alle vorherigen Inhalte, so dass der Code in Ordnung ist.

+4

für das 'int-Array [4]', sie sind alle initialisiert. Wenn die Initialisierungsliste nicht alle Elemente initialisiert, wird der Rest auf 0/NULL gesetzt (C99 §6.7.8/19). –

+0

Das ist verwirrend; "Heap" und "dynamische Zuweisung" beziehen sich auf die gleiche Sache. "Statische Initialisierung" bedeutet das Initialisieren von statischen Variablen, was bei sogenannten "Stack" -Variablen nicht der Fall ist. Die Art der Zuweisung in "int array [3];" innerhalb einer Funktion ist "automatische Zuweisung" (oder informell "Stack", einige Systeme haben keinen Stack), nicht "statisch". –

Verwandte Themen