Argumentübergabe an die main-Funktion!?



  • Hallo erstmal!
    Ich muss vorweg sagen, dass ich ein absoluter Neuling bin, also bitte nicht böhse sein wenn ich so eine dumme Frage stelle 😃 .
    Und zwar geht es um folgendes kleines Programm, das in einem Lehrbuch auftaucht:

    #include <iostream.h>
    
    void main(int argc, char *argv[])
    {
    	cout << argc << '\n';
    
    	for(int i=0;i<argc;i++)
    	{
    		cout << argv[i] << '\n';
    	}
    }
    

    Dieser Quellcode steht völlig Kommentarlos im Buch und ich verstehe folgendes nicht:
    Der zweite Parameter der main Funktion (chat *argv[]) ist doch ein Zeiger oder?
    Wozu aber ist denn der Zeiger genau da? Hätte man nicht einfach einen ganz normalen String deklarieren können?

    Und außerdem verstehe ich nicht, warum das Programm auch korrekt funktioniert, wenn man mehrere Argumente übergibt. Wenn ich es per Konsole ausführe und 2 Argumente übergebe, werden auch wirklich beide ausgegeben... warum aber?
    Es wird doch alles nur genau einmal ausgeführt und die Schleife liest ja im Prinzip auch nur die Länge des Strings ein.

    Ich wäre euch dankbar, wenn ihr mir ein wenig Klarheit verschaffen würdet!
    Danke im Voraus
    Special_Unit



  • Hallo

    weil *char argv[] ein Array von char-Pointern ist. Das heißt es werden in dem Array C-Strings übergeben, deren Anzahl durch argc festgelegt ist. Deshalb werden deine 2 Parameter auch im Programm als zwei Strings ausgegeben. Sieh dir einfach die Schleife geneu an.

    bis bald
    akari



  • Wenn du dein Programm so aufrufst:

    ./deinProgramm "Hallo Ich" bin ein netter "Parameter !"
    

    Dann hat argc den Wert 6 und argv diese Werte:

    argv[0] = "./deinProgramm"
    argv[1] = "Hallo Ich"
    argv[2] = "bin"
    argv[3] = "ein"
    argv[4] = "netter"
    argv[5] = "Parameter !"
    

    Ich bin mir jetzt nicht genau sicher, ob 1 und 5 selbst im String noch in "" stehen.



  • Ok, danke, das mit dem Ausgeben hab ich jetzt verstanden, aber ich verstehe immernoch nicht, warum man statt dem Zeiger nicht einfach einen ganz normalen String deklarieren könnte.



  • Du hast keinen Zeiger auf einen String, du hast einen Zeiger auf ein Array von Strings. Ein "ganz normaler String" kann ja auch schlecht mehrere Argumente speichern 😉

    Falls Du in dem Buch noch nicht soweit bist schlage ich vor das ganze für's erste als Erklärung zu akzeptieren, später wenn man Dir Zeigerarithmetik und Arraysemantik beibringt wirst Du verstehen warum man es so macht und auch warum sowas garnicht geht:

    char argv[][]
    


  • Ok, aber warum deklariert man dann nicht einen ganz normalen Array?
    Egal was deklariert wird, warum ist es ein Zeiger?



  • Hallo

    warum deklariert man dann nicht einen ganz normalen Array?

    Es ist ein ganz normales Array. Ein Array von C-Strings. Die Reihenfolge ist wichtig. Es ist eine Array von Pointer auf chars (C-Strings), kein Pointer auf ein Array von char.

    bis bald
    akari



  • Wie meinst du das?
    Mir wurde beigebracht, dass ein Array folgendermaßen deklariert wird:

    char Array[x];

    Wenn dort nun aber steht:

    char *Array[];

    Dann ist es doch ein Zeiger, und wenn nicht, was meinst du dann mit Reihenfolge?



  • Das ist ein Array ([]) von Zeigern auf char (char*).

    ( ( char* ) argv ) []
    

    Also argv ist der Name des Arrays, dessen Elemente vom Typ char* sind (Zeiger auf char). Ein C-String ist nichts anderes als eine Kette von chars, die mit dem Nullzeichen abgeschlossen ist. Ein char* ist ein Zeiger auf den Anfang einer solchen Kette, und die nennt man in C nunmal landläufig "String" (in C++ meint man damit eigentlich schon eher die Klasse std::string, aber das tut hier nichts zur Sache).

    Allerdings solltest Du wirklich noch einige erschöpfende Artikel / Kapitel über Arrays und Zeiger (und deren Zusammenhänge) lesen, damit Du es vollständig verstehst, denn es gibt nicht nur diese Möglichkeit, so eine Gruppe von Strings zu übergeben 😉



  • Hallo,
    ich habe unzählige Beispiele gegoogelt. Aber keins funktioniert. Nehmen wir den Code aus dem ersten Post.

    Als Ausgabe bekomme ich leider nur immer den ersten Buchstaben. Ok es ist ein 2D Array aber ich bekomme die Argumente da nicht richtig raus. Hoffe mir kann Jemand einfach einen Code schreiben der die Argumente ausgibt. Das bekomme ich mit dem Code aus dem ersten Post als Ausgabe (blah.exe).

    Microsoft Windows [Version 6.0.6001]
    Copyright (c) 2006 Microsoft Corporation.

    C:\Users\SchtinkeSocke>cd ..

    C:\Users>cd ..

    C:\>blah hallo welt
    3
    b
    h
    w
    Drücken Sie eine beliebige Taste . . .

    Ich benutze Visual Studio 8.



  • Dann hast du wohl den Code nicht richtig kopiert, der Schnippsel aus dem ersten Post funktioniert jedenfalls...



  • Sowas habe ich schon vermutet. Es geht garkein Beispiel welches ich gefunden habe. Bei manchen kommen nur irgendwelche Zahlen bei manchen eben nur das erste Zeichen.

    Also wird der Fehler irgendwo bei Visual Studio 8 liegen. Da werden die Argumente wohl irgendwie kaputt gemacht bzw. anders verpackt. Muss ich wohl gucken ob ich eine andere IDE finde.

    Die main sieht so aus.

    int _tmain(int argc, _TCHAR* argv[])
    

    Ist _TCHAR* != char* ? Ich kann das _TCHAR einfach in char umbennen 😃 ohne das eine Fehlermeldung kommt.



  • Wieso überhaupt _tmain() ?

    Signaturen von normalen Main-Funktionen sehen so aus:

    int main();
    int main(int argc, char** argv);
    

    Das sind auch die einzigen beiden Formen, die dem C++-Standard entsprechen (mal abgesehen von Rumspielereien wie void als Parametertyp oder char* argv[] , welche aber semantisch identisch sind).



  • Nexus schrieb:

    Wieso überhaupt _tmain() ?

    Signaturen von normalen Main-Funktionen sehen so aus:

    int main();
    int main(int argc, char** argv);
    

    Das sind auch die einzigen beiden Formen, die dem C++-Standard entsprechen (mal abgesehen von Rumspielereien wie void als Parametertyp oder char* argv[] , welche aber semantisch identisch sind).

    Wieso _tmain()? Keine Ahnung, musst du Microsoft fragen. 😉 . Deswegen habe ich erwähnt das ich es mit Visual Studio 8 probiert habe. Da habe ich eine Konsolenanwendung angelegt und da wird dann eben etwas Code schon automatisch erstellt.

    Eine Lösung fehlt mir aber immernoch. Einen zweiten Pointer kann ich ja in die main setzten wie in deinem Beispiel. Aber wie komme ich an VOLLSTÄNDIGE Argumente ran?
    Das dass erste Beispiel nicht funktioniert habe ich ja mit der Dos Ausgabe bewiesen.

    Ich kann auch den ganzen Code posten. Das untere ist ja uninteressant. Die Ausgabe kennt ihr ja schon.

    // blah.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung.
    //
    
    #include <stdafx.h>
    #include <windows.h>
    #include <shellapi.h>
    #include <string>
    #include <iostream>
    
    using namespace std;
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	cout << argc << '\n';
    
        for(int i=0;i<argc;i++)
        {
            cout << argv[i] << '\n';
        }
    
    	char systemDir32[800];
    	strcpy(systemDir32,getenv("SystemRoot"));
    	strcat(systemDir32,"\\System32\\javaw.exe");
    
    	string dir32 = "";
    	dir32 = dir32 +systemDir32;
    
    	// 32 bit windows
    	if (GetFileAttributesA(dir32.c_str()) != INVALID_FILE_ATTRIBUTES){
    		ShellExecuteA(NULL, "open", dir32.c_str(), "-jar myswt.jar", NULL, SW_SHOW);
    	}
    	else{
    		cout << "Java nicht gefunden. Starte Javasetup." << endl;
    		ShellExecuteA(NULL, "open", "jre-6u6-windows-i586-p.exe", NULL, NULL, SW_SHOW);
    	}
    
    	system("PAUSE");
    	return 0;
    }
    


  • Probiere es mal mit standardkonformen C++ aus (also main(..) ohne _t).
    Ansonsten gehört es in das "Compiler-Unterforum" (wo Du dann mehr Leute triffst, die sich mit so MS-spezifischem Kram auskennen).

    Gruß,

    Simon2.



  • SchtinkeSocke schrieb:

    Wieso _tmain()? Keine Ahnung, musst du Microsoft fragen.

    Ähnlich wie TCHAR ist auch _tmain sozusagen generisch. Abhängig von Projekteinstellungen bzw. Präprozessormakros wird eine normale main()-Funktion erzeugt oder eine für UNICODE.

    Für dich als Neuling wäre es vermutlich ratsam unter

    Projekt/Eigenschaften/Konfigurationseigenschaften

    bei Zeichensatz den Wert Multi-Byte-Zeichensatz verwenden einzustellen.

    Dann wird eine normale main() erzeugt und der hinzugelinkte Teil des Programms übergibt die Parameter auch als ganz normale char(s).



  • Kritiker schrieb:

    Für dich als Neuling wäre es vermutlich ratsam unter ...

    Oder einfacher: (wenn es nur um Konsolenanwendungen und C++ geht) Beim Anlegen der Konsolenanwendung "Leeres Projekt" auswählen...



  • asc schrieb:

    "Leeres Projekt" auswählen

    Ja, kann asc (ausnahmsweise 🙂 ) voll zustimmen. Beim nächsten Projekt zu Beginn besser gleich "Leeres Projekt" auswählen.

    Auch wenn ich mir schon denken kann, was dich in die Arme der MS-HalloWelt-Applikation getrieben hat. 😉



  • Kritiker schrieb:

    asc schrieb:

    "Leeres Projekt" auswählen

    Ja, kann asc (ausnahmsweise 🙂 ) voll zustimmen. Beim nächsten Projekt zu Beginn besser gleich "Leeres Projekt" auswählen.

    Auch wenn ich mir schon denken kann, was dich in die Arme der MS-HalloWelt-Applikation getrieben hat. 😉

    War sicher nicht der Grund den du denkst. Ich bin Java Programmierer. In meiner Ausbildung vor Jahren hatte ich auch c++. Leider ist das in Vergessenheit geraten weil ich damit lange nichts zu tun hatte. Visual Studio 8 habe ich eben original hier liegen und dachte mir: "Nimmste das eben wenn du es schon hast".

    Naja danke für die Hilfe, ich werde alles diese Woche noch ausprobieren und mich melden obs klappt.


Log in to reply