Diskussionsthread zu "Häufig gemachte Fehler und allgemeine Hinweise"

Disclaimer: Dieser Thread wurde aus dem alten Forum importiert. Daher werden eventuell nicht alle Formatierungen richtig angezeigt. Der ursprüngliche Thread beginnt im zweiten Post dieses Threads.


Spricht denn irgendetwas dagegen, strncpy zu verwenden, wenn strcpy auch gehen würde? (außer ein relativ kleiner Performance-Verlust)
Damit vermeidet man die Gefahr, das Codestückchen in dem strcpy vorkommt eventuell nochmal in anderem Kontext zu verwenden, in dem dann strncpy angebracht wäre.


Prinzipiell nicht - nur besteht eben die Gefahr, dass man [m]strncpy()[/m] falsch verwendet, weil man gerne mal vergisst, dem [m]‚‘[/m] seinen zusätzlichen Platz einzuräumen…

Diskussionsthread zu “Allgemeine Hinweise und häufig gemachte Fehler”
Ich hab zwecks Übersichtlichkeit im Originalthread mal einen neuen für Diskussionen aufgemacht. Eventuelle Fragen und Kommentare bitte hier posten.


Wenn man strncpy falsch anwendet, fehlt evtl das letzte Zeichen. Wenn man dagegen strcpy falsch verwendet, bzw. den Buffer zu klein macht und ihn munter darauf weiter schreiben lässt überschreibt man Daten, die später zu Fehlverhalten führen, das beim debuggen schwerer zu lokalisieren ist als wenn man das letzte Zeichen vermisst. Das Fehlverhalten ist auch sicherheitstechnisch bedenklich, wenn der String aus einer Benutzereingabe kommt.

Ein weiterer Punkt bei der Anwendung von strncpy ist, dass man dann oft erst darüber nachdenkt, wie groß man den Buffer überhaupt gemacht hat und dabei drauf kommt, dass dieser noch gar nicht oder falsch allokiert ist.
Wenn man die Funktionen mit der Größe von Buffer und der abschliesenden nicht beherrscht sollte man sich das lieber nochmal anschauen anstatt einfach die Funktion zu nehmen, die das vermeintlich einfacher macht.


Zu Punkt 7. Unnötige if-Verschachtelungen wollt ich nur mal sagen, dass der Philipsen uns das eingetrichtert hat, da man evtl. einen Fehler reinbaut, wenn man dann eigentlich in das if noch eine Anweisung hinzufuegen moechte, aber diese Anweisung wird dann ja immer ausgefuehrt, nicht nur wenn die Bedingung gilt :smiley:


Hm, könntest du den Satz noch mal umformulieren bitte? Ich verstehe den nicht wirklich… Nicht böse gemeint. :wink:


Laut Philippsen sollten wir keine einzeiligen if-Schleifen benutzen, sondern immer schön mit Klammern drum rum. Von “immer else dazu” hat er aber so weit ich weiß nix gesagt.


Ah so. Na darauf kam’s mir aber gar nicht an dabei. :stuck_out_tongue: Ich persönlich schreibe bei einzeiligen ifs keine Klammern dazu, deswegen hab ich das auch im Beispiel so gemacht. Aber worauf ich eigentlich hinweisen wollte, ist tiefe Verschachtelungen mehrerer ifs zu vermeiden wenn es geht. Und genauso unnötig lange Blöcke innerhalb von {}. :wink:


Also wenn

[quote]if COND
foo[/quote]
hat und einem danach auffaellt dass da bar mit rein muss und man die {}-Klammern vergisst, wird bar ja immer ausgefuehrt, nicht nur wenn COND gilt.
Wenn man aber gleich die {} drumsetzt, kann einem das nicht passieren.

Das wollte ich sagen.


Ja, das hab ich dann nach Erklärung von Velines auch verstanden. :slight_smile:
Wie gesagt, ich setze keine {} bei einzelnen Anweisungen, weil es mir vom Aussehen einfach besser gefällt und es mir selber noch nie passiert ist, dass ich bei einer if-Anweisung und mehreren Kommandos vergessen hab, die {} einzufügen.
Prinzipiell halte ich das aber für eine gute Idee (es zu tun), da ich den Fehler doch schon ein paar Mal korrigieren durfte. :smiley:


