Seite 1 von 1

Problem mit Zeigern

Verfasst: 04.06.2009, 13:47
von odenter
Ich hab ein Problem mit Zeigern.
Ich habe einen Typ xyz und eine Funktion die einen Zeiger auf eben diese Typ zurück liefert. Nun möchte ich aber evtl. mehr als ein Ergebnis zurück liefern, also hab ich gedacht geb ich ein Array zurück, was im Grunde ja das gleiche wie ein Zeiger ist.
Anbei ein Beispiel das funktioniert. Was mich aber stört ist das ich mit negativen Indizes darauf zugreifen muss. Hat jemand ne Idee wie ich das anders machen kann, oder so hinbekomme das Element 1 auch per Index 0 zugreifbar ist?

Wenn ich ein

Code: Alles auswählen

t--
t--
mache, dann stehe ich nicht auf dem korrekten ersten Element, das jedenfalls war mein ursprünglicher Plan.

Code: Alles auswählen


class Test {
private:
public:
  __int32 x32;
  __int64 x64;
  double d;
  float f;

  Test() {
    x32 = 0;
    x64 = 0;
    d = 0;
    f = 0;
  }
protected:
};

#define ANZ 3

int main(char *argv, int argc) {

  Test *t;
  t = new Test[sizeof(Test)*ANZ];
  for (int i = 1; i <= ANZ; i++) {
    t->d = i + 2.234;
    t->x32 = i;

    if (i != ANZ) {
      t++;
    }
  }

  //t[0]    3. Element
  //t[-1]   2. Element
  //t[-2]   1. Element
  return 0;
}
Also im Grunde will ich (Zeiger - (Anzahl * GrößeVomRückgabeTyp)) zurückgeben, aber wie mach ich das?

Re: Problem mit Zeigern

Verfasst: 04.06.2009, 14:00
von Schrompf
Oh haua. Nimm's mir nicht übel, aber Du brauchst da definitiv mehr Grundlagenverständnis. Dass Du mit negativen Indizes zugreifen musst, ist klar, wenn Du vorher mehrfach den Zeiger t inkrementierst. Aber das dort eingebaute Speicherleck ist unschön. Eine Schleife von 1 beginnen zu lassen ebenso, das parallele Mitrechnen zweier Schleifenvars eigentlich auch. Zweimal "t--;" sollte auf jeden Fall gehen, genauso wie "t -= 2;" - das wäre dann die Antwort auf Deine Frage am Ende.

Ein Vorschlag meinerseits:

Code: Alles auswählen

std::vector<Test> GibMirDrei()
{
  std::vector<Test> zeugs( 3); 
  for( int i = 0; i < 3; ++i)
  {
    zeugs[i].d = i + 2.234;
    zeugs[i].x32 = i;
  }

  return zeugs;
}
Gäbe es auch als Variante ohne Allokationen oder über boost::array mit statischer Element-Anzahl.

[edit]Blöde Code-Tags. Warum tötet der meine Einrückungen?

Re: Problem mit Zeigern

Verfasst: 04.06.2009, 14:22
von Krishty
Musst {code=cpp} schreiben.

Meist tut es als Rückgabe auch ein struct, weil man zwei Rückgabewerte eigentlich nur braucht, wenn man eh Objekte zurückgibt (Linien usw).

Re: Problem mit Zeigern

Verfasst: 04.06.2009, 14:26
von odenter
Hier geht es tatsächlich nicht um Linien sondern um Lua.

Code: Alles auswählen

function testRtn()
  return "eins", 2, 3, 4, 5, "sechs"
end
Das t-=2 war übrigens die Antwort die ich brauchte, wobei das bei mir dynamisch sein wird.

Ich kann beliebig viele Rückgabewerte haben, da Lua die Rückgabe von mehr als einem Wert zulässt. Speicherleck gibt es keins, da das Beispielcode war/ist und nur das Problem veranschaulichen sollte, da interessiert mich kein Speicher. ^^ Und das Speicherlecks entstehen wenn man bei der Benutzung einer API pennt ist jawohl klar.

Ich weiss nicht was ich anders gemacht habe, aber das habe ich immer im Debugger gemacht, dort kam defenitiv das falsche Ergebnis, schreibe ich es in den Code stehe ich auf dem richtigen Pointer den ich zurück geben will. Ich will nämlich hinterher nur per die Ergebnisse durchlaufen.
In der Theorie hatte ich also alles richtig, ich weiss nicht wie Du darauf kommst zu meinen ich wüsste nicht genug über die Grundlagen?! ^^

Und vielleicht gefällt es Dir nicht eine Schleife bei 1 beginnen zu lassen, in diesem Fall ist es Zweckdienlich, denn in Lua beginnt die Indiezierung des Stacks auch bei 1...

