2010-04-12 3 views
16

Ich habe einen Segmentierungsfehler im folgenden Code, aber nachdem ich es in Zeiger auf Zeiger geändert habe, ist es in Ordnung. Kann mir irgendjemand irgendeinen Grund geben?Warum Zeiger auf Zeiger erforderlich ist, um Speicher in Funktion zu reservieren

void memory(int * p, int size) { 
    try { 
     p = (int *) malloc(size*sizeof(int)); 
    } catch(exception& e) { 
     cout<<e.what()<<endl; 
    } 
} 

es nicht in der Hauptfunktion als Schlag

int *p = 0; 
memory(p, 10); 

for(int i = 0 ; i < 10; i++) 
    p[i] = i; 

jedoch nicht funktioniert, funktioniert es so.

void memory(int ** p, int size) {    `//pointer to pointer` 
    try{ 
     *p = (int *) malloc(size*sizeof(int)); 
    } catch(exception& e) { 
     cout<<e.what()<<endl; 
    } 
} 

int main() 
{ 
    int *p = 0; 
    memory(&p, 10);  //get the address of the pointer 

    for(int i = 0 ; i < 10; i++) 
     p[i] = i; 

    for(int i = 0 ; i < 10; i++) 
     cout<<*(p+i)<<" "; 

    return 0; 
} 
+7

Wie Malloc nie werfen wird, sind diese Versuche Blöcke sinnlos. –

+0

Diese try-Blöcke sind nicht gültig, wenn dies C ist. Ist das eigentlich C++? Wenn dies der Fall ist, müssen sich die Tags ändern. –

+0

@Fred, die Frage ist relevant für beide C, auch wenn das Snippet C++ ist, wie Sie hingewiesen haben. Ich habe das C++ - Tag hinzugefügt – hhafez

Antwort

50

Weil Sie wollen einen Zeigerwert erhalten zurück von den Vorgängen in der Funktion. malloc reserviert Speicher und gibt Ihnen eine Adresse für diesen Speicher.

In Ihrem ersten Beispiel speichern Sie diese Adresse in der lokalen Argumentvariable p, aber da es nur das Argument ist, kehrt es nicht zum Hauptprogramm zurück, weil C/C++ pass-by-value ist standardmäßig - auch für Zeiger.

Main  Function  malloc 

    p   p   allocated 
+---+  +---+   
| 0 |  | 0 |   A 
+---+  +---+ 

becomes... 

    p   p   allocated 
+---+  +---+   
| 0 |  | ------------> A 
+---+  +---+ 

und damit als Haupt p liest, wird es 0, nicht A.

In Ihrem Arbeits Code, der Zeiger folgen auf eine Adresse übergeben, und diese Adresse gibt Ihnen die Position der Zeigervariable im Hauptprogramm. Sie aktualisieren den Zeigerwert an dieser Adresse, woraufhin das Hauptprogramm den Wert von als seinen Speicherort suchen kann - und somit die von malloc zurückgegebene Adresse an das Hauptprogramm zur Verwendung zurückgibt.

Main  Function  malloc 

    p   p   allocated  
+---+  +---+   
| 0 |<------- |   A 
| |  | | 
+---+  +---+ 

becomes... 

    p   p   allocated  
+---+  +---+   
| |<------- |   
| ----------------------> A 
+---+  +---+ 

und somit, wenn der Haupt p liest, wird es A.

+13

+1 für die ASCII-Kunst. 8v) –

+2

ASCII-Kunst kann ehrlich Spaß manchmal sein ... – Amber

+0

verdammt ... ich würde schöne Zeigerdiagramme machen ... nicht mehr – Polaris878

7

einen Zeiger speichert die Adresse, an der die Daten gespeichert sind. Wenn Sie einen Zeiger auf eine Funktion übergeben, geben Sie ihr die Adresse die Daten. Hier haben Sie jedoch keine Adresse für die Daten, bis Sie malloc aufrufen. Stattdessen müssen Sie stattdessen die Adresse den Zeiger übergeben (d. H. Zeiger auf Zeiger). Dies erlaubt memory, die Adresse des Zeigers p zu nehmen und p so einzustellen, dass er auf den Bereich des Speichers zeigt, den er für die Daten zuweist.

+0

Viel klarer als Dav's, obwohl es scheint, dass Sie beide die gleiche Sache sagen. Sie bekommen beide eine Stimme. :) – Dustin

1

Das erste Beispiel funktioniert nicht, da der Zeigerparameter nicht der Zeiger in main ist, sondern nur den gleichen Wert hat.

0

Sie nicht einen Zeiger auf Zeiger zu verwenden, benötigen aber einen referenzierten Zeiger, dh ein * & nicht nur *

3

In C, Sie haben nur Pass-by-Wert. So erhält Ihre Funktion memory() ihre eigene local-only Kopie von p. malloc inside memory() weist nur der Kopie von p zu, die für die Funktion lokal ist. Wenn memory() zu main() zurückkehrt, ist die Kopie von p aus main unverändert. In C++, können Sie dies lösen, indem Pass-by-Referenz verwendet wird, wie folgt aus:

void memory(int*& p, int size)

