argv und Strings kopieren



  • Hi!
    Was soll das ganze dublizieren.
    Tuh doch einfach argv und argc speichern.

    typedef struct
    {
        int argc;
        char** argv;
    }cmdline_param;
    

    em ef ge
    d.



  • @ hartmut1164:
    Dein Vorschlag sieht eigentlich genauso aus wie meiner - ein String ist doch ein Array, oder übersehe ich da jetzt ein paar Details?
    Die Null soll wirklich als String vorhanden sein, da das praktisch mein Zeichen ist, dass ein Parameter nicht übergeben wurde. Ich könnte es wohl auch um einen Byte verkürzen, vielleicht tue ich das ja noch.

    @ feraL:
    Ich weiß, dass es diverse Funktionen gibt - aber was ich selbst schreibe, verstehe ich besser - und außerdem kann ich (falls nötig) die Funktion an das aktuelle Programm anpassen. Ansonsten scheint dein strdup die gleiche Arbeit zu leisten, wie mein _string_copy :).

    Das ganze soll erstmal alle möglichen Kommandozeilen-Parameter übernehmen, sortieren und (im geänderten Array) leicht zu Abfragen zur Verfügung stellen. Deshalb ist mein Array wohl auch etwas überlang (26 Strings momentan - für jeden Buchstaben eine Möglichkeit). So kann ich innerhalb des Programms leicht mit einer if-Abfrage auf das "i." Feld des Arrays zugreifen und weiß sofort, ob der Parameter i übergeben wurde (z.B. i50) oder nicht ('0').
    Falls es da wesentlich leichtere (und elegantere) Möglichkeiten gibt, die trotzdem die volle Flexibilität bieten, würde es mich freuen, wenn sie mir jemand mitteilen könnte.

    @ dublikat0r:
    Das bringt mich nicht ans Ziel, meine Parameter sollen bei der Eingabe keiner festen Reihenfolge unterliegen, beliebig kombiniert werden usw. Bisher habe ich immer auf argv[argc] o.ä. zugegriffen, musste jedoch einige Proben durchführen, um herauszufinden, ob ein Parameter übergeben wurde.

    Was mich noch immer wurmt:
    Warum gehen diese Code-Zeilen nicht?

    Puffer[ argv[i + 1][0] - 97 ] = realloc(Puffer[ argv[i + 1][0] - 97] , slaenge * sizeof(char));
    if(Puffer[argv[i + 1][0] - 97][0] == 48) 
                _string_copy( Puffer[argv[i + 1][0] - 97] , argv[i + 1] );
    

    Die letzte ist ziemlich unnötig (fiel mir ja nach einer Weile auf 😉 ), aber ich erkenne bei keiner der Zeilen einen Fehler.



  • Stiefel2000 schrieb:

    @ dublikat0r:
    Das bringt mich nicht ans Ziel, meine Parameter sollen bei der Eingabe keiner festen Reihenfolge unterliegen, beliebig kombiniert werden usw. Bisher habe ich immer auf argv[argc] o.ä. zugegriffen, musste jedoch einige Proben durchführen, um herauszufinden, ob ein Parameter übergeben wurde.

    mit der struktur ist keine reihenfolge festgelegt, es wird lediglich argv und argc in einer struktur verpackt und kann einfach als parameter für weitere funktionen zur verfügung stehen, ohne das die argumente unnötig verdoppelt werden.



  • Stiefel2000 schrieb:

    @ hartmut1164:
    Dein Vorschlag sieht eigentlich genauso aus wie meiner - ein String ist doch ein Array, oder übersehe ich da jetzt ein paar Details?
    Die Null soll wirklich als String vorhanden sein, da das praktisch mein Zeichen ist, dass ein Parameter nicht übergeben wurde. Ich könnte es wohl auch um einen Byte verkürzen, vielleicht tue ich das ja noch.

    Es geht um folgenden Sequenz (bei Dir Zeile 4 und 5):

    Puffer[i] = malloc(2 * sizeof(char));
            Puffer[i] = "0";
    

    Im ersten Schritt weisst dem Pointer Puffer[i] Arbeitsspeicher zu (2 * char). Dann nimmst Du aber den Pointer unverbiegst ihn auf eine Stelle im Arbeitsspeicher in der der String konstant "'0','/0'" steht. Dabei bleibt die allocierte Stelle im Arbeitsspeicher unbeschrieben, aber nur der Pointer verbogen.

    Puffer [i] ist kein String (C kennt diesen Datentyp nicht), sondern nur die Representation der ersten Position eines Strings.



  • Stiefel2000 schrieb:

    ein String ist doch ein Array, oder übersehe ich da jetzt ein paar Details?

    weder ein Array, noch ein Pointer. Ein String ist eine mit \0 abgeschlossene Folge von Zeichen, das ist ein gewaltiger Unterschied. Man kann diese Liste in ein Array speichern, und darauf mit einem Zeiger zugreifen. Du musst nur die C Grundlagen über Arrays und Zeiger nochmal lernen, denn wer

    Puffer[i] = malloc(2 * sizeof(char));
            Puffer[i] = "0";
    

    schreibt, hat es eindeutig nicht verstanden.



  • Sag mir mal, ab wo es falsch wird:

    char * test = "test";
    
    char * test;
    test = "test";
    
    char * test[2] = {"test1" , "test2"};
    
    char * test[2];
    test[0] = "test1";
    test[1] = "test2";
    
    char ** test = malloc(2*sizeof(char*));
    test[0] = "test1";
    test[1] = "test2";
    
    char ** test = malloc(2*sizeof(char*));
    test[0] = malloc(6*sizeof(char));
    test[0] = "test1";
    test[1] = "test2";
    

    Das alles erzeugt bei mir gültigen C-Code, sollte es meinem Verständnis nach auch. Es wäre nett, wenn du mir mal ganz langsam auf die Sprünge helfen könntest - allzu kompliziert kann das ganze ja nicht sein.



  • Stiefel2000 schrieb:

    char ** test = malloc(2*sizeof(char*));
    test[0] = malloc(6*sizeof(char));
    test[0] = "test1";
    test[1] = "test2";
    

    das ist falsch, hartmut hat es dir bereits erklärt. Wenn du aber hartmuts Erklärung nicht verstehst, dann solltest du lieber sofort dein C-Grundlagen Buch und die Kapitel Pointer, Malloc und Strings *nochmal* durcharbeiten.

    Stiefel2000 schrieb:

    Das alles erzeugt bei mir gültigen C-Code, sollte es meinem Verständnis nach auch.

    kompilierbarer Code != fehlerfreier Code, sonst gäbe es keine Software-Bugs



  • Heißt "falsch" einfach, dass ich mir die malloc-Zeile sparen soll (das wäre dann nicht wirklich falsch, sondern überflüssig)?

    test[0] = "test1";
    

    Auf der rechten Seite erstelle ich ein char-Array, das einen Pointer an die linke Seite übergibt - zufällig darf ich dort auch Pointer speichern. Daran stört mich also nichts. Eventuell habe ich vorher mit malloc einen anderen Speicherbereich reserviert, in der Erwartung, dass ich diesen Speicher anschließend beschreibe.

    Übrigens habe ich kein C-Grundlagenbuch und da ich noch immer vermute, dass es hier um ein winziges Verständnisproblem geht, wäre es wesentlich nützlicher, wenn mir jemand in zwei Sätzen genau erklärt, was falsch ist.

    Ich habe auch mal den Inhalt der Variablen des letzten Feldes ausgeben lassen, das sieht so aus:

    003F2690  //Adresse von test[0] unmittelbar nach dem malloc
    003F2610  //Adresse von test (**)
    00403004 + 0040300A  //Adressen von test[0] und test[1] nach dem Beschreiben
    test1 + test2  //Inhalt der beiden Arrays
    


  • Stiefel2000 schrieb:

    Übrigens habe ich kein C-Grundlagenbuch und da ich noch immer vermute, dass es hier um ein winziges Verständnisproblem geht, wäre es wesentlich nützlicher, wenn mir jemand in zwei Sätzen genau erklärt, was falsch ist.

    Es geht leider nicht um ein "winziges Verständnisproblem", sondern um ein sehr grundsaetzliches Problem. Wenn Du leidlich Englisch kannst, dann empfehle ich das hier als C-Buch (einer der wenigen Faelle, wo sogar empfehlen wuerde die rund 80 Seiten auzudrucken und sich als Ringhefter hinzustellen):

    http://www.oucs.ox.ac.uk/documentation/userguides/c/l922.pdf



  • supertux schrieb:

    char ** test = malloc(2*sizeof(char*));
    test[0] = malloc(6*sizeof(char));
    test[0] = "test1";
    test[1] = "test2";
    

    das ist falsch, hartmut hat es dir bereits erklärt. Wenn du aber hartmuts Erklärung nicht verstehst, dann solltest du lieber sofort dein C-Grundlagen Buch und die Kapitel Pointer, Malloc und Strings *nochmal* durcharbeiten.

    Nein, falsch ist das nicht. Es ist Schwach-/Unsinnig, weil Speicherplatzverschwendung.



  • Stiefel2000 schrieb:

    char * test = "test";
    
    char * test;
    test = "test";
    
    char * test[2] = {"test1" , "test2"};
    
    char * test[2];
    test[0] = "test1";
    test[1] = "test2";
    
    char ** test = malloc(2*sizeof(char*));
    test[0] = "test1";
    test[1] = "test2";
    
    char ** test = malloc(2*sizeof(char*));
    test[0] = malloc(6*sizeof(char));
    test[0] = "test1";
    test[1] = "test2";
    

    ^^
    diese ganzen zuweisungen arbeiten mit adressen. z.b:

    char * test[2];     // ein array, das 2 adressen aufnehmen kann
    test[0] = "test1";  // erstes element bekommt die adresse von "test1"
    test[1] = "test2";  // zweites element bekommt die adress von "test2"
    

    dabei sind "test1" und "test2" zwei strings, die in einem (von deinem programm aus) nicht beschreibbaren speicher liegen. test[0] und test[1] zeigen nach den zuweisungen auf diese strings. ein kopieren der strings findet nicht statt.
    was anderes wäre das:

    char test[] = "test1";
    

    ^^dabei wird das array test[] mit den zeichen t,e,s,t,1,\0 initialisiert, also es wird wirklich was rüberkopiert.
    🙂



  • blubb schrieb:

    supertux schrieb:

    char ** test = malloc(2*sizeof(char*));
    test[0] = malloc(6*sizeof(char));
    test[0] = "test1";
    test[1] = "test2";
    

    das ist falsch, hartmut hat es dir bereits erklärt. Wenn du aber hartmuts Erklärung nicht verstehst, dann solltest du lieber sofort dein C-Grundlagen Buch und die Kapitel Pointer, Malloc und Strings *nochmal* durcharbeiten.

    Nein, falsch ist das nicht. Es ist Schwach-/Unsinnig, weil Speicherplatzverschwendung.

    Nicht nur das: Die Sache mal aus der Sicht des Betriebsystems. Der Prozess hat Speicher angefordert (eben im malloc) und wird ordnungsgemaess beendet. Weil aber die Referenz zum angeforderten Speicher nicht zu finden ist, diese deshalb auch nicht mit free () freigeben werden kann, stellt das Betriebssystem fest, dass dort noch Speicher existiert, der vom Prozess selber nichaufgeraeumt wurde und mossert.



  • Das Problem muss ja hochkomplex sein, wenn keiner von euch in der Lage ist, es mir kurz und knapp zu erklären 🤡.

    @ +fricky: Das mit den Zeigern war mir natürlich klar, aber der Hinweis von dir, dass bei der einen Schreibweise was kopiert wird, war noch ganz nützlich (das wusste ich nämlich nicht).

    @ hartmut1164: Vielen Dank für den Link, ich werde mir das Werk ansehen, sobald ich Zeit habe.

    Die Essenz eurer zahlreichen Beschwerden an mich ist also, dass ich an der Stelle, an der ich eigentlich einen Speicherbereich beschreiben wollte,

    char ** test = malloc(1*sizeof(char*)); 
    /*test[0] = malloc(6*sizeof(char));*/
    test[0] = "test1"; //diese Zeile meine ich
    

    eine Zuweisung zu einem anderen Speicherbereich durchgeführt habe. Darf ich das so stehen lassen und als "wieder was gelernt" verbuchen?

    Falls ja: Wie würde ich denn meinem 6-Byte langen dynamischen Char-Array einen String zuweisen können? Nur über den Zugriff auf die einzelnen Elemente (also zeichenweise)?



  • Stiefel2000 schrieb:

    ...aber der Hinweis von dir, dass bei der einen Schreibweise was kopiert wird, war noch ganz nützlich (das wusste ich nämlich nicht).

    das geht aber nur so, wenn die variable frisch angelegt wird. später im code dann nicht mehr.

    Stiefel2000 schrieb:

    Falls ja: Wie würde ich denn meinem 6-Byte langen dynamischen Char-Array einen String zuweisen können? Nur über den Zugriff auf die einzelnen Elemente (also zeichenweise)?

    etwa so:

    char *str = malloc(6);  // speicher für 6 zeichen holen
    ...
    strcpy (str, "hallo"); // füllen mit h,a,l,l,o,\0 achtung: nur sizeof(str)-1 zeichen (ausser der 0) sind möglich.
    ...
    free(str);  // <-- wenn der speicher nicht mehr gebraucht wird
    

    🙂



  • blubb schrieb:

    Nein, falsch ist das nicht. Es ist Schwach-/Unsinnig, weil Speicherplatzverschwendung.

    und damit falsch 😉

    Stiefel2000 schrieb:

    Das Problem muss ja hochkomplex sein, wenn keiner von euch in der Lage ist, es mir kurz und knapp zu erklären 🤡.

    Im Gegenteil, aber hier wird dir keiner etwas erklären, was du nicht selbst mit einem Grundlagen Buch lernen kannst. Viele deiner Fragen kommen durch das Fehler von gewissen Grundlagenwissen wie "was ist ein String", "was ist ein konstantes Literal", usw.



  • supertux schrieb:

    ...aber hier wird dir keiner etwas erklären, was du nicht selbst mit einem Grundlagen Buch lernen kannst...

    manche lernen leichter wenn sie jemanden fragen, anstatt aus büchern. wie auch immer, programmieren lernt man sowieso nur durch übung.
    🙂



  • @ +fricky: Das mit strcpy hätte ist mal eine Idee, darauf wäre ich niee gekommen ;). Aber ich habe wirklich nicht daran gedacht, obwohl ich in meinem Quelltext oben genau das mache...

    Eine Antwort auf meine Frage im letzten Post wäre ganz nett, ich hoffe noch immer, dass die Unklarheiten damit beseitigt wären.

    Die Essenz eurer zahlreichen Beschwerden an mich ist also, dass ich an der Stelle, an der ich eigentlich einen Speicherbereich beschreiben wollte, eine Zuweisung zu einem anderen Speicherbereich durchgeführt habe. Darf ich das so stehen lassen und als "wieder was gelernt" verbuchen?


Anmelden zum Antworten