Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Erzeugung eines dynamisch langen **char in c++

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 < [ 2 ]
000
06.04.2005, 09:46 Uhr
~lisan
Gast


Hi,

Ich muss die instanz einer klasse AkSimulation(int argc, char** argv) erstellen.
Dazu konstruiere ich mir die argumentliste argv- leider ein **char.

Ich arbeite nun allerdings mit std::stringstream und std::string.

Meine Fragen dazu:
1. Wie schaffe ich es am elegantesten ein **char aus strings oder streams zu erzeugen.
2. Wie kann in c++ den standart typen *char dynamisch anpassen.
Im moment mache ich es leider so haesslich:

Code:
char *argv[10];
for (i=0;i<args;i++)
                argv[i]=new char[20];


Nun weiss ich im meinem speziellen fall allerdings nicht wie lang argv tatsaechlich ist,
wie ich kann ich c++ like dieses array 'resizen'.

Gruss,
Lisan.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
06.04.2005, 10:23 Uhr
ao

(Operator)



C++:
#include <iostream>
#include <cstdlib>
int main (void)
{
    int nNbrOfArgs = 30;        // wir nehmen mal 30, jeder andere Wert tuts auch
    char ** ppArgv = new char* [nNbrOfArgs];  // Array von 30 char*-Pointern

    int nIndex;
    for (nIndex = 0; nIndex < nNbrOfArgs; nIndex++)
    {
        ppArgv[nIndex] = new char [256];  // für jeden Pointer ein Stück Speicher holen
    }

    // Eigentlich ists hier fertig.
    // Zur Demonstration noch was reinschreiben
    // und den Inhalt ausgeben.

    for (nIndex = 0; nIndex < nNbrOfArgs; nIndex++)
    {
        ::sprintf (ppArgv[nIndex], "%d", nIndex);
        std::cout << ppArgv[nIndex];
    }

    // Und am Schluss das Aufräumen nicht vergessen

    for (nIndex = 0; nIndex < nNbrOfArgs; nIndex++)
    {
        delete [] ppArgv[nIndex];
    }

    delete [] ppArgv;

    return 0;
}


ao

Dieser Post wurde am 06.04.2005 um 10:23 Uhr von ao editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
06.04.2005, 10:35 Uhr
~lisan
Gast


Ja, genau so mache ich es ja - will ich aber nicht.
Die laenge diess array ist unbekannt und wird zwischedurch immer laenger.
Ich suche nach einer resize moeglichkeit ohne vectoren zu benutzen oder mir traits zu schreiben.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
06.04.2005, 10:46 Uhr
ao

(Operator)


Der new-Operator kann kein Resize. In der C- (nicht C++-) Library gibts aber die malloc-Familie, und dazu gehört auch realloc, damit geht das. Ist allerdings etwas gewöhnungsbedürftig.

Warum sollen es denn keine Vektoren sein? Ich würde die Argumente in einem std::vector<std::string> mit allem Komfort verwalten, und erst vor dem Instanzieren von AkSimulation den Vektor ausquetschen und ein temporäres char**-Array draus bilden, um den Konstruktor damit zu füttern.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
06.04.2005, 11:43 Uhr
(un)wissender
Niveauwart


std::vector ist perfekt für dieses Vorhaben.
std::vector<char*> vec; und dann als AkSimulation(vec.length(), &vec[0]) übergeben, fertig
--
Wer früher stirbt ist länger tot.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
06.04.2005, 12:48 Uhr
0xdeadbeef
Gott
(Operator)


Wenn du unbedingt einen char const ** brauchst...ich würds so anfangen:

C++:
#include <string>
#include <vector>

// ...

std::vector<std::string> v;

// ...v mit Daten füllen...

char const **p = new char const *[v.size()];
for(std::size_t i = 0; i < v.size(); ++i)
  p[i] = v[i].c_str();

// ...mit p arbeiten...

delete[] p;


--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
06.04.2005, 12:54 Uhr
ao

(Operator)



Zitat von (un)wissender:
std::vector<char*> vec;

Ein Vektor von Zeigern? Schauder! Auch wenn das Extrahieren der Strings eleganter geht, beim sicheren Verwalten der Vektorinhalte programmierst du dir den Wolf. Bei vector<string> kriegst du die ganze Speicherverwaltung geschenkt, bei vector<char*> musst du sie selber nachbauen.

Ich meine, wenn man schon mit Containerklassen anfängt, dann soll man es auch konsequent machen.

