Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

LittleKitty

Frischling

  • »LittleKitty« ist der Autor dieses Themas

Beiträge: 8

Beruf: Studentin

  • Private Nachricht senden

1

26.05.2014, 20:05

Frage zu Aufgabe 7 (char Array als Eigenschaft einer Klasse)

Hallo, ich habe leider ein Problem bei Aufgabe 7.
Ich will, dass der Benutzer seinem Schiff einen Namen geben kann.. (Ich weiß das sollte normal in eine eigene Funktion).

Das Problem ist, dass ich irgendwelche Hieroglyphen nach der Eingabe erhalte :(

(Link)


C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>
class CRaumschiff{
    public:
        int xPos, yPos, energy, velocity;
        char name[31];

        CRaumschiff();
        CRaumschiff(int, int);
        ~CRaumschiff();

        void printInfo();
};

CRaumschiff::CRaumschiff(){
    xPos = yPos = velocity = 0;
    energy = 1000;

    std::cout << "Standardkonstruktor" << std::endl << std::endl;
};

CRaumschiff::CRaumschiff(int xPos, int yPos){
    if (xPos >= 0 && xPos <= 800 && yPos >= 0 && yPos <= 600){
        this->xPos = xPos;
        this->yPos = xPos;
        std::cout << "Koordinaten gesetzt auf: " << xPos << "/" << yPos << std::endl << std::endl;
    } else {
        std::cout << "Koordinatenfehler " << xPos << "/" << yPos << std::endl;
        this->xPos = 80;
        this->yPos = 60;
        std::cout << "Koordinaten gesetzt auf: " << xPos << "/" << yPos << std::endl << std::endl;
    }
    energy = 1000;
};

CRaumschiff::~CRaumschiff(){
    std::cout << "Destruktor aufgerufen" << std::endl;
};

void CRaumschiff::printInfo(){
    std::cout << "################" << std::endl;
    std::cout << "Raumschiffinfos:" << std::endl;
    std::cout << "Energie: " << energy << std::endl;
    std::cout << "x: " << xPos << std::endl;
    std::cout << "y: " << yPos << std::endl;
    std::cout << "################" << std::endl << std::endl;
};

int main(){
    CRaumschiff *ship1 = NULL;
    ship1 = new CRaumschiff();
    ship1->printInfo();
    std::cout << "Player's Shipname:" << std::endl;
    std::cin.get(ship1->name, 30);

    std::cin.ignore();


    CRaumschiff *enemy = NULL;
    ship1 = new CRaumschiff(500, 500);
    ship1->printInfo();
    std::cout << "Playership: " << ship1->name << std::endl;
    delete ship1;
    delete enemy;

    std::cin.ignore();
    return 0;
}



Auch sowas klappt nicht und ich komm nicht dahinter woran es liegt
ship1->name = "Maya\0";

Da kommt dann Error C2440 - irgendwas mit constant, obwohl ich hier nirgends const verwende?

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

2

26.05.2014, 20:08

"name" ist ein char[31]. "Maya\0" ist ein const char[6]. Wozu auch immer Du genau das "\0" brauchst.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

LittleKitty

Frischling

  • »LittleKitty« ist der Autor dieses Themas

Beiträge: 8

Beruf: Studentin

  • Private Nachricht senden

3

26.05.2014, 20:20

Mh..
Jetzt bin ich noch verwirrter, aber danke für die schnelle Antwort

"\0" hab ich so im Buch gelernt, damit keine alten Fragmente vom String auftauchen(?)

4

26.05.2014, 20:29

Problem/Frage 1:

Du deklarierst eine Variable name mit einer festen Länge und behauptest dabei, dass sich diese Länge nicht mehr ändert. (char name[31])

Bei der Instanziierung deiner Klasse (ship1 = new CRaumschiff(500, 500);) wird diese Variable automatisch definiert und der Speicherplatz (Array), also 31 char's reserviert. Bei dieser Reservierung bleibt der Inhalt dieses Speicherbereiches unangetastet - somit stehen unnütze Bytes darin und bei der Ausgabe kommt es zu "Hyroglyphen". Der Ausdruck ship1->name bezeichnet somit einen Zeiger auf das erste Element dieses nicht initialisierten Speicherplatzes.

Nun versuchst du genau dieser Zeigervariable einen anderen Wert zu zuweisen.

C-/C++-Quelltext

1
std::cin.get(ship1->name, 30);
Diese Funktion sucht das Ende der Zeichenkette (ein Byte mit dem Wert 0) und hängt die eigentliche Eingabe des Nutzers dort einfach dran. Du hast jedoch eine maximale Anzahl an Zeichen in deiner Zeichenkette bestimmt: 30. Da vermutlich innerhalb dieser 30 Zeichen in deinem bereits vorhandenen Speicherbereich scheinbar keine 0 zu finden ist, macht die Funktion im Grunde genommen garnichts - sonst würde es zum Overflow, bzw. Memory Access Violation kommen.

Was du jetzt machen kannst, um das zu beheben ist, deinen Speicherbereich vor dem get()-Aufruf komplett zu nullen. (memset() bzw. ZeroMemory())


Problem / Frage 2:

ship1->name = "Maya\0";
Das funktioniert nicht, da du deiner Variable einfach einen anderen Zeigerwert übergeben möchtest - undzwar einen Zeiger auf einen konstanten Speicherbereich - dazu noch von anderer Länge, als du bei der Deklaration erst behauptet hast. Somit entsteht ein Typemismatch und der Compiler wirft einen Fehler.
Siehe dazu auch BlueCobolds Kommentar.



Ich hoffe, dir sind nun die Grundlagen etwas vertrauter ;)
EnvisionGame(); EnableGame(); AchieveGame(); - Visionen kann man viele haben. Sie umzusetzen und auf das Ergebnis stolz zu sein ist die eigentliche Kunst.

