[ANFÄNGER] c++ Speicherzugriffsfehler (Speicherabzug geschrieben) (String Array)



  • Moin moin....
    Als erstes.... ich bin der neue hier im Forum 😃

    Ich befasse mich jetzt seit einigen Tagen mit C++ und bin jetzt auf ein Problem gestoßen, wo ich keine Ahnung hab wo das her kommt....

    Ich rufe eine Funktion auf, die eine neue Datei anlegt, und in diese Datei einen String Array rein speichert....
    Der Inhalt des Arrays ist ja erstmal egal... wichtig ist das ich (in diesem Beispiel) 10 Strings (im eigentlichen Code sind 41) alle in eine eigene Zeile geschrieben haben möchte....
    Also... im Beispiel 10 Zeilen, im Code sinds 42

    [...] 
    bool someClass::doSomthing() {
       [...] // Do some stuff then
       setConfig();
       // do some other stuff
       [...]
       return true;
    }
    void someClass::setConfig() {
        std::string inhalt[10];
    
        inhalt[0] = "Zeile 1";
        inhalt[1] = "Zeile 2";
        inhalt[2] = "Zeile 3";
        inhalt[3] = "Zeile 4";
        inhalt[4] = "Zeile 5";
        inhalt[5] = "Zeile 6";
        inhalt[6] = "Zeile 7";
        inhalt[7] = "Zeile 8";
        inhalt[8] = "Zeile 9";
        inhalt[9] = "Zeile 10";
    
        std::fstream output;
        output.open ("my.txt", std::fstream::in | std::fstream::out | std::fstream::app);
    
        for(int i=0; i < 10; i++ ){
            output << inhalt[i] << std::endl;
        }
        output.close();
    }
    

    doSomething ruft also setConfig auf.... Das Program crasht mit der Meldung Speicherzuriffsfehler...
    In einer anderen IDE den Code compiled und da steigt er mit der Meldung: free() invalid pointer: 0x00007fe956d5be00... Schmeiß ich den Debugger der IDE an bekomme ich bei inhalt[9].... die meldung das das Programm abgestürzt ist...
    Interessanter weise wird die datei my.txt aber vollständig erstellt....

    Vergrößere ich das Array um 1 (also im beispiel auf 11) und erweiter die forschleife ebenfalls um 1 (i < 11) ... ist der fehler verschwunden.....

    Was hab ich falsch gemacht?

    Denkt bitte dran.... ich befasse mich da erst wenige Tage damit
    Gruß
    Sada


  • Mod

    Sadakazu schrieb:

    Was hab ich falsch gemacht?

    Ist am gezeigten Code nicht erkennbar. Was vermuten lässt, dass ein anderer Teil deines Programmes fehlerhaft ist.
    Poste Code, der so vollständig ist, dass er compiliert und das Problem damit reproduziert werden kann.



  • Ok, hatte gehofft das kleine bisschen reicht schon..... ^^

    #include <iostream>
    #include <fstream>
    
    bool doSomething();
    void getStdCfg();
    
    bool doSomething() {
        std::cout << "bla bla bla" << std::endl;
    
        int a = 5;
        int b = 493479;
    
        int c = a*b;
    
        getStdCfg();
    
        std::cout << "Und das ergebniss von " << a << "*" << b << "=" << c << std::endl;
        return true;
    }
    
    void getStdCfg() {
    
        std::string line[41];
        line[0] = "player_limit: -1";
        line[1] = "ip_forward: false";
        line[2] = "permissions:";
        line[3] = "  default:";
        line[4] = "  - bungeecord.command.server";
        line[5] = "  - bungeecord.command.list";
        line[6] = "  admin:";
        line[7] = "  - bungeecord.command.alert";
        line[8] = "  - bungeecord.command.end";
        line[9] = "  - bungeecord.command.ip";
        line[10] = "  - bungeecord.command.reload";
        line[11] = "timeout: 30000";
        line[12] = "log_commands: false";
        line[13] = "online_mode: true";
        line[14] = "servers:";
        line[15] = "  lobby:";
        line[16] = "    motd: '&1Just another BungeeCord - Forced Host'";
        line[17] = "    address: localhost:25566";
        line[18] = "    restricted: false";
        line[19] = "listeners:";
        line[20] = "- query_port: 25565";
        line[21] = "  motd: '&cAnother BungeeCord'";
        line[22] = "  priorities:";
        line[23] = "  - lobby";
        line[24] = "  bind_local_address: true";
        line[25] = "  tab_list: GLOBAL_PING";
        line[26] = "  query_enabled: false";
        line[27] = "  host: 127.0.0.1:25565";
        line[28] = "  forced_hosts:";
        line[29] = "    pvp.md-5.net: pvp";
        line[30] = "  max_players: 10";
        line[31] = "  tab_size: 60";
        line[32] = "  ping_passthrough: false";
        line[33] = "  force_default_server: false";
        line[34] = "disabled_commands:";
        line[35] = "- disabledcommandhere";
        line[36] = "network_compression_threshold: 256";
        line[37] = "groups:";
        line[38] = "  md_5:";
        line[39] = "  - admin";
        line[40] = "connection_throttle: 4000";
        line[41] = "stats: 75684394-9962-4aa3-a237-75851b1a1d1f";
    
        std::fstream output;
    
        output.open ("config.yml", std::fstream::in | std::fstream::out | std::fstream::app);
    
        for(int i=0; i < 41; i++ ){
            output << line[i] << std::endl;
        }
        output.close();
    
    }
    
    int main(int argc, char *argv[])
    {
        int a;
        doSomething();
    
        std::cin >> a;
    
        return 0;
    
    }
    

    Und bitte kein kommentar zu dem sinn oder unsinn xD auch das ist nur ein Schnipsel... aber dort tritt der fehler genauso auf wie im eigentlichen Code......


  • Mod

    Dein string-Array hat nur 41 Elemente, aber du schreibst noch in das 42. Element (line[41]).



  • Sadakazu schrieb:

    std::string line[41];
    line[41] = …;
    

    Fällt dir hir was auf? 😉



  • Also hatte ich doch recht... wenn ich das Array um 1 erweiter funktionierts....
    Im anderen forum gabs dann ne antwort.. ja kann sein aber dann hast nur die speicherzelle verdeckt ....

    Aber JETZT wo du es sagst.. JAAA manchmal sieht man den Wald vor lauter bäumen nicht...
    klar... ich inizialisiere 41 strings, schreibe aber 42 stück auf ^^ plöd


  • Mod

    Wobei es normalerweise keinen guten Grund, Arrays überhaupt auf diese Art und Weise zu verwenden. Werden sie direkt initialisiert, kann der Compiler die Größe selbst herausfinden. In anderen Fällen ist ein normaler Container angebracht.

    void getStdCfg() {
    
        std::string lines[] = {  // !!!
           "player_limit: -1",
           "ip_forward: false",
           "permissions:",
           "  default:",
    // ...
           "connection_throttle: 4000",
           "stats: 75684394-9962-4aa3-a237-75851b1a1d1f" };
    
        std::fstream output("config.yml", std::fstream::app);
    
        for (auto& line: lines){
            output << line << '\n';
        }
    }
    


  • wobei mir das komischerweise die YML zerhackt.... auch wenn ich statt \n ein << std::endl; mache...

    Mach ich das mit meiner "methode" ist die YML okay....



  • Sadakazu schrieb:

    wobei mir das komischerweise die YML zerhackt.... auch wenn ich statt \n ein << std::endl; mache...

    Dann machst du irgendwo irgendwas falsch, denn campers Weg tut dasselbe wie deiner (sofern du die richtigen Indizes verwendest).

    Du kannst übrigens auch Mehrzeilen-Strings verwenden:

    auto multiLineString = R"xxxx(#erste Zeile
    ...
    hier der Inahlt
    ...
    )xxxx";
    

    Statt xxxx kannst du auch jeden anderen Begrenzerstring wählen.



  • std::vector<std::string> lines;
    lines.push_back("abc");
    lines.push_back("123");
    // maybe more push_back
    
    for (const std::string& line : lines)
      output << line << '\n';
    


  • Dann machst du irgendwo irgendwas falsch, denn campers Weg tut dasselbe wie deiner (sofern du die richtigen Indizes verwendest).

    Ne, wohl ehr unglücklich ausgedrückt...
    Die config.yml sieht genau gleich aus, das ist richtig...
    Aber sie hat irgendwo einen Formatierungsfehler weswegen diese config nicht funktioniert...
    Hab erst gedacht das es vielleicht am \n liegt und hab deswegen std::endl versucht... aber da hat die config.yml auch nicht funktioniert....
    vergleiche ich die beiden dateien, sehen sie optisch genau gleich aus.... diese sch* yml dateien sind extrem empfindlich.....

    Und ich wage zu bezweifeln das man bei copy&paste irgendwo was "falsch" machen kann 😉

    wo ist der Vorteil von vector? durch das lines.push_back() hab ich doch ehr deutlich mehr schreibarbeit mit.... oder?



  • Sadakazu schrieb:

    wo ist der Vorteil von vector? durch das lines.push_back() hab ich doch ehr deutlich mehr schreibarbeit mit.... oder?

    stimmt schon, in diesem Fall wäre eine Initialisierungsliste wohl günstiger, das hat camper ja schon für den array-Fall gezeigt.



  • Ja nur wie schon gesagt, funktioniert die config.yml datei nicht (mehr)...
    mit meinem lines[0] = "bla"; funktioniert es..... komischerweise....

    Wie gesagt.. optisch sehen sie absolut identisch aus..... aber die config.yml verursacht später im bungeecord schwerwiegende fehler....



  • Guck dir den Unterschied mit einem geeignetem Werkzeug an (diff, WinMerge, ...).



  • Ehm lol?

    std::string line[42];
    	line[0] = "player_limit: -1";
    	line[1] = "ip_forward: false";
    	line[2] = "permissions:";
    	line[3] = "  default:";
    	line[4] = "  - bungeecord.command.server";
    	line[5] = "  - bungeecord.command.list";
    	line[6] = "  admin:";
    	line[7] = "  - bungeecord.command.alert";
    	line[8] = "  - bungeecord.command.end";
    	line[9] = "  - bungeecord.command.ip";
    	line[10] = "  - bungeecord.command.reload";
    	line[11] = "timeout: 30000";
    	line[12] = "log_commands: false";
    	line[13] = "online_mode: true";
    	line[14] = "servers:";
    	line[15] = "  lobby:";
    	line[16] = "    motd: '&1Just another BungeeCord - Forced Host'";
    	line[17] = "    address: localhost:32000";
    	line[18] = "    restricted: false";
    	line[19] = "listeners:";
    	line[20] = "- query_port: 25565";
    	line[21] = "  motd: '&1Just another BungeeCord'";
    	line[22] = "  priorities:";
    	line[23] = "  - lobby";
    	line[24] = "  bind_local_address: true";
    	line[25] = "  tab_list: GLOBAL_PING";
    	line[26] = "  query_enabled: false";
    	line[27] = "  host: 127.0.0.1:25565";
    	line[28] = "  forced_hosts:";
    	line[29] = "    pvp.md-5.net: pvp";
    	line[30] = "  max_players: 10";
    	line[31] = "  tab_size: 60";
    	line[32] = "  ping_passthrough: false";
    	line[33] = "  force_default_server: false";
    	line[34] = "disabled_commands:";
    	line[35] = "- disabledcommandhere";
    	line[36] = "network_compression_threshold: 256";
    	line[37] = "groups:";
    	line[38] = "  md_5:";
    	line[39] = "  - admin";
    	line[40] = "connection_throttle: 4000";
    	line[41] = "stats: 75684394-9962-4aa3-a237-75851b1a1d1f";
    
    	std::fstream output;
    	output.open ("./proxy/config.yml", std::fstream::in | std::fstream::out | std::fstream::app);
    
    	for(int i=0; i < 42; i++ ){
    		output << line[i] << std::endl;
    	}
    	output.close();
    

    groups:
    md_5:
    - admin
    ip_forward: false
    network_compression_threshold: 256
    stats: 75684394-9962-4aa3-a237-75851b1a1d1f
    permissions:
    default:
    - bungeecord.command.server
    - bungeecord.command.list
    admin:
    - bungeecord.command.alert
    - bungeecord.command.end
    - bungeecord.command.ip
    - bungeecord.command.reload
    online_mode: true
    servers:
    lobby:
    motd: '&1Just another BungeeCord - Forced Host'
    address: localhost:32000
    restricted: false
    timeout: 30000
    listeners:
    - query_port: 25565
    motd: '&1Just another BungeeCord'
    priorities:
    - lobby
    bind_local_address: true
    tab_list: GLOBAL_PING
    query_enabled: false
    host: 127.0.0.1:25565
    forced_hosts:
    pvp.md-5.net: pvp
    max_players: 10
    tab_size: 60
    ping_passthrough: false
    force_default_server: false
    player_limit: -1
    disabled_commands:
    - disabledcommandhere
    log_commands: false
    connection_throttle: 4000

    Funktioniert zwar... aber warum macht er das?



  • Ja, schmeisst alles durcheinander, behält aber die wesentlichen Strukturen zusammen. Die Frage dürfte sein, wer 'er' ist.. dein snippet ist es jedenfalls nicht.



  • Eine idee wie man das herausfinden kann????
    Oder kann man vielleicht eine Datei aus dem programm selber "extrahieren" und an die richtige stelle kopieren? bei Java würde das ja gehen... würde a) den code schlanker machen und b) deutlich besser funktionieren.....

    Aber dann würde sich die frage stellen, wie kann ich ggf in der datei suchen um dort drin etwas zu verändern? zb ist die ip dort nur temporär erstmal als localhost drin...
    schöner würd ich's finden wenn ich die SystemIP da rein bekomme (funktion dafür existiert bereits).

    Hab nur noch keine ahnung wie ich die Datei entsprechend "manipulieren" kann 😃



  • Sadakazu schrieb:

    Oder kann man vielleicht eine Datei aus dem programm selber "extrahieren" und an die richtige stelle kopieren? bei Java würde das ja gehen... würde a) den code schlanker machen und b) deutlich besser funktionieren.....

    Was meinst du mit Datei aus dem programm selber "extrahieren"? Was willst du überhaupt erreichen?

    Aber dann würde sich die frage stellen, wie kann ich ggf in der datei suchen um dort drin etwas zu verändern? zb ist die ip dort nur temporär erstmal als localhost drin...

    Du könntest entweder einen Platzhalter reinsetzen, den du nachträglich ersetzt. Oder du machst das gleich bei der String-Erzeugung.

    Hab nur noch keine ahnung wie ich die Datei entsprechend "manipulieren" kann 😃

    YAML lesen/manipulieren funktioniert ganz gut mit yaml-cpp: https://github.com/jbeder/yaml-cpp/wiki/Tutorial



  • Was meinst du mit Datei aus dem programm selber "extrahieren"? Was willst du überhaupt erreichen?

    1.) ich hab grad noch den fehler gefunden warum die andere Methode mir die YML kaputt gemacht hat.... war mein fehler... hab irgendwo 2 leerzeichen gelöscht.... Funktioniert jetzt wunderbar..... so kanns temporär bleiben....

    2.) BungeeCord ist ein Java Proxy Server für Minecraft Server.... dieser soll heruntergeladen werden... in einen Ordner verschoben werden..... sofort eine passende Config für den Server erstellen (ip adresse, port anpassung usw) wo genau dieses Programm drauf ausgeführt wird....
    Entweder direkt passend erstellen.... oder eine angepasste config.yml aus dem programm "auspacken" und anschließend anpassen.....

    Allerdings... so wie es jetzt ist, kann ich auch meine Funktionen für IP und port etc nutzen um es wirklich individuell zu halten....


Anmelden zum Antworten