ao
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
06.04.2005, 15:44 Uhr
(un)wissender
Niveauwart


Bei std::vector<std::string> bekommst du aber das char** array nicht geschenkt, bei std::vector<char*> schon. Es ist auch nichts gegen einen vector ausZeiger einzuwenden. Die Korrektheit wird davon nicht negativ beeinflusst und die Speicherverwaltung entfällt bzw. wird in diesem Fall um nichts aufwändiger. Sein char** müsste er genauso löschen. Mit std::vector<char*> hat man in diesem Fall die perfekte Lösung.
--
Wer früher stirbt ist länger tot.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
06.04.2005, 16:51 Uhr
ao

(Operator)



Zitat von (un)wissender:
Bei std::vector<std::string> bekommst du aber das char** array nicht geschenkt

Das nicht, aber man holt es sich ganz einfach so, wie beefy es gezeigt hat.

Zitat:
die Speicherverwaltung entfällt bzw. wird in diesem Fall um nichts aufwändiger.

Doch. Du arbeitest mit fremden Daten, auf deren Lebensdauer du keinen Einfluss hast. Auf solche Objekte darfst du keine Pointer speichern, weil der Besitzer sie zwischendurch zerstören kann, ohne dass du das erfährst, und dann greifst du über deinen Pointer ins Klo.

Wer die Daten für sich behalten will, muss Kopien machen, d.h. Speichermanagement betreiben. Und dabei helfen die Containerklassen entscheidend. Unterm Strich hat man also weniger Arbeit und weniger Risiko.

ao
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
009
06.04.2005, 16:57 Uhr
virtual
Sexiest Bit alive
(Operator)



Zitat von (un)wissender:
Mit std::vector<char*> hat man in diesem Fall die perfekte Lösung.

Ziemlich überzeugt, wie?
Also, wie kommen denn die netten char* Objekte in den Vector rein? Bestimmt nicht mit Zauberhand, sondern durch stringstream und string, wie der OP sagte. Heißt doch frei übersetzt:

std::vector<std::string> ist die falsche Lösung, weniger weil man nicht in richtung char** kommen kann (dazu später), sondern weil es ein Performancekiller wäre. std::list<std::string> oder std::deque<std::string> wären hier ggf. die besseren Varianten.

std::vector<char*> ist vermutlich nicht die perfekte (keinesfalls die Standalone Lösung), weil irgendwo muß der Speicher der Strings ja verwaltet werden - vermutlich wohl in einem Container der std::string objekte aufnimmt...

Scheinbar benötigt man also beides, std::list<std::string> sowie ein ganz flaches char**. Ich würde also erstmal eine Hilfsklasse schreiben, welche aus einem Conteiner ein C Array basteln kann:

C++:
#include <algorithm>

template<typename T>
class c_array {
public:
private:
    T*  array;

    int array_size;
public:
    /* Helper to ge the const char* of a string */
    static const char* cpp2cstr(const std::string& s) { return s.c_str(); }

    /* Construtor */
    template<typename C>
        c_array(const C& container) {
            array = new T[array_size=container.size()];
            std::transform(container.begin(),
                           container.end(),
                           array,
                           &c_array::cpp2cstr);
        }

    /* Destructor. */
    ~c_array() { delete[] array; }

    /* Getter */
    const T* get() const { return array; }

    /* Get size. */
    int size() const { return array_size; }
};


Ist jetzt nur so dahingeschrieben, mit Verbesserungspotential: möglicherweise will man eine bessere Kontrolle darüber haben, daß ein c_array und der initialisierende Container gleiche Lebenszeit haben; aber das setzt im Zweifel den EInsatz von smartPointern voraus und würde den Rahmen sprengen.

Einsetzen kann man das dann so (eigentlich für alle möglichen Container primitiver Typen):

C++:
int main() {
    /* Container aufbauen. Hier vielleicht std::stringstream verwenden, keine Ahnung */
    std::list<std::string> l;
    l.push_back("Eins");
    l.push_back("Zwei");
    l.push_back("Drei");
    l.push_back("Vier");

    /* Erzeuge ein c_array object, welches das C Style Array verwaltet, hole das C Array */
    c_array<char const *> ca(l);
    const char* const* p = ca.get() ;

    /* Demonstriere den Gebrauch */
    for(int i=0; i<ca.size(); ++i) {
        std::cout<<p[i]<<std::endl;
    }

    /* Die Destruktoren machen die Aufräumarbeiten */
}


--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 < [ 2 ]     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: