Forum: PC-Programmierung c++ Speicher dynamisch erweitern (als Funktion)


von Max (Gast)


Lesenswert?

Hallo
ich habe mir eine Funktion geschrieben die ein "Array" dynamisch anlegt, 
da ich verschiedene Variablen benötige die dynamisch angelegt werden 
sollen, wollte ich das flexibel gestalten (d.h. ich gebe die Adresse und 
[breite][Länge] mit). Leider schlagen meine Versuche fehl, und hoffe ihr 
helft mir weiter zu kommen.

Das ganze ist wie folgt aufgebaut:
Eine Klasse mit 3 private Variablen, die dynamisch vergrößert werden 
sollen und eine Memberfunktion die diese anlegen soll.

Bsp:
1
 // Die Klassenvariablen (Klasse Matrix)
2
double **matrix1,**matrix2,**ergebnis;
3
4
// Memberfunktionsaufruf
5
void anlegen(double*,int,int) //double* z.B. matrix1, int breite,int länge
6
7
// Der Aufruf in einer anderen Funktion
8
anlegen(matrix1,laenge,breite);
9
anlegen(matrix2,laenge,breite);
10
11
12
// Funktion
13
14
void Matrix::anlegen(double**speicher,int a, int b1){
15
  speicher =new double*[a];
16
  if (NULL == speicher) {
17
    cout<<"Kein Speicher vorhanden"<<endl;
18
    return;
19
  }
20
  
21
  for(int i=0;i<a;i++) {
22
    speicher[i]=new double[b1]; //[a][b1]
23
    if(NULL==speicher[i]) {
24
    cout<<"Kein Speicher vorhanden"<<endl;
25
    return;
26
    }
27
//    speicher[i]=0;
28
  }
29
  
30
  return;
31
}

Mein Compiler ist MinGW (Editor ist Notepad++)
gibt keine Fehler raus.
Ich vermute der Speicher wird nicht erweitert, denn sobald man die den 
neuen Speicher füllt stürzt das Programm ab.


Gruß
Max

von Peter II (Gast)


Lesenswert?

> speicher =new double*[a];

ich glaube das müsste ein

*speicher =new double*[a];

werden.

Aber wenn du nicht unbedingt das Rad neu erfinden willst, kannst du auch 
einfach realloc verwenden, oder noch besser gleich std::vector.

von Max (Gast)


Lesenswert?

>> speicher =new double*[a];

>ich glaube das müsste ein

>*speicher =new double*[a];

Fehler: »double**« kann nicht nach »double*« in Zuweisung umgewandelt 
werden

>Aber wenn du nicht unbedingt das Rad neu erfinden willst, kannst du auch
>einfach realloc verwenden, oder noch besser gleich std::vector.