LittleKitty

Frischling

  • »LittleKitty« ist der Autor dieses Themas

Beiträge: 8

Beruf: Studentin

  • Private Nachricht senden

5

26.05.2014, 21:07

Danke für die ausführliche Antwort.
So klappt es :crazy:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int main(){
    CRaumschiff *ship1 = NULL;
    ship1 = new CRaumschiff();
    ship1->printInfo();
    std::cout << "Player's Shipname:" << std::endl;
    memset(ship1->name, '0', 31);
    std::cin.get(ship1->name, 30);
    std::cin.ignore();


    CRaumschiff *enemy = NULL;
    enemy = new CRaumschiff(500, 500);
    enemy->printInfo();

    std::cout << ship1->name << std::endl;

    delete ship1;
    delete enemy;

    std::cin.ignore();
    return 0;
}


Was mache ich wenn ich "enemy" den Namen "Red Baron" geben will?
enemy->name = "Red Baron"; klappt ja nicht. :dash:

6

26.05.2014, 21:24

C-/C++-Quelltext

1
memset(ship1->name, '0', 31);

Nutz besser mal Integer, anstatt von einzelnen Chars als Werte. Durch den impliziten Cast mag das zwar auch so funktionen (warum auch immer, weil der Ascii von '0' ist nicht 0..), ist aber möglicherweise besser verständlich, wenn du eine Zahl nutzt. 0. ;)

enemy->name = "Red Baron";
Klappt wieder nicht, weil du einem nicht-konstanten Zeichenkettenpointer einen konstanten zuweisen möchtest.
Stattdessen kannst du Hilfsfunktionen nutzen. strcat, strcpy und so weiter.
Die sind aber grundsätzlich in C++ mittlerweile deprecated (darum ist Davids Buch auch leider leider nicht mehr auf dem neusten Stand)
Wenn du mit Visual Studio 2013 arbeitest, wird er dir sogar einen Fehler geben. Grund dafür ist, dass durch diese Funktionen sehr leicht ein fehlerhafter Speicherzugriff getätigt werden kann.
Um das zu vermeiden hast du mehrere Möglichkeiten:
  • Nutze strcpy_s, strcat_s, etc. - Das ist lediglich eine Erweiterung von Microsoft der Grundfunktionen um ein weiteres Argument, dass die maximale Größe des Ziel-Speicherbereichs festlegt:

    C-/C++-Quelltext

    1
    2
    3
    
    char enemy[50];
    memset(enemy, 0, 50);
    strcat_s(foo, 50, "Red Baron");

  • Nutze den String der Standard Library:

    C-/C++-Quelltext

    1
    2
    3
    
    #include <string>
    std::string enemy;
    enemy = "Red Baron";


Pro-Hinweis: Ich persönlich bin ja noch konservativ in der Hinsicht und verwende lieber die strcat_s Alternative. Die aber schön in ein Makro bzw. in eine eigene Wrapper-Klasse gepackt, damit man sie möglichst flexibel noch ändern kann - sollte sich doch mal wieder was ändern ^^
EnvisionGame(); EnableGame(); AchieveGame(); - Visionen kann man viele haben. Sie umzusetzen und auf das Ergebnis stolz zu sein ist die eigentliche Kunst.

LittleKitty

Frischling

  • »LittleKitty« ist der Autor dieses Themas

Beiträge: 8

Beruf: Studentin

  • Private Nachricht senden

7

26.05.2014, 21:33

Okay ich seh' schon da brauchts dann für die Grundlagen doch noch zusätzlich ein anderes Buch

Danke für die Hilfe und sorry für dieses Mischmasch an Englisch/Deutsch...

LittleKitty

Frischling

  • »LittleKitty« ist der Autor dieses Themas

Beiträge: 8

Beruf: Studentin

  • Private Nachricht senden

8

27.05.2014, 10:32

Angenommen ich lasse zunächst über die Tastatur den Benutzer wählen, will den Namen aber später aus irgendwelchen Gründen wieder überschreiben..
Also etwa so:

C-/C++-Quelltext

1
2
3
4
5
6
    std::cout << "Player's Shipname:" << std::endl;
    memset(ship1->name, 0, 31);
    std::cin.get(ship1->name, 30);
    std::cin.ignore();
        //*
    strcat_s(ship1->name, 30, "Player 1");


~muss ich dann an der Stelle //* wieder mit memset alles auf Null setzen?
Wenn ich das richtig verstehe, würde sonst Player 1 nur an die Benutzereingabe angehängt werden, da erst danach die erste Null auftaucht?

Kann es sein, dass strcat_s von Microsoft stammt? Was nehm ich stattdessen (string mal außen vor) für andere Betriebssysteme?
Ein paar Meinungen im Netz raten von der Verwendung von strcat ab, weil es womöglich unsicher ist ( andere behaupten wieder das stimmt nicht ).

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

9

27.05.2014, 11:06

Mach Dir da wenig Sorgen drüber, char* oder char[] wirst Du in gutem C++ ohnehin nicht sehen (ich hoffe weiter hinten im Buch auch schon nicht mehr). Da wird dann std::string verwendet und das ist in vielerlei Hinsicht sauberer und sicherer.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

LittleKitty

Frischling

  • »LittleKitty« ist der Autor dieses Themas

Beiträge: 8

Beruf: Studentin

  • Private Nachricht senden

10

27.05.2014, 14:47

Okay. Danke.
Im übernächsten Kapitel gibts dann schon eine Einführung zur STL

Werbeanzeige