in C, verwenden Sie doppelte Zeiger ähnliche Ergebnisse zu erzielen.

+1

Sollte '* &' sein. (Von rechts gelesen. Das ist einer der Gründe, warum ich den Raum anders herum gestellt hätte: 'int * & p' (' int * 'ist der Typ, auf den du Bezug nimmst) :) – UncleBens

+0

Wäre es nicht be 'int * & 'um einen Verweis auf einen Zeiger auf ein int zu bezeichnen? Ihr Codebeispiel ist 'int & *', was ein Zeiger auf einen Verweis auf einen int ist, der den Zweck einer Referenz vereitelt, wenn Sie einen Zeiger auf eine Referenz übergeben. Oder vielleicht irre ich es ...? – Dustin

+0

@UncleBens, Dustin: Das war ein Tippfehler, schöner Fang. Ich habe den Space & * neben den Typ verschoben. – kbyrd

2

In Ihrem ersten Aufruf Speicher:

void memory(int * p, int size) 

Erkennen, dass Sie ein VALUE zu Speicher() über, nicht eine Adresse. Daher übergeben Sie den Wert 0 an Speicher(). Die Variable p ist nur eine Kopie von was auch immer Sie passieren in ... in den gleichen Wert enthält aber tut NICHT auf die gleiche Adresse ...

In Ihrer zweiten Funktion, Sie sind das Bestehen der ADDRESS von Ihr Argument ... Stattdessen zeigt auf die Adresse Ihrer Variablen, anstatt nur eine Kopie Ihrer Variablen zu sein.

Also, wenn Sie malloc nennen wie so:

*p = (int *) malloc(size*sizeof(int)); 

Sie zuweisen Rückkehr des malloc auf den Wert der Variablen, dass p Punkte.

So ist Ihr Zeiger dann außerhalb des Speichers() gültig.

0

Sie benötigen einen Zeiger auf den Zeiger, da Sie den Wert des neu zugewiesenen Zeigers zurückgeben müssen.

gibt drei Möglichkeiten, um diesen Wert zurückzukehren (2, wenn Sie C verwenden):

  • einen Zeiger verwenden, hier ist es ein Zeiger ist ein Verweis auf den Zeiger
  • verwenden, hier ist es ein Verweis auf Zeiger
  • den Rückgabewert der Funktion verwenden, so Speicher einen int machen zurückgeben * statt Leere

der dritte Weg, meine Vorliebe hat auf jeden Fall.

(und nicht, ich gebe nicht zu, Sie könnten auch eine globale, es ist kein vierter Weg, sondern ein Horror).

-1

ich den Code korrigiert .. lesen Sie den Kommentar und alles wird klar sein ..

#include<iostream> 
#include<conio.h> 
#include<exception> 

using namespace std; 


void memory(int* p, int size) {    //pointer to pointer` not needed 
    try{ 
     p = new int[size] ; 
    } catch(bad_alloc &e) { 
     cout<<e.what()<<endl; 
    } 
} 

int main() 
{ 
    // int *p = 0; wrong .. no memory assigned and then u are passing it to a function 
    int *p; 
    p = new int ; // p = malloc(sizeof(int)); 
    /*before using a pointer always allocate it memory else 
    you ll get frequent system crashes and BSODs*/ 
    memory(p, 10);  //get the address of the pointer 

    for(int i = 0 ; i < 10; i++) 
     p[i] = i; 

    for(int i = 0 ; i < 10; i++) 
     cout<<*(p+i)<<" "; 

    getch();  
    return 0; 
} 
0

Speicher (p, 10); // Erhalte die Adresse des Zeigers

dies sendet nur den p-Wert nicht die Adresse des p. es sendet (* p). Wenn die Adressen von p 123 und ihr Wert 50 sind, senden sie 50 an die Funktion.

und bei der Speicherfunktion macht es einen neuen Zeiger mit neuer Adresse wie 124 und es enthält 50; und es wird den Speicher zuweisen und den Start des zugewiesenen Speichers 124 nicht 123 schreiben, so dass p am Haupt noch 50 enthält. Also hast du nichts gemacht !. Sie können dies mit diesem Code steuern.

 #include<iostream> 
    #include<conio.h> 
    #include<exception> 

    using namespace std; 


    void memory(int* p, int size) {    //*************pointer to pointer` is a must********** 
     try{ 
      p = new int[size] ; 
      p[0]=100; 
     } catch(bad_alloc &e) { 
      cout<<e.what()<<endl; 
     } 
    } 

    int main() 
    { 
     int *p = 0; ******you can do you should do this******* 
     p = new int ; 
/* p = malloc(sizeof(int)); // this just change the value inside of p it is unnecessary 
and you will lose a adress from memory :) and possibly it will be unsafe if you free p may, you just 
free one adress*/ 
     /*before using a pointer always allocate it memory else 
     you ll get frequent system crashes and BSODs*/ 
     memory(p, 10);  //get the address of the pointer//you are getting nothing 
     cout <<p[0]; 
     //we set p[0] to 100 but it will write a garbage value here. 
     //because the value inside of p didn't change at the memory function 
     //we sent just the value inside of p. 

     getch();  
     return 0; 
    } 
Verwandte Themen