etwa so mit vector:
1
#include <vector>
2
using namespace std;
3
int main()
4
{
5
    const int FirstDim = 3;
6
    const int SecDim = 2;
7
    vector< vector<int> > My2DimArr(FirstDim);
8
    for (int i = 0; i < FirstDim; i++)
9
        My2DimArr[i].resize(SecDim);
10
   
11
    My2DimArr[1][1] = 42;
12
}
(von http://www.c-plusplus.de/forum/39489-full)

mir geht es eigentlich eher darum mit einer funktion universell mehrere 
2D-Matrizen anzulegen. Daher dachte ich wenn ich die Adresse übergebe, 
kann ich das so gestalten...
mit dem vector bin ich genau so schlau wie vorher (könnte natürlich 
diese funktion für jedes "Array" schreiben... unschön)
trotzdem danke

von Peter II (Gast)


Lesenswert?

Max schrieb:
> Fehler: »double**« kann nicht nach »double*« in Zuweisung umgewandelt
> werden
ok, dann mal so

void Matrix::anlegen(double& *speicher,int a, int b1){

dann müsste es auch gehen

von Rolf M. (rmagnus)


Lesenswert?

Max schrieb:
> // Funktion
>
> void Matrix::anlegen(double**speicher,int a, int b1){
>   speicher =new double*[a];
>   if (NULL == speicher) {

Dieses new liefert niemals NULL zurück. Wenn kein Speicher allokiert 
werden konnte, wird eine Exception geworfen. Alternativ kann man 
new(nothrow) nehmen.

Max schrieb:
> Ich vermute der Speicher wird nicht erweitert, denn sobald man die den
> neuen Speicher füllt stürzt das Programm ab.

Um den füllen zu können, müßtest du erstmal irgendwie seine Adresse 
haben. Versuch's mal mit:
1
void Matrix::anlegen(double**&speicher,int a, int b1)

von Peter II (Gast)


Lesenswert?

Peter II schrieb:
> Max schrieb:
>
>> Fehler: »double**« kann nicht nach »double*« in Zuweisung umgewandelt
>> werden
> ok, dann mal so
>
> void Matrix::anlegen(double& *speicher,int a, int b1){
> dann müsste es auch gehen

sorry wird auch nicht gehen, weil es ja eine matrix ist. Du braucht noch 
einen * mehr.

void Matrix::anlegen(double& **speicher,int a, int b1){

aber vermutlich geht das auch nicht.

von Karl H. (kbuchegg)


Lesenswert?

Max schrieb:

> Das ganze ist wie folgt aufgebaut:
> Eine Klasse mit 3 private Variablen, die dynamisch vergrößert werden
> sollen und eine Memberfunktion die diese anlegen soll.

Die erste Frage, die ich mir stelle:
Wenn die Pointer sowieso Member Variablen der Klasse sind, warum 
übergibst du dann den Pointer an die Memberfunktion? Als Memberfunktion 
hat die sowieso direkten Zugriff.
1
class Matrix
2
{
3
  public:
4
    Matrix() : speicher_( NULL ), sizeX_( 0 ), sizeY_( 0 )
5
    {}
6
    Matrix( unsigned int sizeX, unsigned int sizeY )
7
    {
8
      allocate( sizeX, sizeY );
9
    }
10
    ~Matrix()
11
    {
12
      deallocate();
13
    }
14
15
    double get( unsigned int x, unsigned int y ) const;
16
    void   set( unsigned int x, unsigned int y, double value );
17
18
  private:
19
    double** speicher_;
20
    int      sizeX_;
21
    int      sizeY_;
22
23
    Matrix( const Matrix& rhs );            // not implemented by intention
24
    Matrix& operator=( const Matrix& rhs ); // not implemented by intention
25
26
    void allocate( unsigned int sizeX, unsigned int sizeY );
27
    void deallocate();
28
};
29
30
inline void Matrix::allocate( unsigned int sizeX, unsigned int sizeY )
31
{
32
  speicher_ = new double* [sizeY ];
33
  for( unsigned int y = 0; y < sizeY; ++y )
34
    speicher_[y] = new double [sizeX];
35
36
  sizeX_ = sizeX;
37
  sizeY_ = sizeY;
38
}
39
40
inline void Matrix::deallocate()
41
{
42
  for( unsigned int y = 0; y < sizeY_; ++y )
43
    delete [] speicher_[y];
44
  delete [] speicher_;
45
46
  speicher_ = NULL;
47
  sizeX_ = 0;
48
  sizeY_ = 0;
49
}
50
51
inline double Matrix::get( unsigned int x, unsigned int y ) const
52
{
53
  if( x < sizeX_ && y < sizeY_ && speicher_)
54
    return speicher_[x][y];
55
56
  return 0.0;
57
}
58
59
inline void Matrix::set( unsigned int x, unsigned int y, double value )
60
{
61
  if( x < sizeX_ && y < sizeY_ && speicher_)
62
    speicher_[x][y] = value;
63
}

Achtung: Der Code ist nie compiliert worden. Da mögen noch Syntaxfehler 
drinnen sein. Und für eine brauchbare Klasse müsste man jetzt noch den 
Copy Constructor und den Zuweisungsoperator, die ich momentan zur 
Sicherheit stillgelegt habe, noch implementieren.

1
int main()
2
{
3
  Matrix a( 5, 8 );
4
5
  for( int x = 0; x < 5; ++x )
6
    for( int y = 0; y < 8; ++y )
7
      a.set( x, y, x*y + x );
8
9
  for( int y = 0; y < 8; ++y )
10
  {
11
    for( int x = 0; x < 5; ++x )
12
      std::cout << a.get( x, y ) << ' ';
13
    std::cout << std::endl;
14
  }
15
}


Aber im Grunde wärst du mit std::vector besser bedient. Der macht das 
alles aus dem Stand, was du jetzt aufwendig nachimplementierst und hat 
dann auch noch vernünftige Reallokierungsstrategien mit.
ABer sagen wir einfach mal: Es ist eine Übung in der Implementierung von 
dynamischem Resource-management. So gesehen ist das ok. Denn auch das 
muss man als C++ Programmierer in Zeiten der STL beherrschen.

von Max (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Um den füllen zu können, müßtest du erstmal irgendwie seine Adresse
> haben. Versuch's mal mit:
> void Matrix::anlegen(double**&speicher,int a, int b1)

scheint zu funktionieren, ich mach morgen den umfangreichen test ;)

Karl Heinz Buchegger (kbuchegg) (Moderator)
>Die erste Frage, die ich mir stelle:
>Wenn die Pointer sowieso Member Variablen der Klasse sind, warum
>übergibst du dann den Pointer an die Memberfunktion? Als Memberfunktion
>hat die sowieso direkten Zugriff.

weil ich 3 Variablen habe für die diese Funktion gilt.
Aber vielen Dank für den Code.

Gute Nacht

von Karl H. (kbuchegg)


Lesenswert?

Max schrieb:

>>Wenn die Pointer sowieso Member Variablen der Klasse sind, warum
>>übergibst du dann den Pointer an die Memberfunktion? Als Memberfunktion
>>hat die sowieso direkten Zugriff.
>
> weil ich 3 Variablen habe für die diese Funktion gilt.

Und?
Die sind alle Member der Klasse.
Und damit haben alle Funktionen der Klasse Zugang zu diesen 
Membervariablen.

von Max (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Und?
> Die sind alle Member der Klasse.
> Und damit haben alle Funktionen der Klasse Zugang zu diesen
> Membervariablen.

aber ich will ja diese 3 dynamisch anlegen
double **matrix1,**matrix2,**ergebnis;
und nicht nur **speicher.
speicher soll je nach bedarf eine von den adressen beinhalten.
Oder überseh ich in deinem code i.was?

von Karl H. (kbuchegg)


Lesenswert?

Max schrieb:
> Karl Heinz Buchegger schrieb:
>> Und?
>> Die sind alle Member der Klasse.
>> Und damit haben alle Funktionen der Klasse Zugang zu diesen
>> Membervariablen.
>
> aber ich will ja diese 3 dynamisch anlegen
> double **matrix1,**matrix2,**ergebnis;
> und nicht nur **speicher.

Nein.
Du willst 3 Matrix Objekte anlegen!

Und jedes Matrix Objekt kümmert sich ganz alleine und für sich um seinen 
Speicher!

Du denkst noch nicht objektorientiert.
1
int main()
2
{
3
  Matrix mat1( 5, 8 );
4
  Matrix mat2( 8, 5 );
5
  Matrix ergeb( 8, 8 );
6
7
  ....
8
9
  ergeb = multiply( mat1, mat2 );
10
11
  // oder (wenn du in deinen C++ Studien schon weiter bist)
12
13
  ergeb = mat1 * mat2;
14
15
  // im Moment geht nur (wegen fehlendem op=)
16
17
  multiply( ergeb, mat1, mat2 );
18
19
  // es würde auch gehen
20
21
  mat1.multiply( ergeb, mat2 );
22
23
  ...
24
}

genau das ist der Dreh bei OOP. Objekte sind eine Symbiose aus Daten und 
Funktionalität. Das Matrix Objekte legt nicht Speicher an und gibt dir 
einen Pointer zur weiteren gefälligen Verwendung. Das Matrix Objekt IST 
dein Speicher. Wenn du mit der Matrix was tun willst, zb die Matrizen zu 
multiplizieren, dann ist dieses Matrix Objekt dein Ansprechpartner und 
nicht eine Funktion, der du einen Pointer auf Speicher übergibst, den du 
von einem Objekte bekommen hast, das du nur hast damit es dir Speicher 
allokiert. Letzteres ist die prozedurale Sichtweise der Welt. Aber wenn 
du in Richtung OOP gehen willst, dann musst du auch anfangen OOP als 
solches zu benutzen. Objekte sind Einheiten aus Daten und Code. Und man 
arbeitet mit ihnen, indem man ihnen Befehle gibt (in Form von Aufrufen 
der Memberfunktionen). Die Objekte kapseln die Daten in ihrem Inneren 
und manipulieren sie anhand deiner 'Befehle'. Aber die Innereien eines 
Objektes, wie etwas konkret implementiert ist - das ist Sache des 
Objektes. Das geht denjenigen, der das Objekt verwendet nichts an - das 
WILL er gar nicht wissen. So wie du nicht wissen willst, was in deiner 
Autoelektronik alles passiert, wenn du (bei den neueren Autos) den 
'Start'-Knopf drückst. 'Das Auto' ist ein Objekt, dem du den Befehl 
'Starten' gegeben hast. Wie es das macht, das ist das Bier der 
Auto-Klasse.

Genau darauf beruht der Erfolg von OOP. In der strikten und sauberen 
Aufteilung und Zuordnung von Kompetenzen und Zuständigkeiten. Das Matrix 
Objekt ist ganz allein und eigenverantwortlich dafür zuständig, den 
Speicher zu verwalten. Seinen Speicher! Nicht den Speicher eines anderen 
und ein anderes Objekt ist auch nicht dafür zuständig, sich um den 
Speicher dieses Objektes zu kümmern.


Und wenn du eine andere Klasse hast, die zb aus 3 'Matrizen' besteht, 
dann besteht die eben aus 3 Matrizen. Matrizen - das sind Matrix Objekte 
und nicht einfach nur Doppelpointer auf double.
1
class Image
2
{
3
  ....
4
5
6
  private:
7
    Matrix  channelRed;
8
    Matrix  channelBlue;
9
    Matrix  channelGreen;
10
};

Ein Image Objekt hat mit der ganze Speicherverwaltung für seine Pixel 
nichts mehr zu tun. Das erledigen die Matrix Objekte. Dazu sind sie da 
und das können sie. Das Image Objekt gibt einen eventuellen 'Befehl' 
sich zu vergrößern einfach nur weiter an seine Matrix Objekte. Aber es 
kümmert sich nicht mehr darum, wie das genau funktioniert. Das ist das 
Bier der Matrix Objekte.


Und ja, ich weiß.
Genau das ist das Schwierige in der objektorientierten Programmierung. 
Diese Verschiebung der eigenen Denkweise, wie ein Programmsystem 
auszusehen hat. Kommt man von der klassischen prozeduralen 
Programmierung, dann ist das umso Schwieriger. Aber wenn du diese 
Verschiebung nicht machst, dann kannst du dir Klassen auch sparen. Denn 
dann programmierst du maximal in Strukturen (also 'struct'), denen du 
das Mäntelchen 'class' umgehängt hast. Aber mit objektorientierter 
Programmierung, mit all seinen Vorteilen, hat das alles dann nichts zu 
tun. Du programmierst weiterhin C (in der undisziplinierten Form) und 
nicht OOP-C++, selbst wenn du einen C++-Compiler benutzt.

Der erste Schritt ist die Akzeptanz, dass man als Programmierer etwas 
Freiheit aufgeben muss. So wie in einem Werkzeug-Lager. Da gibt es einen 
Lagerverwalter und der hat dieses Lager über. Wenn ich was will, dann 
habe ich mich an diesen Verwalter zu wenden und nicht auf eigene Faust 
in den Regalen zu stöbern. Die Programmiersprache hilft mir dabei, den 
Tresen der Werkzeugausgabe komfortabel einzurichten. Aber ich hab nur 2 
Möglichkeiten: entweder ich akzeptiere, dass ich nicht eigenmächtig mir 
was aus den Regalen holen kann, oder ich akzeptiere das nicht. Und im 
2.ten Fall wird dann irgendwann der Firmenchef kommen und mir nahelegen 
mein Verhalten umzustellen oder ich fliege raus. Wenn wir OOP machen 
wollen, dann müssen wir auch OOP machen. Auch wenn im ersten Blick noch 
nicht ersichtlich ist, welche Vorteile das bringt. Auch wenn wir von zu 
Hause gewohnt waren, in jedem Schrank, in jeder Komode einfach jede 
Schublade aufmachen zu können und uns zu nehmen, was wir wollen oder 
brauchen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.