Länge von dynamischen Array bestimmen



  • Hallo,

    ich versuche gerade ein Int-Array dynamisch anzulegen, als Länge dient die Länge eines Strings, der dann in dem array gespeichert wird, nachdem die einzelnen Zeichen des Strings in Int umgewandelt wurden. Das funktioniert soweit auch ohne Probleme.
    Jetzt möchte ich aber feststellen, wie lang die einzelnen Arrays sind. Ich kann hier aber nicht direkt auf die Variable zugreifen, sondern nur über einen Pointer. Ich habe es jetzt mit sizeof(pArray1) probiert, aber der Rückgabewert ist immer falsch und wenn ich von zwei verschiedenen Arrays pArray1 und pArray2 die Länge bestimmen will, die Arrays sind unterschiedlich lang, kommt für beide der gleiche, falsche Wert raus. Was mache ich falsch (bin relativ ungeübt in C++).

    ...
    pzahla = &zahla;     // Pointer auf Variablen setzen
    pzahlb = &zahlb;
    pzahlc = &zahlc;
    ...
    pzahla = new int [eingabe1.length()];		// länge festlegen
    pzahlb = new int [eingabe2.length()];						
    ...
    fnk-StringToIntArray(pzahla, eingabe1)         // wandelt String in Int-Array um
    fnk-StringToIntArray(pzahlb, eingabe2)         // funktioniert ohne Fehler !
    ...
    size1 = sizeof(pzahla);        // Länge abfragen        
    size2 = sizeof(pzahlb);
    

    Hier ist die Ausgabe bei der Eingabe von 123 und 5678 dann size1 = 4 und size2 = 4.
    Liegt es eventuell daran, dass hier die Länge des Pointers (Länge der Adresse) und nicht die der Variable zurückgegeben wird? Wie bekomme ich die Länge der Variable?

    lg mo



  • Erstens: Wenn du einen Zeiger auf eine Variable setzt, diesem (dem Zeiger) aber mit new neuen Speicher gibst, verliert er die Adresse. Was du machen könntest ist:

    pzahla=new int[eingabe1.length()]; // Lege Speicher fest ...
    pzahlb=new int[eingabe2.length()];
    
    pzahla[0]=zahla; // ... und belege den Speicher mit den Variablen.
    pzahlb[0]=zahlb;
    

    Zweitens: Wenn du sizeof verwendest, teilst du am besten durch die Grösse des Typs:

    size1=sizeof(pzahla)/sizeof(/*Typ von pzahla*/);
    size2=sizeof(pzahlb)/sizeof(/*Typ von pzahlb*/);
    


  • Drittens: Du willst std::vector verwenden.

    // oben: include <vector>
    
    std::vector<int> pzahla(eingabe1.length());
    std::vector<int> pzahlb(eingabe2.length());
    
    size1=pzahla.size();
    size2=pzahlb.size();
    

    Gruß,

    Simon2.



  • ok, habe den Code entsprechend geändert. Leider das gleiche Problem. In wiefern wäre es besser std::vector zu verwenden? Was genau würde das für Vorteile bringen?

    ...
    
    pzahla = new int [eingabe1.length()];        // länge festlegen
    pzahlb = new int [eingabe2.length()];   
    
    pzahla[0]=zahla;              // zuweisen
    pzahlb[0]=zahlb;	                   
    ...
    fnk-StringToIntArray(pzahla, eingabe1)         // wandelt String in Int-Array um
    fnk-StringToIntArray(pzahlb, eingabe2)         // funktioniert ohne Fehler !
    ...
    size1 = sizeof(pzahla)/sizeof(int);       // Länge abfragen        
    size2 = sizeof(pzahlb)/sizeof(int);
    

    lg mo



  • Man kann auf die Länge eines dynamisch Arrays nicht zugreifen. std::vector speichert deshalb die Länge mit. Die Idee mit sizeof funktioniert nur mit statischen Arrays.



  • Hallo,
    vor einiger Zeit hatte ich das gleiche Problem. Ich empfehle auch stl zu verwenden, doch wenn Du möchtest (es gibt einen guten Beipsielcode hier - bei Wunsch kriegste auch den Link 🙂 ), könntest Du eine Klasse (oder Template) erstellen, dass ein dynamisches Array erstellt. Dann hast du die Möglichkeit die Länge in einer Variablen zu speichern und diese mittels einer Methode immer abzufragen.

    So habe ich das gemacht, wobei es sehr umständlich ist und es daher komfortabler ist, wenn du gleich std::vector benutzt.

    lg, freakC++



  • hvgguser schrieb:

    ...
    size1 = sizeof(pzahla)/sizeof(int);
    size2 = sizeof(pzahlb)/sizeof(int);
    ...
    

    pzahla und pzahlb sind Zeiger. Die Größe eines Zeigers ist konstant und unabhängig davon, auf was es zeigt. Der Zeiger belegt immer gleich viel Speicher.

    Trotz der vielen syntaktischen Ähnlichkeiten zwischen int* und int[123] sind es dennoch zwei unterschiedliche Typen. int* ist ein Zeiger, welcher auch auf ein Array-Element zeigen kann. int[123] ist ein Array.

    Du musst schon einen echt guten Grund haben, um

    int* blah = new int{123];
    

    gegenüber

    vector<int> blah (123);
    

    vorzuziehen.

    Gruß,
    SP



  • ok, überzeugt 🙂
    Werde es mal mit std::vector probieren

    lg mo



  • Moin,

    ich habs jetzt über eine Klasse gemacht, in der die Länge mit gespeichert wird. Dachte mir das sei sinnvoll, da es bei dem Projekt darum geht beliebig große Natürliche Zahlen zu Addieren, Subtrahieren, ... So kann ich die Funktionen dazu gleich mit in die Klasse packen. Einzige Befürchtung hierbei ist, dass der "Umweg" über Klassen in die Performance geht, was gerade bei Operationen mit großen Zahlen durchaus bemerkbar (10^20 Stellen und mehr) sein dürfte.

    Ich habe jetzt aber das Problem, dass beim Kompilieren der Fehler Auftritt, dass die Methode des Objektes nicht existieren würde (wenn ich den Fehler richtig verstehe), obwohl das Objekt inkl. Methode existiert. Hier ein kleiner Auszug:

    #include "cNumberN.h"                                // externe Datei mit Objekt einbinden
    ...
    cNumberN meinObjekt1, meinObjekt2, meinObjekt3;      // Objekte deklarieren
    ...
    meinObjekt1.setNumberByString(eingabe1);            // Objekte mit Werten füllen
    meinObjekt2.setNumberByString(eingabe2);
    
    meinObjekt1.Add(meinObjekt1, meinObjekt2, meinObjekt3);        // Hier ist das Problem
    ...
    
    >cNumberN.h<
    
    class cNumberN
    {
    public:
    void setNumberByString(std::string number);			// Übergebe dem Objekt eine Zahl im String-format
    void Add(cNumberN *obj1, cNumberN *obj2, cNumberN *obj3);       // zwei Zahlen addieren und speichern
    private:
    int *poZahl;							// das int-array in dem die Zahl gespeichert wird
    int leng;							// die Länge des int-arrays
    };
    

    Mit der Funktion Add sollen die ersten beiden Objekte die Übergeben werden addiert werden (also die Zahlen innerhalb der Objekte) und dann im dritten gespeichert werden. Beim Kompilieren kommt hier der Fehler "error: no matching function for call to 'cNumberN::Add(cNumberN&, cNumberN&, cNumberN&)' " Als Programmierumgebung benutze ich XCode.
    Kann mir jemand einen Tipp geben, was der Fehler genau ist? Wie gesagt, ich bin noch recht neu in C++.

    lg mo



  • hvgguser schrieb:

    ich habs jetzt über eine Klasse gemacht, in der die Länge mit gespeichert wird

    std::vector erledigt das und noch viel mehr für dich. Hast du Gründe dafür, warum du das alles selber machen willst?

    hvgguser schrieb:

    (10^20 Stellen und mehr)

    Das dürfte speichertechnisch wohl schwierig werden.

    Kann mir jemand einen Tipp geben, was der Fehler genau ist?

    Deine Funktion Add will Zeiger auf Objekt der Klasse cNumberN , du übergibst aber keine Zeiger, sondern direkt die Objekte.

    Der Aufruf muss so aussehen:

    meinObjekt1.Add(&meinObjekt1, &meinObjekt2, &meinObjekt3);
    


  • ah, danke.
    Der Grund das ich das alles selber mache ist, das ich laut Aufgabenstellung alles selber machen soll. Da ich nicht weiß in wie weit ich eventuell Punktabzug bekomme wenn ich vector verwende, oder andere fertige Konstrukte, mach ich es lieber so.

    Klar, 10^20 wird bei herkömmlichen Speichern ein wenig schwierig, aber es geht einfach darum, dass es wenn ausreichend Speicher und Rechenleistung gegeben sind, beliebig große Zahlen verarbeitet werden können.

    lg mo



  • deine funktion will zeiger, gib ihr zeiger:
    meinObjekt1.Add( **&**meinObjekt1, **&**meinObjekt2, **&**meinObjekt3);
    mfg



  • Es gibt die Bibliothek gmp. Auch kannst du dir ansehen, wie der Konsolenrechner bc das macht.



  • thx. werde ich mir mal anschauen.
    Ist es eigentlich möglich, ein mit pVar = new int [länge] erzeugtes Array nachträglich verlängern, ohne dass die bereits im Array gespeicherten Zahlen verloren gehen? Oder muss man den Umweg gehen, dass man das Array in einem temporären Array zwischenspeichert, dann das ursprüngliche Array zerstört, mit der neuen Länge neu anlegt und dann die Werte aus dem temp.-Array dort wieder reinschreibt?

    lg mo



  • Das ist der Weg, wenn man mit Arrays arbeitet. Die allgemeine Strategie von std::vector ist, die Groesse zu verdoppeln. So muss nur selten ein neues Array angelegt und die Eintraege kopiert werden. Wenn du das aber oft brauchst, dann ist vielleicht eine Liste oder Heap/Set/Tree besser geeignet.



  • hvgguser, nimm GMP (GNU multiple precision library), falls Du keine Probleme mit der GPL-Lizenz hast. Es ist jedenfalls sine sehr praktischer C++ Header (gmpxx.h) dabei, der Sachen, wie große Ganzzahlen, Brüche schön als Klassenobjekt verpackt.

    Wenn das allerdings eine Übung sein soll, die Dir verbietet, andere Bibliotheken zu nutzen...

    hvgguser schrieb:

    Ist es eigentlich möglich, ein mit pVar = new int [länge] erzeugtes Array nachträglich verlängern, ohne dass die bereits im Array gespeicherten Zahlen verloren gehen?

    ** std::vector **!

    hvgguser schrieb:

    Oder muss man den Umweg gehen, dass man das Array in einem temporären Array zwischenspeichert, dann das ursprüngliche Array zerstört, mit der neuen Länge neu anlegt und dann die Werte aus dem temp.-Array dort wieder reinschreibt?

    Das ist das, was der vector für Dich erledigt. Man kann das für PODs auch anders regeln, wenn man unbedingt will. Zu Deinem Schutz, verrate ich Dir aber nicht wie. Wenn es auf Performanz ankommt, nimm einfach GMP. 😉

    Gruß,
    SP



  • Wie gesagt, ich kann leider keine fertige Lösung wie GMP nehmen, da ich die Aufgabenstellung bekommen habe, alles selbst zu schreiben, inkl. der Datenstrukturen die ich verwende. Deshalb wollte ich eigentlich nicht std::vector nehmen.
    Ich habe es jetzt zwar erstmal mit vector gemacht, aber da vector im Prinzip ein Objekt ist befürchte ich nach wie vor, dass die Performance bei Rechenoperationen auf großen Zahlen in die Knie geht. Ich werde wenn ich es zeitlich schaffe auch einen Heap oder eine einfache Liste probieren.

    lg mo



  • hvgguser schrieb:

    Einzige Befürchtung hierbei ist, dass der "Umweg" über Klassen in die Performance geht, was gerade bei Operationen mit großen Zahlen durchaus bemerkbar (10^20 Stellen und mehr) sein dürfte.

    hvgguser schrieb:

    Ich habe es jetzt zwar erstmal mit vector gemacht, aber da vector im Prinzip ein Objekt ist befürchte ich nach wie vor, dass die Performance bei Rechenoperationen auf großen Zahlen in die Knie geht.

    Du solltest statt befürchten lieber messen und anschliessend sehen, ob es wirklich einen Unterschied gibt. Das, was du machst, nennt man Premature Optimization - durch unbestätigte Vermutungen einen Weg zu gehen, mit dem man langfristig schlechter fährt.

    Die Ansicht, dass Klassen schon prinzipiell langsamer sein müssen als einfache Datentypen, ist in C++ einfach nur falsch. Was langsamer sein kann, sind Funktionen wie Konstruktoren, aber eigentlich nur, wenn die auch besonders viel tun. In den meisten Fällen sind Compiler in der Lage, durch Inlining kleine Funktionen wegzuoptimieren, wodurch man wieder keinen Overhead mehr hat.

    hvgguser schrieb:

    Ich werde wenn ich es zeitlich schaffe auch einen Heap oder eine einfache Liste probieren.

    Dir geht es also doch nicht um Geschwindigkeit, oder wie ist das zu verstehen?

    Ich rate dir, zuerst dein Problem sauber zu lösen und dir dann Überlegungen dieser Art zu machen. Und zwar mit Profiler oder Zeitmessungsfunktionen, und nicht nach Gefühl. Schon gar nicht sollte man sich durch kleine Optimierungen im Voraus verleiten lassen, seinen Code hässlich zu gestalten, um vermeintlich schneller zu sein. Das ist dann eben der erwähnte schlechtere Weg - am Schluss ist der Code schlecht wartbar, fehleranfällig und obendrein vielleicht sogar noch langsamer, weil man doch nicht ganz Recht hatte mit seinen Vermutungen.



  • Dir geht es also doch nicht um Geschwindigkeit, oder wie ist das zu verstehen?

    Hat er doch geschrieben, dass er eigl. alles selbst machen soll:

    Wie gesagt, ich kann leider keine fertige Lösung wie GMP nehmen, da ich die Aufgabenstellung bekommen habe, alles selbst zu schreiben, inkl. der Datenstrukturen die ich verwende.



  • Ich habe mit dem Satz eher darauf anspielen wollen, dass er mit Listen, Heaps etc. vielleicht um einiges langsamer ist als mit einem einfachen dynamischen Array wie bei std::vector (oder etwas Selbstgebasteltem). Das Anfordern vieler kleiner Elemente braucht seine Zeit, da machen die Reallokationen vielleicht weniger aus, wenn sie nicht dauernd vorkommen. Ausserdem kommt bei einer verketteten Liste ein Overhead von zwei Zeigern pro Element dazu. Und so wie ich hvgguser verstanden habe, möchte er viele Dezimalstellen speichern können...

    Aber allgemein sollte man wenn möglich seine Implementierung generisch halten, sodass man bei Bedarf Datenstrukturen mit relativ wenig Aufwand austauschen kann. typedef trägt hier seinen Teil bei.


Anmelden zum Antworten