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

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
FredK
Beiträge: 31
Registriert: 06.05.2004, 17:11

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

Beitrag 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();
}
Benutzeravatar
Krishty
Establishment
Beiträge: 8250
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

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

Beitrag 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
Zuletzt geändert von Krishty am 18.03.2010, 22:54, insgesamt 2-mal geändert.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Aramis
Moderator
Beiträge: 1458
Registriert: 25.02.2009, 19:50
Echter Name: Alexander Gessler
Wohnort: 2016
Kontaktdaten:

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

Beitrag von Aramis »

Du solltest außerdem std::string verwenden und auf das Rumhamstern mit realloc verzichten. Ehrlich.
FredK
Beiträge: 31
Registriert: 06.05.2004, 17:11

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

Beitrag von FredK »

Aha... Und wieder was neues gelernt ;-)

Aber ich schreibe innerhalb von inventar.add() trotzdem nicht in die Varable obj_name.
Benutzeravatar
Krishty
Establishment
Beiträge: 8250
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

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

Beitrag 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.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
FredK
Beiträge: 31
Registriert: 06.05.2004, 17:11

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

Beitrag 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.
Benutzeravatar
Krishty
Establishment
Beiträge: 8250
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

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

Beitrag von Krishty »

Genau. Arrays sind böse, ::std::string und ::std::vector sind gut.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Schrompf
Moderator
Beiträge: 4859
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

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

Beitrag 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...
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Jonathan
Establishment
Beiträge: 2374
Registriert: 04.08.2004, 20:06
Kontaktdaten:

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

Beitrag 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.
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Antworten