Mehrdimensionale Vektoren als Funktionsparameter in C++

Schnelle objektorientierte, kompilierende Programmiersprache.
Antworten
nufan
Wiki-Moderator
Beiträge: 2558
Registriert: Sa Jul 05, 2008 3:21 pm

Mehrdimensionale Vektoren als Funktionsparameter in C++

Beitrag von nufan » Fr Mai 01, 2009 11:01 pm

Ja, ich mal wieder :)

Zur Problembeschreibung:
Für ein Programm brauche ich einen zweidimensionalen Array. Er hat eine Mindestgröße. Jedoch kann sich seine Größe während der Laufzeit ändern. Natürlich hätte ich mir das mit ein bisschen memcpy, new und delete selbst basteln können, aber warum das Rad neu erfinden? Also Google angeworfen. Der erste Treffer sieht mal nicht schlecht aus. Nur übergebe ich diesen Array bzw. (hoffentlich bald) Vektor einige Male an eine Funktion. Doch wie sieht dann der Funktionskopf (bezüglich Typ) der Funktion aus? Muss da jedes Mal

Code: Alles auswählen

vector<vector<typ> > name(größe);
stehen?

Noch was:
Liegt bei einem Vektor der gesamte Speicherbereich in einer Reihe? Kann ich ohne Probleme an fread/fwrite mit einer Anzahl von Länge*Breite übergeben?

Wäre dankbar für ein kurzes Beispiel mit Erklärung oder wenigstens einen Link. Bei ersterem profitiert auch das Wiki davon :)

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8860
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Mehrdimensionale Vektoren als Funktionsparameter in C++

Beitrag von Xin » Sa Mai 02, 2009 7:37 am

dani93 hat geschrieben:Für ein Programm brauche ich einen zweidimensionalen Array. Er hat eine Mindestgröße. Jedoch kann sich seine Größe während der Laufzeit ändern. Natürlich hätte ich mir das mit ein bisschen memcpy, new und delete selbst basteln können, aber warum das Rad neu erfinden? Also Google angeworfen. Der erste Treffer sieht mal nicht schlecht aus. Nur übergebe ich diesen Array bzw. (hoffentlich bald) Vektor einige Male an eine Funktion. Doch wie sieht dann der Funktionskopf (bezüglich Typ) der Funktion aus? Muss da jedes Mal

Code: Alles auswählen

vector<vector<typ> > name(größe);
stehen?
Möglichkeit 1:

Code: Alles auswählen

typedef vector<vector< typ > > MeinTyp;[code]
Nun hast Du eine Kurzschreibweise.

Du kannst davon ableiten:
[code]class MeinTyp : public vector<vector< typ > > {};[code]

Noch besser:
Du schreibst eine eigene Klasse.

[quote="dani93"]Noch was:
Liegt bei einem Vektor der gesamte Speicherbereich in einer Reihe? Kann ich ohne Probleme an fread/fwrite mit einer Anzahl von Länge*Breite übergeben?[/quote]
Bei zweidimensionallen Vectoren gebe ich Dir mal einfach so eine Garantie, dass der Speicherbereich nicht in einer Reihe liegt.

Bei einem eindimensionalen Vector darfst Du davon ausgehen, dass das Implementierungsabhängig ist - also darfst Du davon nicht ausgehen.
Bei VisualStudio 6 war das noch so... also (<- das klingt nach einer Schlussfolgerung, war aber eine Dummheit) hat man diese Tatsache für ein kommerzielles Programm genutzt. Es wird heute noch auf Visual Studio 6 entwickelt. Auf Windows XP, weil VS6 läuft auf Vista nicht. Ab Studio 7 hat ich nämlich die Implementierung des Vectors geändert und da man da auch einfach auf die internen Daten des Vectors zugreift, statt eine eigene Klasse zu kapseln, kann man nicht auf Studio 7, 8 oder sonstwas wechseln.

[quote="dani93"]Wäre dankbar für ein kurzes Beispiel mit Erklärung oder wenigstens einen Link. Bei ersterem profitiert auch das Wiki davon  :)[/quote]
Welche Art Beispiel brauchst Du denn?
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Benutzeravatar
fat-lobyte
Beiträge: 1398
Registriert: Sa Jul 05, 2008 12:23 pm
Wohnort: ::1
Kontaktdaten:

