array über pointer returnen und ausgeben
-
Hi! Ich hab grad erst angefangen C++ zu lernen und hab mal eine Frage zu folgendem Code:
#include <iostream> using namespace std; int *test(); int main() { int *pointer ; pointer = test() ; cout<<*pointer++<<" "<<*pointer++<<" "<<*pointer++<<" "<<*pointer<<"\n" ; } int *test() { int array[4] = { 0, 1, 2, 3 } ; int *ptr ; ptr = array ; return ptr ; }Eigentlich vollkommen verständlich nur die Ausgabe ist mir schleierhaft.
Output:
0 1 2 16384Wieso kommt da 16384 und nicht wie erwartet eine 3? Ich hab das Ganze dann auch mal mit einem 7 Stellen großen array probiert, also Werte von 0 bis 6. Da kam dann folgender Output:
0 4481984 2 3 4 5 6Hier versteh ich wiederrum nicht wieso da 4481984 ausgegeben wird statt einer 1. Anschließend hab ich probiert die Werte des pointers in extra definierte Variablen zu übergeben. Das hat das erwartete Ergebnis geliefert. Nur es kann doch nicht der Sinn sein 7 Variablen zu definieren um die Zahlen auszugeben oder?
Hoffe mir kann einer sagen wie ich das Problem löse und wieso da solche komischen Werte entstehen. Danke schonmal.
-
Du lieferst einen Zeiger auf eine lokale Variable zurück - das kann gut gehen, aber die Chancen stehen gut, daß der Wert längst überschrieben wurde, bevor du ihn zu Gesicht bekommst.
-
Heißt also das Array in der main methode definieren und dann einen Zeiger darauf an die Funktion übergeben und dann gehts? Alles klar danke.