Wieso soll argv auf dem Stack liegen? Auf dem Stack liegt doch nur der Pointer.


Ach Ford, wofür haben wir denn den Diskussionsthread? :wink:

Naja, eben. Wenn ich mal kurz demonstrieren darf:

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char *argv[]) {
        char **tmp;
        int i;

        printf("%x\n", argv);
        printf("%x\n", argv[0]);
        tmp = (char **)realloc(argv, (argc + 2) * sizeof(char *));
        printf("%x\n", tmp);
        tmp[argc] = "Hi";
        tmp[argc+1] = "Ho";
        for (i = 0; i < argc; ++i)
                printf("%x: %s\n", tmp[i], tmp[i]);

        return EXIT_SUCCESS;
}

Das produziert auf meinem System:

~$ ./test a b c
bfad1bb4
bfad22a9
*** glibc detected *** ./test: realloc(): invalid pointer: 0xbfad1bb4 ***
======= Backtrace: =========
/lib/libc.so.6[0xb7e6bb00]
/lib/libc.so.6(__libc_realloc+0x1f6)[0xb7e6fb76]
/lib/libc.so.6[0xb7e6fc41]
/lib/libc.so.6(__libc_realloc+0x3c)[0xb7e6f9bc]
./test[0x80483f3]
/lib/libc.so.6(__libc_start_main+0xd8)[0xb7e1d7c8]
./test[0x8048311]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:02 984889     test
08049000-0804a000 rw-p 00000000 08:02 984889     test
0804a000-0806b000 rw-p 0804a000 00:00 0          [heap]
b7e07000-b7e08000 rw-p b7e07000 00:00 0
b7e08000-b7f2c000 r-xp 00000000 08:02 2498       /lib/libc-2.5.so
b7f2c000-b7f2d000 r--p 00124000 08:02 2498       /lib/libc-2.5.so
b7f2d000-b7f2f000 rw-p 00125000 08:02 2498       /lib/libc-2.5.so
b7f2f000-b7f32000 rw-p b7f2f000 00:00 0
b7f48000-b7f52000 r-xp 00000000 08:02 7976       /usr/lib/libgcc_s.so.1
b7f52000-b7f53000 rw-p 00009000 08:02 7976       /usr/lib/libgcc_s.so.1
b7f53000-b7f55000 rw-p b7f53000 00:00 0
b7f55000-b7f56000 r-xp b7f55000 00:00 0          [vdso]
b7f56000-b7f70000 r-xp 00000000 08:02 2496       /lib/ld-2.5.so
b7f70000-b7f71000 r--p 00019000 08:02 2496       /lib/ld-2.5.so
b7f71000-b7f72000 rw-p 0001a000 08:02 2496       /lib/ld-2.5.so
bfabe000-bfad3000 rw-p bfabe000 00:00 0          [stack]
Abgebrochen

(Man beachte die Adresse des Zeigers und den Adressbereich des Stacks)

Und auf einer Sun:

faui40a [~]> ./test a b c
ffbffb84
ffbffc84
0
Segmentation Fault

Nachtrag:
Ich habe meinen Kommentar im anderen Thread geändert. Auch unter Linux liegt alles auf dem Stack (auch die Inhalte von argv - wie man in meinem Beispiel ja sieht). Damit schlägt realloc() sowieso fehl. Das fragliche Programm, das mich zu dem Post animiert hat, hat nur funktioniert, weil der Ersteller vorher argv = NULL gemacht hat… Das geht zwar, aber ist mehr als nur böse IMHO.


Selbst wenn das argv Array auf dem Heap liegen würde dürfte darauf kein
realloc verwendet werden. Der Speicher wurde schließlich nicht mit der
Speicherverwaltung der C-Bibliothek allokiert. Wo das array und die Strings
letztendlich liegen ist Sache des Laders. Lediglich der Zeiger auf das Array
selbst muss auf dem Stack liegen.


Nachdem bereits über zwei Jahre vergangen sind, wäre es vielleicht mal an der Zeit, die “wichtig”-Markierung zu entfernen und diesen Thread (und den anderen auch) in die Liste der normalsterblichen Threads einzureihen. :slight_smile:


As you wish