Re: Mehrdimensionale Vektoren als Funktionsparameter in C++

Beitrag von fat-lobyte » Sa Mai 02, 2009 9:28 am

dani93 hat geschrieben: Muss da jedes Mal

Code: Alles auswählen

vector<vector<typ> > name(größe);
stehen?
Hat Xin schon beantworet, ich wäre aber eher für die typedef- Variante.
dani93 hat geschrieben:Liegt bei einem Vektor der gesamte Speicherbereich in einer Reihe? Kann ich ohne Probleme an fread/fwrite mit einer Anzahl von Länge*Breite übergeben
Zwar liegen die Elemente höchstwahrscheinlich in einer Reihe - du hast aber keine Garantie dafür. Tatsache ist, du hast nichtmal die Möglichkeit einen richtigen "Zeiger" im klassischen Sinne auf deine Elemente zu bekommen.

Was du bekommen kannst ist ein "Iterator".
Was ist dieser komische Iterator?
Das möchte ich versuchen Anhand eines Zeigers zu erklären: Ein Zeiger auf ein Array hat zwei Funktionen:
erstens: er zeigt auf das Objekt, also wo im Speicher das Array liegt
zweitens: er kann verwendet werden, um auf das Array zuzugreifen, also "durchzuiterieren".

Spaltet man nun die beiden Funktionen eines Zeigers auf verschieden Dinge auf, hast du erstens - den speicherteil (ich vergleiche das in meinem Kopf mit einer Java- Referenz) und zweitens einen Zugriffsteil, den Iterator.

Die Container der STL handhaben den Speicher nämlich intern, die Iterator sind nur für den Zugriff da.

Für den Dateizugriff würde ich dir in C++ sowieso was anderes empfehlen, und zwar die Iostream Klassen. Etwas in die Jahre gekommen, funktionieren aber immer noch. Um deinen zweidimensionalen Vektor einzulesen bzw. zu schreiben müsstest du nur den Vektor mithilfe der Iteratoren richtig schreiben bzw. auslesen.
Dazu könntest du std::istream_iterator bzw. std::ostream_iterator in einer verschachtelten schleife verwenden.

Als alternative gibts noch was von Boost, das habe ich aber noch nie verwendet: http://www.boost.org/doc/libs/1_38_0/li ... /user.html
Haters gonna hate, potatoes gonna potate.

nufan
Wiki-Moderator
Beiträge: 2558
Registriert: Sa Jul 05, 2008 3:21 pm

Re: Mehrdimensionale Vektoren als Funktionsparameter in C++

Beitrag von nufan » Sa Mai 02, 2009 4:32 pm

Ich hab mir das noch mal überlegt und doch eine eigene Klasse geschrieben ;)
Vorweg - sie ist auf mein Programm zugeschnitten. Sie kann das, was ich will. Es ist also kein "normaler" Vektor. Es ist ein 2D-Vektor, bei dem alle Spalten gleich lang und alle Zeilen gleich breit sind. Gelöscht werden kann nur zeilen- bzw. blockweise und nur am Ende.


Hier der Code:

Code: Alles auswählen

class C2DVector
{

  private:
    int **v;
    int w, h;

  public:
    C2DVector ();
    C2DVector (int sw, int sh);
    ~C2DVector ();
    int GetWidth ();
    int GetHeight ();
    void NewRow ();
    void NewColumn ();
    void DelRow ();
    void DelCol ();
    void SetValue (int row, int column, int value);
    int GetValue (int row, int column);
    void PrintArray ();                                     // nur zu debug-Zwecken

};

Code: Alles auswählen

#include "C2DVector.h"
#include <cstring>
#include <iostream>


using namespace std;


C2DVector::C2DVector ()
{

  v = NULL;

  w = h = 0;

}



C2DVector::C2DVector (int sw, int sh)
{

  v = new int * [sh];

  w = sw;
  h = sh;

  for (int i = 0; i < sh; i++)
  {

    v[i] = new int [sw];

    memset (v[i], 0, w);

  }

}