Letztendlich gehts hier um ein Interface für Skripte. Boost gefällt mir nicht, die erste Idee war eine std::map zurück zu geben hielt ich aber für overpowered, da in der Regel nur ein Ergebnis zurück geliefert wird, aber eben nicht immer.
Wobei das so ohne weiteres eh nicht geht weil ich hier Abstrakte-Klassen habe.

Re: Problem mit Zeigern

Verfasst: 04.06.2009, 15:36
von kimmi
Bau dir das doch als Stack und gebe auf den einen Pointer zurück. Dann kannst du mittels Push / Pop darauf zugreifen. Die Elemente könntesst du als Variant implementieren. Nur so ein Ansatz auf die Schnelle.

Gruß Kimmi

Re: Problem mit Zeigern

Verfasst: 04.06.2009, 19:44
von Lord Delvin
odenter hat geschrieben:Letztendlich gehts hier um ein Interface für Skripte.
Öhm, warum schreibst du keine funktion, der du die erwaretete Signatur und den funktionsnamen übergibst und dann mit ... alle parameter und referenzen auf die rückgabewerte?

Ich hab seit längerem nichts mehr gemacht aber ich glaub mich an sowas zu erinnern:

für Lua code

Code: Alles auswählen

g = function(x)
return x, x*x
end

f = function(phi, x)
return _G[phi](x)
end
könntest du auf der C++ seite schreiben

Code: Alles auswählen

LuaState L;
/// some load ///
char name[] = "g";
float x = 10, r1, r2;
L.call("f", "sd>dd", name, x, &r1, &r2);
Dann wäre r1 = 10 und r2 = 100;

Die Implementierung von call ist zugegebener Maßen etwas komplizierter und länglich, aber da findet sich n haufen Code zu, wenn du suchst. Wobei ich das direkt über operator() gemacht hab, ist imho natürlicher:D

EDIT: Ansonsten ** ist ein guter weg um mehrere Rückgabewerte zu implementieren, aber ich glaub garnicht, dass du das willst, weil du ja eigentlich nicht eine funktion pro lua functionstyp schreiben willst...damit schießt man sich ja gewaltig in den fuß.

Re: Problem mit Zeigern

Verfasst: 04.06.2009, 19:49
von TGGC
odenter hat geschrieben:Also im Grunde will ich (Zeiger - (Anzahl * GrößeVomRückgabeTyp)) zurückgeben, aber wie mach ich das?
return (Zeiger - (Anzahl * GrößeVomRückgabeTyp)); f'`8k

[ ] Autocogito


Gruß, TGGC (Was Gamestar sagt...)

Re: Problem mit Zeigern

Verfasst: 04.06.2009, 20:01
von Krishty
TGGC hat geschrieben:return (Zeiger - (Anzahl * GrößeVomRückgabeTyp));
Wenn du ihm schon dumm kommst, stell dich dabei nicht auch noch dumm an.

Code: Alles auswählen

return Zeiger - Anzahl;
Denn bei Zeigerarithmetik ist eine Einheit sizeof(gezeigterTyp) Bytes groß.

odenter, das ist bei deiner Allokation auch falsch, t = new Test[ANZ]; reicht vollkommen.

Re: Problem mit Zeigern

Verfasst: 05.06.2009, 10:05
von odenter
Krishty hat geschrieben:
TGGC hat geschrieben:return (Zeiger - (Anzahl * GrößeVomRückgabeTyp));
Wenn du ihm schon dumm kommst, stell dich dabei nicht auch noch dumm an.

Code: Alles auswählen

return Zeiger - Anzahl;
Denn bei Zeigerarithmetik ist eine Einheit sizeof(gezeigterTyp) Bytes groß.
odenter, das ist bei deiner Allokation auch falsch, t = new Test[ANZ]; reicht vollkommen.
Stimmt, danke. Test ist in dem Fall ja schon die "Größe".

@Lord Devlin
Ja ich hab mir die ganzen Templates angeguckt, die gefielen mir aber alle nicht. Und zwar aus dem Grunde weil dort meistens irgendwelche statischen Variablen waren in die Funktionsnamen + Zeiger geaddet wurden um diese dann von Dort Lua bekannt zu machen.

Ich bin .NET geschädigt und mir gefällrt dort die Benutzung von ADO.NET genauer die DbCommand-Klasse ziehmlich gut.
Man fügt dort lustig Parameter ein ala

Code: Alles auswählen

