Kommandozeilenparameter in Array speichern



  • Hallo zusammen,

    ich habe ein kleines Problem, auf dessen Lösung ich nicht komme.

    Aufgabenstellung soll sein, dass ein Programm gestartet wird mit einer Zeichenkette und anschließend soll die Zeichenkette alphabetisch sortiert werden.
    Mein grundlegendes Problem ist nun die Zeichenkette in ein Char-Array zu kopieren.

    Prinzipiell lautet der Methodencode:

    int main(int argc, char** argv)
    

    arc zählt die Argumente und argv ist der Vektor.
    Das Problem ist für mich jetzt nur, dass zwar beispielsweise argv[1] auf das erste Zeichen des Parameters zeigt, aber ich finde keine Möglichkeit auf das zweite Zeichen zu zeigen, da argv[2] schon auf den dritten Parameter zeigt.

    Um es verständlich zu machen, z.B.:

    ./text.exe hallo welt

    würde argv[1] auf hallo zeigen, argv[2] allerdings auf Welt. Ich stelle mir aber vor, die Zeichenkette hallo in ein char Array zu kopieren, um es dort zu sortieren. Dabei erhalte ich aber Fehlermeldungen, wenn ich ein Array erzeuge und den Pointer des ersten Elements auf den Inhalt des argv Arrays zeigen lasse, wegen ** nach *, oder so, keine Ahnung.
    Wie gesagt mit *argv[1] erhalte ich noch den ersten Buchstaben der Zeichenkette, aber ich finde keine Lösung, wie ich auf die weiteren Chars komme, da *argv[2] schon auf den nächsten Parameter zeigt.

    Vielleicht kann mir jemand helfen, vielleicht auch mit einem ganz anderen Ansatz.

    MfG



  • argv ist ein 2D Array.
    argv[1][0] wäre der 1. und
    argv[1][1] der 2. Buchstabe des 1. Parameters...



  • Ich weiß nicht ob dir das schon bekannt ist, kann aber nicht schaden: unter argv[0] findet man das aufgerufene Programm wieder. Ganz praktisch wenn man mit symbolischen Links arbeitet.



  • Ah ok, da hätte ich eigentlich auch drauf kommen können, hm dann tut es mir leid für meine dumme Frage, vielen Dank trotzdem.

    MfG



  • Prinzipiell gilt auch hier wieder wie schon so oft: nutze lieber std::string!
    Beispielsweise so:

    int main(int argc, char** argv)
    {
      std::deque<std::string> argd;
      for(int i = 0; i < argc; ++i) argd.push_back(std::string(argv[i]));
      //in argd[0] bis argd[argc-1] sind jetzt die Parameter als strings.
    
    }
    


  • Oder kürzer:

    std::deque<std::string> args(argv, argv + argc);
    


  • Wieso ne Deque?



  • Hmm ... naja nicht ganz richtig 😉

    std::vector<std::string> arguments(argv + 1, argv + (argc - 1));
    

    Oder willst du den Programmpfad/namen dabei haben 😉



  • Konrad Rudolph schrieb:

    Wieso ne Deque?

    Hatte ich mich anfangs auch gefragt. Die Antwort, die ich mir gegeben habe ist, dass man beim Auswerten der Optionen die bereits verarbeiteten gerne vorne rausholen möchten könnte. Praktisch um die verbliebenen Argumente dann an einen anderen Verarbeiter weiterzugeben.

    (D)Evil schrieb:

    Hmm ... naja nicht ganz richtig 😉

    std::vector<std::string> arguments(argv + 1, argv + (argc - 1));
    

    Oder willst du den Programmpfad/namen dabei haben 😉

    Dann einigen wir uns aber auf diese Variante, ok? 😉

    std::vector<std::string> arguments(argv + 1, argv + argc);
    


  • okay 😉



  • Konrad Rudolph schrieb:

    Wieso ne Deque?

    Was spricht dagegen? Ich zieh standardmaessig eine deque dem vector vor, allerdings aus Gruenden, die bei dieser speziellen Anwendung nicht ins Gewicht fallen. Ob man nun eine deque oder einen vector benutzt, duerfte vor allem mit dem von LordJaxom erwaehnten Range-Konstruktor hier voellig wurscht sein. Bei der push_back methode koennte ein vector zwischendurch umkopieren muessen, wenn die anfangskapazitaet kleiner als die Zahl der Kommandozeilenparameter ist.



  • (D)Evil schrieb:

    ...Oder willst du den Programmpfad/namen dabei haben 😉

    😕
    Klar - warum nicht ? Ich habe die immer mit dabei....

    Gruß,

    Simon2.



  • Hi Pumuckl,

    Ich zieh standardmaessig eine deque dem vector vor

    Das halte ich für falsch. Für Anwendungen, wo nur push_back gebraucht wird, ist der Vektor schneller – immer. Und wenn man vorhersagbare Laufzeit braucht, muss man wohl oder übel die List benutzen, da auch die Deque manchmal neue Speicherblöcke anfordern muss.

    Der einzige Vorteil der C++-Deque (!) in allgemeinen Anwendungen ist das schrittweise Freigeben von Speicher, was dann im Vergleich zum Vektor um einiges schneller geht.



  • Konrad Rudolph schrieb:

    Das halte ich für falsch. Für Anwendungen, wo nur push_back gebraucht wird, ist der Vektor schneller – immer.

    Stimmt so leider nicht. Gerade bei vielen push_back()s muss der vector immer wieder einen neuen, größeren Speicherblock allokieren und dann den gesamten Inhalt vom alten in den neuen Block kopieren. Deque hingegen allokiert sich eine neue page und lässt den alten content unangetastet. Das kann gerade bei nicht-trivialen Klassen einen enormen Overhead bedeuten. Natürlich kann man, wenn man von vornherein die Anzahl der Elemente kennt, sich mit reserve() das kopieren und neu-allikieren beim vector sparen, aber das ist dann einer der (nicht allzu häufigen) Spezialfälle wo vector das Rennen macht. Ich weiß, dass das Thema kontrovers ist, mehr dazu unter anderem hier.



  • pumuckl schrieb:

    Gerade bei vielen push_back()s muss der vector immer wieder einen neuen, größeren Speicherblock allokieren und dann den gesamten Inhalt vom alten in den neuen Block kopieren.

    Ich bin gerade zu faul, in eine Implementierung zu schauen. Aber wird da wirklich der Kopierkonstruktor der Elemente aufgerufen? Das wäre ja eine Verschwendung. Ich dachte bisher, das sei lediglich eine Block-Kopie. Das wäre doch vollkommen ausreichend.

    Ich gehe sogar so weit zu behaupten, dass ein Vektor falsch implementiert ist, wenn er den Kopierkonstruktor beim Umräumen aufruft.

    Abgesehen davon hat ein Vektor natürgemäß wesentlich bessere konstante Faktoren als die Deque (und zwar teilweise signifikant besser) für all seine Zugriffsoperationen. Ich habe neulich mal einen Performance-Test gemacht und der hat die Deque klar von den Rängen verwiesen.

    Ich muss sagen, dass ich den GOTW-Artike nicht grandios finde. Die Daten sind hoffnungslos veraltet und der Artikel geht mir nicht genug in die Tiefe.



  • Ich ging bisher immer selbstverständlich davon aus und bin auch nach wie vor überzeugt davon, dass ein Vector beim Umräumen seine Elemente kopieren muss.

    Und wie anders kann man C++-Objekte kopieren als mit der üblichen Kopiersemantik? Ein memcpy auf ein Array von C++-Objekten in freier Wildbahn ist tödlich, dann wird es im Vector auch nicht viel besser aussehen. Ausserdem ist Kopierbarkeit ja auch eine der Anforderungen an Vector-Elementtypen.



  • LordJaxom schrieb:

    Ich ging bisher immer selbstverständlich davon aus und bin auch nach wie vor überzeugt davon, dass ein Vector beim Umräumen seine Elemente kopieren muss.

    Hmm, scheint zu stimmen:

    The constructor template <class InputIterator> vector(InputIterator first, InputIterator last) […] does at most 2N calls to the copy constructor of T and logN reallocations … since it is impossible to determine the distance between first and last and then do copying.

    2N ist eine obere Grenze für 1 + 2 + … + N / 4 + N / 2 + N. Demnach wird für jede Reallokation der Kopierkonstruktor aufgerufen.



  • Rohen Speicher zu kopieren ist doch archaisch, nicht umsonst ist memcpy nicht Teil der C++-Standardbibliothek sondern der C-Bibliothek 😉
    Stell dir mal eine Klasse vor, die in irgendeiner Weise einen Pointer auf ein eigenes Element enthält. Beim simplen memcpy zeigt der Pointer hinterher immernoch dorthin, wo das Element mal war. Willkommen bei den Segfaults 😉



  • pumuckl schrieb:

    Rohen Speicher zu kopieren ist doch archaisch

    Nein, nur low-level.

    nicht umsonst ist memcpy nicht Teil der C++-Standardbibliothek sondern der C-Bibliothek 😉

    … damit *ist* es Teil der C++-Standardbibliothek. Aber ich dachte auch eher an 'std::copy' auf einen 'std::raw_storage_iterator'.

    Stell dir mal eine Klasse vor, die in irgendeiner Weise einen Pointer auf ein eigenes Element enthält.

    Wer macht denn sowas? o.O



  • Naja denken wir uns doch mal eine Stringklasse, die ein Array von 50 Zeichen als Member enthält, und erst wenn der Inhalt auf mehr als 50 Zeichen anwächst einen Puffer auf dem Heap allokiert. Der Einfachheit halber wird die Adresse des aktuellen Inhalts in einem Zeiger gehalten, der entweder auf ein Member des eigenen Objekts zeigt, oder aber irgendwo in den Heap.


Anmelden zum Antworten