Malloc Array bequemer ansprechen


  • Mod

    Mal zum Thema Kritik ^^ völlig daneben:
    Ohne Cast wird

    int *MyArray=0;
    MyArray = (int *)malloc(n*m);
    

    keinen Deut besser. Es ist immer noch völlig falsch.



  • camper schrieb:

    Es ist immer noch völlig falsch.

    sollte wohl

    MyArray = malloc(n*m*sizeof(int));
    

    sein.
    und den überflüssigen cast^^ hab' ich auch schon weggemacht
    🙂


  • Mod

    sizeof-freak schrieb:

    camper schrieb:

    Es ist immer noch völlig falsch.

    sollte wohl

    MyArray = malloc(n*m*sizeof(int));
    

    sein.
    und den überflüssigen cast^^ hab' ich auch schon weggemacht
    🙂

    es sollte sein:

    MyArray = malloc(n*m*sizeof *MyArray);
    

    Das Weglassen des Casts bringt überhaupt keinen Gewinn, wenn du den Typen dafür an andere Stelle wieder einführst.

    Natürlich ist es leichter, sich irgendwelche Regeln wie "caste niemals das Ergebnis von malloc" sinnlos zu merken, als zu versuchen, den Sinnzusammenhang dahinter zu verstehen.



  • camper schrieb:

    es sollte sein:

    MyArray = malloc(n*m*sizeof *MyArray);
    

    stimmt. das ist meistens besser.

    camper schrieb:

    Natürlich ist es leichter, sich irgendwelche Regeln wie "caste niemals das Ergebnis von malloc" sinnlos zu merken...

    das schimpft sich 'best practice'. man kann malloc casten, aber dadurch können fehler kaschiert werden. ausserdem sollte man sowieso nur casten, wenn man unbedingt muss.
    🙂


  • Mod

    malloc-freak schrieb:

    das schimpft sich 'best practice'. man kann malloc casten, aber dadurch können fehler kaschiert werden. ausserdem sollte man sowieso nur casten, wenn man unbedingt muss.

    Man kann es bleiben lassen, malloc zu casten, und gerade dadurch Fehler kaschieren. Oh... genau das ist oben passiert. Das man nie casten sollte, wo es nicht notwendig ist, wäre im Prinzip aus sich heraus evident, wenn es nicht zu viele Fälle gäbe, in denen Konvertierungen ohne Cast möglich sind. Ich will damit nicht die Position (die ich durchaus teile) angreifen, die besagt, dass der Cast überflüssig ist - nur dass man dort nicht stehen bleiben sollte und, wenn man oberflächlich damit umgeht, das sogar zu weniger Sicherheit führen kann.



  • Da habt Ihr einen Fehler entdeckt noch bevor mir das Programm um die Ohren geflogen ist*g*
    Vielen Dank 🙂



  • camper schrieb:

    Man kann es bleiben lassen, malloc zu casten, und gerade dadurch Fehler kaschieren. Oh... genau das ist oben passiert.

    wie hätte ein cast daran was verbessern können?

    camper schrieb:

    Das man nie casten sollte, wo es nicht notwendig ist, wäre im Prinzip aus sich heraus evident, wenn es nicht zu viele Fälle gäbe, in denen Konvertierungen ohne Cast möglich sind.

    ist aber nie was schlimmes dabei. void* in einen typed-* oder char nach int usw. sind doch meistens harmlos. und ganz entmündigen sollte man den coder auch nicht.

    camper schrieb:

    nur dass man dort nicht stehen bleiben sollte und, wenn man oberflächlich damit umgeht, das sogar zu weniger Sicherheit führen kann.

    klar, ich bin auch bestimmt der letzte, der irgendwelche regeln kritiklos hinnimmt. aber wenn man malloc castet hat man absolut nix gewonnen. ausser man will, dass der code zu irgendwelchen uralt-compilern kompatibel ist. da gab malloc, glaube ich, einen char* zurück..
    🙂



  • Ich weiss gar nicht warum ich das überhaupt geschrieben habe...
    http://www.c-plusplus.net/forum/viewtopic.php?t=206606


  • Mod

    nevercastmalloc-freak schrieb:

    camper schrieb:

    Man kann es bleiben lassen, malloc zu casten, und gerade dadurch Fehler kaschieren. Oh... genau das ist oben passiert.

    wie hätte ein cast daran was verbessern können?

    Ein cast kann etwas mehr Sicherheit hineinbringen wenn der sizeof-Ausdruck im malloc-Aufruf mit einem Typen arbeitet (was er nicht tun sollte, aber darauf wird hier viel seltener rumgeritten). Warum? Weil dann Cast und sizeof-Operand (bis auf den Poin ter-Deklarator) optisch identisch sein müssen, und der Cast bei der anschließenden Zuweisung dem Compiler die Gelegenheit gibt, dies mit dem tatsächlichen Typ des Zeigers zu vergleichen.

    foo* ptr;
    ptr = malloc( n * sizeof *ptr );       // (1)
    ptr = (foo*)malloc( n * sizeof *ptr ); // (2)
    ptr = malloc( n * sizeof(foo) );       // (3)
    ptr = (foo*)malloc( n * sizeof(foo) ); // (4)
    

    Alle diese Varianten existieren in realem Code (und vor allem (3) ist extrem verbreitet - jeder Anfänger scheint das zu nutzen). Natürlich ist hier (1) die absolut vorzuziehende Variante. Ich behaupte aber, dass (4) besser als (2) und (3) ist. Nicht mehr und nicht weniger. Ändert jemand den Typ von ptr, so funktioniert (1) sofort ohne Änderung (perfekt), (2) und (4) werden vom Compiler verworfen, bis sie angepasst werden (nicht so gut), (3) läuft einfach durch und beschert uns stundenlanges Debugging (ganz schlecht). (4) ist (2) insofern überlegen, als wir hier zusätzlich eine optische Kontrolle haben, ob der Aufruf in sich stimmig ist. Im Vergleich zu (3) gewinnen wir tatsächlich etwas mit dem Cast - und genau diese Situation hatten wir oben.

    camper schrieb:

    Das man nie casten sollte, wo es nicht notwendig ist, wäre im Prinzip aus sich heraus evident, wenn es nicht zu viele Fälle gäbe, in denen Konvertierungen ohne Cast möglich sind.

    ist aber nie was schlimmes dabei. void* in einen typed-* oder char nach int usw. sind doch meistens harmlos. und ganz entmündigen sollte man den coder auch nicht.

    Wer redet von entmündigen? Du willst dem Coder doch das casten verbieten :p
    "nie" was schlimmes -> "meistens" harmlos ? Hier mangelt es auch an innerer Logik. Und natürlich ist ein Loch im Typsystem - da jeder Objektpointer in void* konvertierbar ist, und umgekehrt, kann man jeden Objektzeiger in jeden anderen konvertieren, wenn ein void* als Mittler (z.B. Funktionsaufrufen) dabei ist, ohne dass das irgendwo ausdrücklich erkennbar ist. Natürlich kann es gut gehen, aber es ist eben ein Risiko.



  • camper schrieb:

    foo* ptr;
    ptr = malloc( n * sizeof *ptr );       // (1)
    ptr = (foo*)malloc( n * sizeof *ptr ); // (2)
    ptr = malloc( n * sizeof(foo) );       // (3)
    ptr = (foo*)malloc( n * sizeof(foo) ); // (4)
    

    (1) ist die beste variante, weil sie allgemein ist, keine frage. funzt nur nicht mehr, wenn foo ein void* ist.
    (2) ist echt mist. der cast beisst sich logisch mit dem sizeof(*ptr) im malloc-aufruf.
    (3) ist eigentlich ok. nur nicht so flexibel wie (1). sieht man am häufigsten und in der realität ist es eher unproblematisch, weils ja immer noch passt, wenn sich die grösse von foo ändert.
    (4) wie (3), aber begünstigt schreibfehler. machste das sternchen an die falsche stelle oder zwei sternchen oder gar keins hin, sieht's optisch zwar toll aus, compiled vielleicht auch, aber fliegt dir um die ohren.

    ptr = (foo)malloc( n * sizeof(foo) );   // (5) <-- fehler wegen des cast, aber optisch gutaussehend weil symmetrisch
    ptr = (foo*)malloc( n * sizeof(foo*) ); // (6) <-- auch falsch, aber für das ungeübte auge schwerer zu erkennen
    

    ohne cast, finde ich, sind die fehlermöglichkeiten grösser. code den man nicht schreibt, kann eben nicht falsch sein. so einfach ist das.
    🙂



  • ^^äääh 'mit cast sind die fehlermöglichkeiten grösser', sorry, war zu schnell.
    🙂



  • Ihr wollt jetzt aber nicht ernsthaft diskutieren, welche schlechte Lösung schlechter ist?



  • Tim schrieb:

    Ihr wollt jetzt aber nicht ernsthaft diskutieren, welche schlechte Lösung schlechter ist?

    klar, ist doch lustig.
    🙂


Anmelden zum Antworten