Problem mit Zeigern

Design Patterns, Erklärungen zu Algorithmen, Optimierung, Softwarearchitektur
Forumsregeln
Wenn das Problem mit einer Programmiersprache direkt zusammenhängt, bitte HIER posten.
Antworten
odenter
Establishment
Beiträge: 207
Registriert: 26.02.2009, 11:58

Problem mit Zeigern

Beitrag 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?
Zuletzt geändert von odenter am 04.06.2009, 14:39, insgesamt 1-mal geändert.
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: Problem mit Zeigern

Beitrag 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?
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Krishty
Establishment
Beiträge: 8249
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Problem mit Zeigern

Beitrag 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).
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
odenter
Establishment
Beiträge: 207
Registriert: 26.02.2009, 11:58

Re: Problem mit Zeigern

Beitrag 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.
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: Problem mit Zeigern

Beitrag 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
Benutzeravatar
Lord Delvin
Establishment
Beiträge: 577
Registriert: 05.07.2003, 11:17

Re: Problem mit Zeigern

Beitrag 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ß.
XML/JSON/EMF in schnell: OGSS
Keine Lust mehr auf C++? Versuche Tyr: Get & Get started
Benutzeravatar
TGGC
Establishment
Beiträge: 569
Registriert: 15.05.2009, 18:14
Benutzertext: Ich _bin_ es.
Alter Benutzername: TGGC
Echter Name: Ich _bin_ es.
Wohnort: Mainz
Kontaktdaten:

Re: Problem mit Zeigern

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

Re: Problem mit Zeigern

Beitrag 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.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
odenter
Establishment
Beiträge: 207
Registriert: 26.02.2009, 11:58

Re: Problem mit Zeigern

Beitrag 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.
Benutzeravatar
kimmi
Moderator
Beiträge: 1405
Registriert: 26.02.2009, 09:42
Echter Name: Kim Kulling
Wohnort: Luebeck
Kontaktdaten:

Re: Problem mit Zeigern

Beitrag 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
odenter
Establishment
Beiträge: 207
Registriert: 26.02.2009, 11:58

Re: Problem mit Zeigern

Beitrag 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");
Antworten