C2DVector::~C2DVector ()
{

  if (v != NULL)
  {

    for (int i = 0; i < h; i++)
      if (v[i] != NULL)
        delete [] v[i];

    delete [] v;

  }

}



int C2DVector::GetWidth ()
{

  return w;

}



int C2DVector::GetHeight ()
{

  return h;

}



void C2DVector::NewRow ()
{

  int **tmp;


  h++;

  tmp = new int * [h];

  for (int i = 0; i < h; i++)
    tmp[i] = new int [w];

  for (int i = 0; i < h - 1; i++)
    memcpy (tmp[i], v[i], w * sizeof (int));

  memset (tmp[h - 1], 0, w * sizeof (int));


  for (int i = 0; i < h - 1; i++)
    if (v[i] != NULL)
      delete [] v[i];

  delete [] v;


  v = tmp;

}



void C2DVector::NewColumn ()
{

  int **tmp;


  w++;

  tmp = new int * [h];

  for (int i = 0; i < h; i++)
    tmp[i] = new int [w];

  for (int i = 0; i < h - 1; i++)
  {

    memcpy (tmp[i], v[i], (w - 1) * sizeof (int));

    tmp[i][w - 1] = 0;

  }


  for (int i = 0; i < h - 1; i++)
    if (v[i] != NULL)
      delete [] v[i];

  delete [] v;


  v = tmp;

}



void C2DVector::DelRow ()
{

  int **tmp;


  h--;

  tmp = new int * [h];

  for (int i = 0; i < h; i++)
    tmp[i] = new int [w];

  for (int i = 0; i < h - 1; i++)
    memcpy (tmp[i], v[i], w * sizeof (int));


  for (int i = 0; i < h - 1; i++)
    if (v[i] != NULL)
      delete [] v[i];

  delete [] v;


  v = tmp;

}



void C2DVector::DelCol ()
{

  int **tmp;


  w--;

  tmp = new int * [h];

  for (int i = 0; i < h; i++)
    tmp[i] = new int [w];

  for (int i = 0; i < h - 1; i++)
    memcpy (tmp[i], v[i], w * sizeof (int));


  for (int i = 0; i < h - 1; i++)
    if (v[i] != NULL)
      delete [] v[i];

  delete [] v;


  v = tmp;

}



void C2DVector::SetValue (int row, int column, int value)
{

  if (row < h && column < w && row >= 0 && column >= 0)
    v[row][column] = value;

}



int C2DVector::GetValue (int row, int column)
{

  if (row < h && column < w && row >= 0 && column >= 0)
    return v[row][column];

    else
      return -1;

}



void C2DVector::PrintArray ()
{

  for (int i = 0; i < h; i++)
  {

    cout << "Zeile " << i << endl;

    for (int j = 0; j < w; j++)
      cout << "Spalte " << j << ": " << v[i][j] << endl;

    cout << endl;

  }

}
Sicher noch optimierungsfähig, aber ich bin schon froh, dass es überhaupt funktioniert ^^
Bis jetzt sind mir noch keine Bugs aufgefallen.

dP.
Beiträge: 23
Registriert: Di Apr 14, 2009 2:52 pm

Re: Mehrdimensionale Vektoren als Funktionsparameter in C++

Beitrag von dP. » So Mai 03, 2009 4:47 pm

Warum nicht einen vector<vector<type>> als Klassenattribut? Das spart die Zeigerei.

nufan
Wiki-Moderator
Beiträge: 2558
Registriert: Sa Jul 05, 2008 3:21 pm

Re: Mehrdimensionale Vektoren als Funktionsparameter in C++

Beitrag von nufan » So Mai 03, 2009 6:19 pm

dP. hat geschrieben:Warum nicht einen vector<vector<type>> als Klassenattribut?
Ich hab diese Klasse nur geschrieben um das zu vermeiden...

dP.
Beiträge: 23
Registriert: Di Apr 14, 2009 2:52 pm

Re: Mehrdimensionale Vektoren als Funktionsparameter in C++

Beitrag von dP. » Mo Mai 04, 2009 1:39 pm

Dann hab ich dich wohl falsch verstanden.

Antworten