Untypischer Laufzeitfehler durch malloc()
-
@EL-europ sagte in Untypischer Laufzeitfehler durch malloc():
Weshalb funktioniert diese Schleife obgleich die Abbruchbedingung lediglich die Zählvariable 'i' ist?
Der mittlere Ausdruck einer
for
Schleife wird als Bedingung ausgewertet. Die Regel dabei ist dass 0 alsfalse
gilt und alle anderen Werte alstrue
.D.h.
i
als Laufbedingung ist gleichbedeutend miti != 0
.Das selbe gilt z.B. auch in
if
Statements. Alsoif (i)
ist gleichbedeutend mitif (i != 0)
. Bei Zeigern hast du das vermutlich schon gesehen, da schreibt man gerne nurif (pointer)
stattif (pointer != 0)
oderif (pointer != NULL)
.Bei Integers finde ich persönlich es aber komisch. Kann man machen wenn 0 für "nichts" steht, z.B. wenn man in einem Integer einzelne Bits als Flags für etwas verwenden und dann mit
if (flags)
prüft ob irgend ein Flag gesetzt ist - da finde ich es noch OK. Wenn 0 aber einfach nur für die Zahl 0 steht wie in diesem Beispiel, würde ich eheri != 0
schreiben.ps: Ganz furchtbar finde ich
if (strcmp(a, b))
. Diese Bedindung ist wahr wennstrcmp(a, b)
etwas anderes als 0 zurückgibt, und das tut sie wenn die Strings unterschiedlich sind. Da kann man sich beim schnell drüberlesen leicht vertun und fälschlicherweise annehmen dass der Block betreten wird wenn die Strings gleich sind.
-
@EL-europ sagte in Untypischer Laufzeitfehler durch malloc():
@Swordfish
Also kann ich mit "if defined" nur Eigenschaften des eingesetzten Compilers abfragen?Der C Präprozessor überprüft damit nur, ob eine Variable des Präprozessors definiert wurde. Beispiel
#include <stdio.h> #include <stdlib.h> int main () { #ifdef LINUX printf("Linux\n"); #else printf("anything else\n"); #endif return EXIT_SUCCESS; }
#ifdef
ist die Kurzform von#if defined
. Man kann auf der Kommandozeile beim Übersetzen mit dem gcc "-D" + "NAME" angeben, so dass die Variable definiert wird:gcc -DLINUX example.c -o example
übersetzt den Code in der einen Variante und ohne in der anderen.
-
@EL-europ sagte in Untypischer Laufzeitfehler durch malloc():
Ohne die Kommentare würde mein Code völlig unleserlich sein, man bräuchte Notizen und müsste sich viel mehr im Gedächtnis behalten;
Dann weißt Du jetzt ja warum ich
@EL-europ sagte in Untypischer Laufzeitfehler durch malloc():
Aber Ich glaube die curses kommt mit schnellen Tastenanschlägen nicht so klar. wenn ich im "Automove-modus" eine Zeit (ca. 3-5min) lang spiele, stürzt das Programm einfach ab. Kannst du mir nochmal Helfen?
nicht beantworten wollte ^^
-
@john-0
Das Funktioniert so wie du schreibst. Doch in dem Übungsprogramm
steht '#if defined MSC_VER ... #elif defined linux' und ich hab kein -D__linux_ beim kompilieren gesetzt. Aber er hat den Code nach linux eingesetzt. Gibt es irgend eine Datei in welcher der Präprozässor standardmäßig Variablen wie z.B. _MSC_VER oder linux abfragt oder hat er die "in sich"? er muss ja irgendwo linux bei mir gefunden haben, sonst hätte der Aufruf der Sleep-Funktion beim compilieren einen Fehler ausgelöst.
-
@Swordfish
Ja, beim lernen von c tun sich bei mir mehrere Baustellen gleichzeitig auf. Ist ne ganz andre Sache als python. Der Compiler hat wohl fast den gleichen Einfluss wie der Code.
Eine Bitte habe ich noch. Erklär mir bitte diesen Schleifenkopf aus deinem Programmfor (size_t i = snake->length - 1; i; --i)
Hier ist doch die Abbruchbedingung gleich der Zählvariable, wieso Funktioniert die Schleife?
-
@EL-europ Denk dir an der Stelle ein
i != 0
dann solltest du darauf kommen.Mehr steht bei https://www.c-plusplus.net/forum/topic/352442/untypischer-laufzeitfehler-durch-malloc/56
-
@DirkB
Bedeutet das jetzt das der Compiler von alleine versteht das hier "i != 0" gemeint ist, und man immer einfach die Zählvariable schreiben kann wenn man "Zählvariable != 0" meint?
-
@EL-europ sagte in Untypischer Laufzeitfehler durch malloc():
@DirkB
Bedeutet das jetzt das der Compiler von alleine versteht das hier "i != 0" gemeint ist, und man immer einfach die Zählvariable schreiben kann wenn man "Zählvariable != 0" meint?Ja. Siehe auch ein anderer kürzlicher Beitrag von dir zum Thema
if (filestream)
. Wobei diese Schreibweise aber ungewöhnlich ist um Integervariablen auf Gleichheit mit 0 zu vergleichen, würde ich in einem Codereview ankreiden. Besonders wenn der autor nicht einmal selber weiß, warum es das macht.
-
@SeppJ
Danke für die Antwort. Als Neuling in c ist solch ein Schleifenkopf fragwürdig. Da liest man schon gerne das er solch eine "Gültigkeit" hat
-
@EL-europ
i != 0
ist ein sog. Ausdruck. Eine Berechnung, die ein Ergebnis liefert.
In diesem Fall eine 1 (für wahr), wenn i ungleich 0 ist und
0 (für unwahr), wenn i gleich 0 ist.In C gilt 0 als unwahr, alles andere als wahr.
i
ist auch ein Ausdruck und liefert den Wert von iEin Funktionsaufruf liefert auch einen Wert. (sofern die Funktion einen Rückgabewert hat)
-
@EL-europ
Hätte ich eigentlich schon beantwortet gehabt: https://www.c-plusplus.net/forum/topic/352442/untypischer-laufzeitfehler-durch-malloc/55
-
@SeppJ sagte in Untypischer Laufzeitfehler durch malloc():
Wobei diese Schreibweise aber ungewöhnlich ist um Integervariablen auf Gleichheit mit 0 zu vergleichen, würde ich in einem Codereview ankreiden.
Ich verstehe ehrlichgesagt nicht warum es so ungewöhnlich sein soll. Jemandem der die Sprache versteht ist die Bedeutung doch sofort klar.
-
@Swordfish Ich schätze mal dass es ungewöhnlich ist weil es sich für die meisten Leute komisch anfühlt.
if (flags)
fühlt sich OK an.
if (number_of_elements)
fühlt sich auch noch OK an.
if (x_coordinate)
fühlt sich komisch an.
Undif (index)
fühlt sich für mich halt auch komisch an. Speziell wenn es in einer Schleife auftaucht die von N-1 bis 1 laufen soll. Weil allein das schon ungewöhnlich ist. Die meisten Schleifen laufen halt von 0 bis N-1, ein paar wenige von N-1 bis 0, aber extrem wenige von N-1 bis 1.
-
Es ist ungewöhnlich, weil hier von der Logik her "ungleich dem Wert 0" abgefragt werden soll, aber
(bool) i
ist von der Semantik her "ist i wahr?". Nun sind philosophische Wahrheit und die Integerwerte 0 und 1 in C technisch gesehen das gleiche, aber das ist eigentlich nur Willkür bei der Definition der Sprache. Daher würde ich bemängeln, wenn man diesen zufälligen Umstand ausnutzt. Reduction ad absurdum:i - true
bedeutet auch das gleiche wiei - 1
und nutzt den gleichen Sprachmechanismus aus. Wie würdest du auf so etwas im Code reagieren?
-
@hustbaer @DirkB
Ich hab den Zusammenhang nicht herstellen können. Das ist das erste mal das ich solch einen Schleifenkopf sehe, zumindest ohne einen Schreibfehler vermuten zu können. Aber für das hab ich mich ja hier angemeldet
Dank allen die mir geholfen haben.
-
@EL-europ sagte in Untypischer Laufzeitfehler durch malloc():
@john-0
Das Funktioniert so wie du schreibst. Doch in dem Übungsprogramm
steht '#if defined MSC_VER ... #elif defined linux' und ich hab kein -D__linux_ beim kompilieren gesetzt. Aber er hat den Code nach linux eingesetzt. Gibt es irgend eine Datei in welcher der Präprozässor standardmäßig Variablen wie z.B. _MSC_VER oder linux abfragt oder hat er die "in sich"? er muss ja irgendwo linux bei mir gefunden haben, sonst hätte der Aufruf der Sleep-Funktion beim compilieren einen Fehler ausgelöst.Variablen und Präprozessor Definitionen, die mit
__
anfangen sind immer vom Compiler bzw. der Laufzeitumgebung definiert. Das kann über Compiler bzw. System Header erfolgen, oder der Compiler definiert die Sachen intern, das gibt die Norm nicht vor.Mein Beispiel sollte nur zeigen, dass man leicht selbst solche Defines machen kann, und sie ebenso leicht auswerten kann. In der Realität würde man natürlich vom System definierte Präprozessor Variablen nutzen, um die Unterscheidung zwischen Windows und Linux zu machen. Nur wäre für ein Anfänger ein Ausflug in POSIX und die diversen Versionen erstmal kontraproduktiv.
-
@john-0
Danke dir für den Tip mit der Compileroption -D und #ifdef im Code. Vielleicht kannst du mir nochmal helfen? Ich hab in den Sourcen der curses lib gestöbert und versteh nur Bahnhof. Die einzelnen Funktionen in einen Zusammenhang zu bringen ist mir nicht möglich. Aber mir fiel wieder ein dort sehr häufig vorkommendes Konstrukt auf das ich nicht verstehereturn(*(int *)0);
Wird hier die 0 auf einen int-Zeiger gecastet und dann wieder der Wert 0 des Zeigers zurückgegeben? Warum gibt man hier nicht einfach 0 zurück?
-
@john-0
Ach, und danke dir auch das ich nun weiss das Variablen in den Headerdateien und im Compiler selbst vorhanden sind
-
@EL-europ sagte in Untypischer Laufzeitfehler durch malloc():
Aber mir fiel wieder ein dort sehr häufig vorkommendes Konstrukt auf das ich nicht verstehe
return(*(int *)0);Wird hier die 0 auf einen int-Zeiger gecastet und dann wieder der Wert 0 des Zeigers zurückgegeben? Warum gibt man hier nicht einfach 0 zurück?
Zunächst fällt doch auf, dass die Dateien, wo das vorkommt, mit "llib-" anfagen und keine .c oder .h-Erweiterung haben. Ich habe jedenfalls als erstes mal in die ncurses/README-Datei geschaut. Und siehe da, es gibt dort genau einen Absatz - und der bezieht sich auf diese Dateien.
Der Code dereferenziert einen Null-Pointer und gibt somit nicht 0 zurück, sondern verursacht undefiniertes Verhalten. Das ist dort Absicht. Das soll für "Linting" sein. Also vermutlich soll man die Funktionen nicht (mehr?) verwenden und wenn doch, kannst du mit
-Wnull-dereference
sehen, wo du etwas verwendest, das du nicht verwenden sollst.Jedenfalls: ich hätte mir mehr Information aus der README erhofft, wie ich diese Dateien benutzen soll - denn in meinem Programm will ich die ja sicher nicht haben - wahrscheinlich müsste ich dazu die vollständige Doku lesen.
-
@wob
Also gibt die Funktion einen uninitialisierten Speicherbereich zurück? Für mich ist das ein "harter Brocken" bewusst undefiniertes Verhalten zu erzwingen, außer man kann es irgendwo "abfangen"
Das Readme hab ich angefangen zu lesen aber dann abgebrochen weil ich die curses eigentlich cross-compilieren will und mit dem readme und meinem knappem Englisch nicht weiter kam. Danke für deine Antwort