Seite 1 von 1

Variable ändert sich, obwohl es nicht sein dürfte

Verfasst: 18.03.2010, 22:40
von FredK
Auch wenn ich das Problem mit nem kleinen Trick umgehen konnte, würde es mich schon interessieren, warum es so passiert ist, wie es ist.

Ich arbeite gerade an einem Inventarbereich. Wenn man nun eine Waffe anwählt und auf "Waffe anlegen" klickt wird die Funktion waffe_wechseln aufgerufen. Hier wird die Waffe, die man in der Hand hat in das Inventar zurückgelegt und die neue vom Inventar entfernt und in die Hand genommen.

Code: Alles auswählen

void waffe_wechseln(char name[256])
{
[...]

	messageboxEx("Alter Objname: %s Neuer Name: %s",character.waffe.objektname,name);

	//Alte Waffe dem Inventar hinzufügen
	inventar.add(character.waffe.objektname);
	
	messageboxEx("Alter Objname: %s Neuer Name: %s",character.waffe.objektname,name);

[...]
}
Jetzt würde ich erwarten, das die beiden char-Arrays "character.waffe.objektname" und "name" unverändert bleiben. "character.waffe.objektname" tut das auch, jedoch ändert sich "name".

Die Ausgabe ist also:
1. Aufruf MessageboxEx: Alter Objname: Schwert Neuer Name: Axt
2. Aufruf MessageboxEx: Alter Objname: Schwert Neuer Name: Schwert
Da ich bei inventar.add(char obj_name[256]) ja nur einen char Array und keine Zeiger übergebe und auch nicht auf eine Variable "name" zugreife, dürfte sich doch nichts ändern, oder seh ich das falsch?

Der Vollständigkeit halber hier noch mal der Code von inventar.add:

Code: Alles auswählen

void inventar_manager::add(char obj_name[256])
{
	
	//Gibt es Item schon?
	for(int i=0;i<num_items;i++)
	{
		if(strcmp(obj_name,this->items[i].name)==0)
		{
			this->items[i].anzahl++;
			
			this->RebuildVarlist();
			return;
		}
	}



	//Es befindet sich das Item noch nicht im Inventar

	//Freien Slot suchen
	int aktl_slot=-1;

	for(int i=0;i<num_items;i++)
	{
		if(this->items[i].anzahl<=0)
		{
			aktl_slot=i;
			break;
		}
	}
	

	//Item hinzufügen
	if(aktl_slot==-1)
	{
		this->num_items++;
		this->items=(item *) realloc(this->items,num_items*sizeof(item));
                aktl_slot=num_items-1;
	}

	

    sprintf(this->items[aktl_slot].name,obj_name);
    this->items[aktl_slot].anzahl=1;

	

	this->RebuildVarlist();
}

Re: Variable ändert sich, obwohl es nicht sein dürfte

Verfasst: 18.03.2010, 22:45
von Krishty
FredK hat geschrieben:Da ich bei inventar.add(char obj_name[256]) ja nur einen char Array und keine Zeiger übergebe […]
Arrays werden als Zeiger übergeben. Das [256] dient nur dem Compiler als Hinweis, praktisch ist es mit char obj_name[] und char * const obj_name identisch.

Insofern würde das ganze auch furchtbar crashen, wenn realloc() dein Array mal ganz woanders hin verschiebt, weil obj_name dann auf freigegeben Speicher zeigen könnte, falls du als Parameter den Namen eines anderen Inventar-Objekts übergibst (z.B. wenn du Inventar kopierst).

[cloogshice]mit ::std::string wäre das nicht passiert.[/cloogshice]

Gruß, Ky

Re: Variable ändert sich, obwohl es nicht sein dürfte

Verfasst: 18.03.2010, 22:51
von Aramis
Du solltest außerdem std::string verwenden und auf das Rumhamstern mit realloc verzichten. Ehrlich.

Re: Variable ändert sich, obwohl es nicht sein dürfte

Verfasst: 18.03.2010, 22:55
von FredK
Aha... Und wieder was neues gelernt ;-)

Aber ich schreibe innerhalb von inventar.add() trotzdem nicht in die Varable obj_name.

Re: Variable ändert sich, obwohl es nicht sein dürfte

Verfasst: 18.03.2010, 23:01
von Krishty
Du liest aber aus dem Speicher, auf den sie zeigt ;) Du weißt nicht, wo sie hinzeigt und wer der Besitzer des Speichers ist. Also kannst du auch nicht wissen, ob sie nicht vielleicht auf das Name-Member von einem deiner this->items zeigt. Bei Zeigern gibt es keine Unschuldsvermutung.

Bei einem ::std::string sind die Besitzverhältnisse hingegen eindeutig geklärt.

Re: Variable ändert sich, obwohl es nicht sein dürfte

Verfasst: 18.03.2010, 23:14
von FredK
Das ist ja fies. :-(
Ich fand das mit den char-Arrays sonst ganz praktisch, aber wenn da so ein Murks raus kommen kann.... sollte ich vielleicht umdenken.

Wenn ich nun ein int irgendwas[293] Array hab, das ich übergebe, dann hätte ich doch das gleiche Problem.

Re: Variable ändert sich, obwohl es nicht sein dürfte

Verfasst: 18.03.2010, 23:19
von Krishty
Genau. Arrays sind böse, ::std::string und ::std::vector sind gut.

Re: Variable ändert sich, obwohl es nicht sein dürfte

Verfasst: 19.03.2010, 08:24
von Schrompf
Und wenn's unbedingt ein direkter Speicherblock sein soll, dann wenigstens const char* anstatt char[]. Dann haut Dir der Compiler auf die Finger, wenn Du den Namen veränderst. Und mal ehrlich: sollte eine Funktion, die eine Waffe anlegen soll, den Namen der Waffe verändern? Eher nicht.

Allgemein aber will ich nochmal wiederholen, was die anderen gesagt haben: Nutze C++! Also std::string, std::vector, == operator anstatt strcmp, sowas halt...

Re: Variable ändert sich, obwohl es nicht sein dürfte

Verfasst: 19.03.2010, 10:46
von Jonathan
Desweiteren sollte man sich damit vertraut machen, wann man Referenzen und wann const benutzen kann. Das sind beides prinzipiell tolle Sachen, die man überall da, wo man es kann, einsetzen sollte. D.h. Objekte nicht als Wert sondern als konstante Referenz übergeben. Das ist erstens schneller und zweitens hilft jedes const dem Compiler Fehler für dich zu finden.
Und wie auch schon erwähnt: Wann immer es für eines deiner Probleme eine Lösung in der Standardlib oder in boost gibt, brauchst du sehr gute Argumente, um sie nicht zu benutzen.