-
Oder besser: Speicher "außen" organisieren - da, wo Du ihn auch benutzen willst....
#include <iostream> #include <vector> using namespace std; void test(vector<int>& v); int main() { vector<int> myInts ; test(myInts); vector<int>::const_iterator pointer = myInts.begin(); cout<<*pointer++<<" "<<*pointer++<<" "<<*pointer++<<" "<<*pointer<<"\n" ; } void test(vector<int>& v); { v.push_back(0); v.push_back(1); v.push_back(2); v.push_back(3); }Gruß,
Simon2.
-
Simon2 schrieb:
Oder besser: Speicher "außen" organisieren - da, wo Du ihn auch benutzen willst....
#include <iostream> #include <vector> using namespace std; void test(vector<int>& v); int main() { vector<int> myInts ; test(myInts); vector<int>::const_iterator p = myInts.begin(); cout<<*pointer++<<" "<<*pointer++<<" "<<*pointer++<<" "<<*pointer<<"\n" ; } void test(vector<int>& v); { v.push_back(0); v.push_back(1); v.push_back(2); v.push_back(3); }Gruß,
Simon2.
Wie gesagt hab grad erst angefangen. Wäre es möglich dazu ne Erkärung zu geben denn so an sich versteh ich das nicht.
-
Ach so .... sorry, hatte ich nicht beachtet.
Ich gehe mal von Deinem Code aus - mit Arrays kennst Du Dich anscheinend schon ein wenig aus:
A) Zwischenschritt: statisches Array "außen":#include <iostream> using namespace std; void test(int* v); int main() { int myInts[4]; // Platz für 4 ints schaffen test(myInts); int* pointer = &myInts[0]; // Adresse des ersten Elements; lt. Standard hätte auch "p = myInt;" gereicht cout<<*pointer++<<" "<<*pointer++<<" "<<*pointer++<<" "<<*pointer<<"\n" ; } void test(int* v); { v[0] = 0; v[1] = 1; // Füllen; jedes Element adressieren (mit []) und Wert zuweisen. v[2] = 2; v[3] = 3; }Nachteile:
1.) Nirgends ist hinterlegt, wie viele Elemente in v passen; müsste man explizit übergeben. Ansonsten "knallts".
2.) main() muss wissen, wieviele int's test() haben möchte
Zwischenschritt: vector (statt Array) mit vorgegebener Länge
Vorteil: vector selbst hält seine Länge.#include <iostream> #include <vector> using namespace std; void test(vector<int>& v); // Übergabe per Referenz (&), damit wir nicht auf einer Kopie zu arbeiten int main() { vector<int> myInts(4); test(myInts); vector<int>::const_iterator pointer = myInts.begin(); // Adresse des ersten Elements; // "Iteratoren" sind eine Verallgemeinerung von Pointern (Pointer sind "spezielle Iteratoren") cout<<*pointer++<<" "<<*pointer++<<" "<<*pointer++<<" "<<*pointer<<"\n" ; } void test(vector<int>& v); { if(v.size() < 4) return; // Vorteil: Hier kann ich die Länge überprüfen v[0] = 0; v[1] = 1; // wie oben: Man kann mit [] auch auf Vectorelementezugreifen v[2] = 2; v[3] = 3; // Alternativ kann ich statt v[0] auch v.at(0) nehmen und bekomme eine exception (s. Tutorial), // wenn ich auf ein nicht vorhandenes Element zugreifen will. }Vorteil: Länge ist implizit dabei
Nachteil: main() muss immer noch wissen, wieviele int's test() haben möchte.C) vector mit dynamischer Größe:
Code: s.o.
Hier verlängert test() selbst den vector mittels push_back() (=Methode von std::vector zu Anhängen eines Elements; der Anwender brauch sich nicht darum zu kümmern wie lang es werden soll und wie der vector sich seinen Speicher dafür besorgt/verwaltet).BTW1: Dass Du einem Vektor eine Anfangsgröß0e mitgibst (B) hindert Dich nicht daran, mittels push_back() später nochwas anzuhängen.
BTW2: Die Ausgabe kannst Du auch viel einfacher machen:cout << myInts[0] << " " << myInts[1] << " "<< myInts[2] << " "<< myInts[3] << "\n";(tut's bei allen Varianten und macht "pointer" überflüssig)
Gruß,
Simon2.
-
Funktion test habe ich mal geändert. Aber den allokierten Speicher must
du noch freigeben.
Noch eine Anmerkung. So eine Programmierung sollte man sich nicht angewöhnen.int *test() { int array[4] = { 0, 1, 2, 3 } ; int *ptr = new int[4]; ptr[0] = array[0] ; ptr[1] = array[1] ; ptr[2] = array[2] ; ptr[3] = array[3] ; return ptr ; }
-
Simon2 schrieb:
[...]
Ok, jetzt wirds schon klarer. Danke!

schokomann schrieb:
Noch eine Anmerkung. So eine Programmierung sollte man sich nicht angewöhnen.
"So eine Programmierung" heißt in dem Falle was?

-
Der Aufrufer der Funktion test muss wissen, dass er den Speicher wieder
freigeben muss. Besser ist die Verwendung der STL, wie es in den
Beispielen schon gezeigt wurde, oder so ein C-Array in eine Klasse
packen. Die Klasse kümmert sich dann um alles und stellt entsprechende
Funktionen für den Zugriff zur Verfügung.
Für ein Demoprogramm oder ein Beispiel was man machen kann und wie
man es besser nicht machen sollte ist es o.k.
Man kann an dem Bsp. zeigen welche Fehler man machen kann, worauf man
bei solchem C-Code achten muss damit es knallt oder besser nicht.Bücher wie Effective C++, More Effective C++ (Scott Meyers),
Modern C++ Design (Andrei Alexandrescu) u.s.w. solle man lesen
und auch umsetzen. Angelika Langer (STL) hat ebenfalls gute Bücher
herausgegeben.Das Geld sollte man ausgeben. Das macht sich später bezahlt.
Ansonsten viel Spaß noch.
-
plis schrieb:
...
schokomann schrieb:
Noch eine Anmerkung. So eine Programmierung sollte man sich nicht angewöhnen.
"So eine Programmierung" heißt in dem Falle was?

"Speicher (oder andere manuell freizugebende Ressourcen) anfordern und die Verantwortung für die Freigabe zu delegieren".
Hier:
- test() fordert Speicher an
- main() muss das wissen und an der geeigneten Stelle freigeben.Das das ein ungünstiger Designansatz ist, kann man sehen, wenn man sich vorstellt, dass beide Funktionen von unterschiedlichen Programmierern implementiert werden. Vielleicht wird test() sogar nur als Lib angeliefert, deren Source man gar nicht zu Gesicht bekommt - woher soll der main()-Programmierer wissen, dass und wann er den Speicher wieder freigeben soll
Ersteres schlägt z.B. fehl, wenn test() (vielleicht erst in der Version 1.1) folgendermaßen implementiert wurde:int *test() { static int array[4] = { 0, 1, 2, 3 } ; // mittels "static" überlebt das Objekt return array; } int main() { int* p = test(); cout << p[1]; delete[]; // RUMMS: delete auf static Speicher kommt nicht gut! return 0; }So ein "delete" führt in den Sumpf "undefinierten Verhaltens" (gerne mal ein segFault, aber theoretisch ist bin zum 3. Weltkrieg alles drin).
Zweiteres kann z.B. in die Binsen gehen, wenn man soewas macht:
int *test() { static int* array = 0; if(array == 0) array = new int[4]; // nur das Erste Mal anlegen. return array; } int main() { int* p, q; p = test(); cout << p[1]; delete[]; // geht in Ordnung, ... q = test(); // ... aber test() rechnet nicht damit cout << q[2]; // RUMMS - Zugriff auf bereits freigegebenen Speicher. return 0; }Auch hier: Undefiniertes Verhalten.
In der Realität kommen noch sehr viel komplexere Situationen dazu, so dass sich insgesamt folgender Rat konsensfähig ist:
schokomann schrieb:
...So eine Programmierung sollte man sich nicht angewöhnen....

Gruß,
Simon2.