Anfaengercode, Wo sind die Fehler
-
kamelkacke schrieb:
Wieso denn sizeof? Ich möchte nicht wissen, wie gross der char in bytes ist.
Ein char hat immer sizeof 1. Hier interessiert aber die sizeof deines char[20]. Die ist nämlich logischerweise 20, nicht 29.
Egal. Lassen wir das erstmal außen vor. Warum zeigt er bei energie nicht 100 an?
camper schrieb:
Compilerwarnungen beachten.
Ich korrigiere zu: Compilerwarnungen einschalten. Dann beachten.
-
Ich lese die antworten, verstehe sie als anfaenger leider nicht. Hier nochmal genau das selbe in funktionsfaehig aber ohne umterschiede...wo ost der unterschied ich checks nicht.
#include <iostream> using namespace std; struct spieler { int leben; int mana; int xposi; int yposi; char name[30]; }; void namenabfrage (spieler *pabfrage); int main () { spieler spieler1; spieler1.leben = 100; spieler1.mana = 100; spieler1.xposi = 0; spieler1.yposi = 0; spieler1.name[30]='Hai'; cout << "Alter Spielername: " << spieler1.name << endl; cout << "Bitte Namen eingeben: \n"; namenabfrage (&spieler1); cout << "Der gewaehlte Name ist: " << spieler1.name << endl; } void namenabfrage (spieler *pabfrage) { cout << "Name des Spielers: "; cin.get (pabfrage->name, 29); }
-
Ah jetzt hab ichs...das void
-
meine kommentare zum code:
1. geeignete datentypen wählen
1.a. kannlebenwirklich negativ werden?
1.b. kannmanawirklich negativ werden?
1.c. gibt es in diesem spiel keine implementierung eines koordinaten-templates?
1.d. willst du sicher keinenstd::stringfür den namen verwenden?2. konstruktor zum angenehmeren initialisieren (ist einerseits schneller und andererseits übersichtlicher und kürzer)
3. für string-literale (also mehrere zeichen aneinander) nutzt man " und nicht ' (siehe zeile 21)
4. die funktion musst du nicht forward-deklarieren, du kannst sie auch direkt dort definieren wo du sie aktuell deklarierst
5. wieso nutzt du call-by-pointer statt call-by-reference?
-
1.a. kann leben wirklich negativ werden?
1.b. kann mana wirklich negativ werden?Wenn man nicht staendig auf Bufferunderflows testen moechte ...
-
Ich beantworte mal die anmerkungen, mit denen ich bis jetzt, mit meinem wissen, was anfangen kann.
1a und 2b, spielst du da auf unsigned an?
Ansonsten danke fuer die anmerkungen, mache mich direkt dran diese zu lernen.
-
knivil schrieb:
1.a. kann leben wirklich negativ werden?
1.b. kann mana wirklich negativ werden?Wenn man nicht staendig auf Bufferunderflows testen moechte ...
okay, in bezug auf seine struktur hast du natürlich recht. ich bin von einer klasse ausgegangen, die diese werte kapselt. da wäre der aufwand des zusätzlichen testens = 0.
kamelkacke schrieb:
Ich beantworte mal die anmerkungen, mit denen ich bis jetzt, mit meinem wissen, was anfangen kann.
1a und 2b, spielst du da auf unsigned an?
Ansonsten danke fuer die anmerkungen, mache mich direkt dran diese zu lernen.
ja. wobei das eher allgemeine kommentare zum code sind und nicht direkt mit dem von dir geschilderten problem zu tun haben.
zeile 21 dürfte gar nicht erst kompilieren. falls doch, dann macht es ganz sicher nicht das, was du dir vorstellt.
kleines beispiel zu den wichtigsten von mir aufgeführten punkten:
#include <iostream> // brauchen wir für zeichenketten (sogenannte strings): #include <string> using namespace std; struct spieler { int leben; int mana; int xposi; int yposi; // strings sind intelligent und flexibel, so können sie jede erdenkliche länge haben und passen sich automatisch an, brauchen also dieses fixe [30] nicht mehr string name; }; // die funktion definieren wir mal direkt hier, ist übersichtlicher void namenabfrage(spieler& pabfrage) //& bedeutet referenz. ähnlich wie zeiger, nur wird garantiert, dass sie IMMER gültig sind. ausserdem einfacher zu benutzen { cout << "Name des Spielers: "; cin >> pabfrage.name; // egal wie lange der name ist, er passt immer in den string } int main () { spieler spieler1; spieler1.leben = 100; spieler1.mana = 100; spieler1.xposi = 0; spieler1.yposi = 0; spieler1.name = "Hai"; // bei zeichenketten " statt ', ausserdem lässt sich der string super einfach überschreiben cout << "Alter Spielername: " << spieler1.name << endl; cout << "Bitte Namen eingeben: \n"; namenabfrage(spieler1); // wir brauchen nichtmal mehr & vor dem spieler1 zu schreiben, da wir call-by-reference haben (also eine referenz verwenden als parameter) cout << "Der gewaehlte Name ist: " << spieler1.name << endl; }
-
igno schrieb:
zeile 21 dürfte gar nicht erst kompilieren. falls doch, dann macht es ganz sicher nicht das, was du dir vorstellt.
spieler1.name[30]='Hai';Tatsächlich compiliert das. Hier haben wir ein multi-character Literal (implementation-defined, aber ausdrücklich erlaubt), kombiniert mit der gefürchteten Technik "ich führe so lange zufällig kleine Änderungen durch, bis es compiliert", die uns das
[30]beschert haben dürfte.
-
volkard schrieb:
hustbaer schrieb:
weil da 29 und nicht
1920sizeof(f.name)sizeof(f.name)/sizeof(f.name[0])stehtOch, sizeof(char) wird schon 1 sein. Über ein -1 würde ich mehr nachdenken. Vermutlich war die 20 in "char name[20];" nur ein Abtippfehler.
Aus dem gleichen Grund warum ich
void Foo() { LOG(__FUNCTION__ ": Blubb"); }schreibe statt einfach
LOG("Foo: Blubb");
Fookönnte mal zuBarwerden.
charkönnte mal zuwchar_twerden.Und wieso -1? Doku sagt explizit dass die Funktion das -1 selbst macht.
@camper
Uiiiii, hab ich komplett übersehen
Ja, Warnings sind schon gut. Bzw. eigentlich sollte das sogar nen Fehler geben.
-
hustbaer schrieb:
Ja, Warnings sind schon gut. Bzw. eigentlich sollte das sogar nen Fehler geben.
Am Ende einer wertzurückgebenden Funktion ohne return anzukommen, führt nur zu undefiniertem Verhalten. Um daraus standardkonform einen Fehler zu machen, muss der Compiler nachweisen, dass jede Ausführung des Programmes (die nicht schon anderweitig auf UB stösst) irgendwann an dieser Stelle ankommt. Das ist in diesem speziellen Fall nat. problemlos möglich, im Allgemeinen aber nicht. Daher ist es grundsätzlich erst einmal nur eine Warnung (kann man nat. per Compilerschalter hochstufen lassen).
Und ill-formed ist es deshalb nicht, weil es im Allgemeinen schon nicht beweisbar ist, dass die Ausführung einer Funktion diese Stelle überhaupt erreichen kann, un wir wollen ja nicht, dass:
Nicht-pathologisches Beispiel
int foo(int x) { switch (x) { case 0: return 42; default: return 0; } }noch mit einem return am Ende bedacht werden muss. Und die Frage, ob etwas ill-formed ist, oder nicht, sollte nicht von den Analysefähigkeiten eines Compilers abhängen.
-
@camper
Das "sollte" war vielleicht misverständlich.
Ich wollte damit nicht ausdrücken dass ich meine der Standard würde das vorschreiben oder empfehlen. Sondern nur dass ich es besser fände, und auch gewohnt bin hier einen Fehler zu bekommen.Die Compiler die ich kenne werfen hier nämlich nen Fehler, weil die Funktion keinen einzigen Pfad mit
returnhat.Was du schreibst klingt danach, als ob auch das laut Standard OK wäre, nämlich so lange diese Funktion nicht aufgerufen wird. Wobei ich wie gesagt ganz klar vorziehe was mein Compiler hier macht, nämlich mir trotzdem nen Fehler zu generieren.