-- pseudo code
insert intal tablleA (feld1, feld2, feld3)
value(@feld1, @feld2, @feld3)
com.parameters.add(new Parameter("@feld1", dbsql.nvarchar))
com.parameters(0).value = "bla blubb"
com.parameters.add(new Parameter("@feld2", dbsql.int))
com.parameters(1).value = 2222
com.parameters.add(new Parameter("@feld2", dbsql.image))
com.parameters(2).value = new byte[100]
com.ExecuteNoQuery()
Auf etwas ähnliches hatte ich mich letztendlich auch schon festgelegt für die Übergabe von Parametern an Lua. Weil ich so auch gleichzeitig den Typ habe um zu bestimmen mit welcher Funktion ich was auf den Stack lege z.B. lua_pushnumber oder lua_pushstring etc. Und für die Rückgabe entsprechend auch. Aktuell kommt das noch als Parameter mit, der Plan ist aber das auch nur durch Methodenaufrufe zuzulassen.

Die Idee von Schrompf war doch gar nicht sooo verkehrt. :) Allerdings nicht als Rückgabe der Funktionen. Das Interface sieht im Prinzip nun so aus, ein bischen was muss ich noch ändern bzw. hinzufügen.

Code: Alles auswählen

class IScript {
private:
  std::string fileNameValue;
  std::string codeValue;
  IScriptVM *scriptingVMValue;

public:
  ~IScript() {
  }

  void SetFileName(std::string fileName) { fileNameValue = fileName; }
  void SetCode(std::string code) { codeValue = code; }

  std::string GetFileName() { return fileNameValue; }
  std::string GetCode() { return codeValue; }

  // Lädt eine Script Datei
  virtual void Load(std::string fileName)=0;
  // Speichert eine Script Datei
  virtual void Save(std::string fileName)=0;
  
  // führt das geladene Script aus, 1 Rückgabewert
  virtual bool Execute(std::vector<IScriptObject> &returnParams)=0;
  // führt eine Funktion aus mit n Parametern und einem Rückgabewert
  virtual bool ExecuteFunction(std::string funcName, std::vector<IScriptObject> &params, std::vector<IScriptObject> &returnParams)=0;
  // führt eine Funktion aus mit n Parametern und n Rückgabewerten
  virtual bool ExecuteFunction(std::string funcName, std::vector<IScriptObject> &params, int rtnCount, std::vector<IScriptObject> &returnParams)=0;

protected:
  //std::vector<IScriptObject> parameterValue;

  IScript() {
  }
};
Und die benutzung sieht dann in etwa so aus

Code: Alles auswählen

  CLuaVM *vm = new CLuaVM; 
  CLuaScript script(vm, "test.lua"); 

  std::vector<IScriptObject> rtn;
  bool ret = script.Execute(rtn);

  std::vector<IScriptObject> rtn1;
  std::vector<IScriptObject> a(2);
  a[0].SetInt32(10);
  a[1].SetInt32(20);
  ret = script.ExecuteFunction("add", a, rtn1); 

  std::vector<IScriptObject> rtn2;
  std::vector<IScriptObject> b(1);
  b[0].SetString("blubbb");
  ret = script.ExecuteFunction("testFunc", b, rtn2);
  
  std::vector<IScriptObject> rtn3;
  ret = script.ExecuteFunction("testRtn", rtn3, 3, rtn3);
  
Lua

Code: Alles auswählen

print "lalala"

function add(x,y)
  return x+y
end

function testFunc(str)
  print(str)
  return 1
end

function testRtn()
  return "blubb", 22, 34
end
Da umzu kommt noch ein Verwalter, dann kann ich auch z.B. Skript-Funktionen überladen.

Re: Problem mit Zeigern

Verfasst: 05.06.2009, 11:04
von kimmi
Warum nicht

Code: Alles auswählen

 a[0].SetInt32( 10 );
  a[1].SetInt32( 20 );
durch sowas ersetzen:

Code: Alles auswählen

myStack args;
args.pushInt( 10 );
args.pushInt( 20 );
etc.
Lua benutzt einen Stack, du gerade einen std::vector. Dein Zugriff über den Index-Operator ist fehleranfälliger. Du mußt dafür sorgen, daß genügend Speicher da ist etc. . Sicher geht das auch mit einem std::vector. Aber es gibt halt auch von der STL stacks.
Das ist aber Geschmackssache, ist mir klar.

Gruß Kimmi

Re: Problem mit Zeigern

Verfasst: 05.06.2009, 13:44
von odenter
Ja wäre noch ne Idee, werd ich testweise mal ausprobieren. Und dann gucken was mir tatsächlich besser gefällt, eigentlich soll es so tatsächlich auch nicht benutzt werden sondern eher so, hab die Methoden nur noch nicht gebaut. :)

Code: Alles auswählen

script.AddParam(::INT32, 123);
script.AddParam(::STRING, "bla blubb");