Malloc auf Array? Globale Variablen?
-
Hallo,
heute muss ich mal mit zwei Fragen nerven:
1. Speicher anfordern via malloc
Ein eindimensionales Array via malloc kriegt man ja ganz einfach gebacken. Aber wie schaut es mit zwei oder auch mehr Dimensionen aus? Wie ist da die Syntax?
Bsp:char Blubb[20][40]
Wie muss malloc für ein derartiges Array aufgerufen werden? Geht das überhaupt?
2. Globale Variablen
Jeder sagt man solle keine globalen Variablen verwenden. Warum nicht? Wäre es nicht vorteilhafter ich würde eine Variable, die ich durch drei Funktionen (main -> Func1 -> Func2 -> Func3) schleife nicht kurzerhand global definieren?
Wo wäre da der Vorteil/Nachteil?So, ich hoffe Ihr könnt mich mal wieder ein wenig erleuchten.
Danke und Gruss
Holgie
-
Holgie schrieb:
...
1. Speicher anfordern via malloc
Ein eindimensionales Array via malloc kriegt man ja ganz einfach gebacken. Aber wie schaut es mit zwei oder auch mehr Dimensionen aus? Wie ist da die Syntax?
Bsp:char Blubb[20][40]
Wie muss malloc für ein derartiges Array aufgerufen werden? Geht das überhaupt?
Hier mal ein kleines Beispielprogramm das ich vor einiger Zeit erstellt habe:
#include <stdio.h> #include <stdlib.h> enum { x = 8, y = 8, z = 8 }; int main(void) { double *** m; int i, j, k; m = malloc(x * sizeof(*m)); for (i = 0; i < x; ++i) { m[i] = malloc(y * sizeof(**m)); for (j = 0; j < y; ++j) { m[i][j] = malloc(z * sizeof(***m)); } } // Mit irgendwelchen Daten befüllen... for (i = 0; i < x; ++i) { for (j = 0; j < y; ++j) { for (k = 0; k < z; ++k) { m[i][j][k] = (i+1) * (j+1) * (k+1); } } } // Ausgabefunktion for (k = 0; k < z; ++k) { printf("Feld %d:\n", k+1); for (i = 0; i < x; ++i) { for (j = 0; j < y; ++j) { printf("%6.0f ", m[i][j][k]); } putchar('\n'); } putchar('\n'); } // Freigeben muss in umgekehrter Reihenfolge passieren... for (i = 0; i < x; ++i) { for (j = 0; j < y; ++j) { free(m[i][j]); } free(m[i]); } free(m); return 0; }
Wenn Du das mal durcharbeitest dann sollte es eigentlich verständlich werden. Wenn nicht - frag einfach nochmal.
2. Globale Variablen .... Wo wäre da der Vorteil/Nachteil?
Vorteil: Bei einfachen Programmen mag es noch übersichtlich sein,
Nachteil: aber bei längeren Programmen wird unweigerlich die Übersichtlichkeit verloren gehen.
-
Ah, Danke. Bin immer wieder erstaunt wie fix das hier geht
Eine kleine Frage noch zum double **m:
Ich sehe das also richtig, dass ich für jede Dimension meines Arrays einen "" setzen muss. Mit meinem bisherigen Verständniss für C wäre das ein Pointer-auf-Pointer-auf-Pointer? Oder ist das wieder eine von den Dereferenzierungsgeschichten um die ich mich immernoch drücke?Und noch zu den globalen Variablen:
Also haben globale Variablen keinen Einfluss auf Geschwindigkeit oder Speicherplatzbedarf (vorrausgesetzt, sie werden in main und global gleich definiert)?Gruss
Holgie
-
Holgie schrieb:
Ah, Danke. Bin immer wieder erstaunt wie fix das hier geht
Eine kleine Frage noch zum double **m:
Ich sehe das also richtig, dass ich für jede Dimension meines Arrays einen "" setzen muss. Mit meinem bisherigen Verständniss für C wäre das ein Pointer-auf-Pointer-auf-Pointer? Oder ist das wieder eine von den Dereferenzierungsgeschichten um die ich mich immernoch drücke?Jep. Ums aber jetzt genau zu machen: m ist in meinem Beispiel ein Zeiger auf einen Zeiger auf einen Zeiger auf einen double.
Holgie schrieb:
Und noch zu den globalen Variablen:
Also haben globale Variablen keinen Einfluss auf Geschwindigkeit oder Speicherplatzbedarf (vorrausgesetzt, sie werden in main und global gleich definiert)?...hmmm ...
ich würde sagen, dass das auf den Compiler ankommt. Aber Kriegsentscheidend (in Bezug auf Geschwindigkeit und/oder Speicherplatz) sollte das nicht sein...
-
Damit hätte ich wohl alle Antworten beisammen. Danke mady!
Gruss
Holgie
-
globale variablen liegen immer im speicher, lokale nur solange sie existieren.
-
Die Warnung vor globalen Variablen ist berechtigt.
Oftmals führen globale Variablen, die aus Bequemlichkeit angelegt wurden,
wie ein Buffer für irgendwelche ''temporären'' Abeitsvariablen zu äußerst interessanten Nebeneffekten, da sie an Stellen modifiziert werden an denen man es nicht erwartet.int glob_tmpdat; func1(...) { int i; glob_tmpdat=5; for (i=0;i<glob_tmpdat;i++) { func2("Teststring"); } } func2(char *s) { int i .... glob_tmpdat=strlen(s); for (i=0;i<glob_tmpdat;i++) s[i]=to_upper(s[i]); ...... }
Typischer Fehler mit globalen Variablen genau solche Nebeneffekte führen zu äußert langen Debugsitzungen.
Der Einsatz von globalen Variablen minimiert die Portabilität von Funktionen.
------------------------------
Wenn beim ProgrammDesign globale Daten mitgeplant werden, und auch der Zugriff
geregelt wird kann, es viele Arbeiten auch deutlich einfacher machen.Inzwischen bietet da C++ einen vernünftigen Ansatz durch das Klassenkonzept.
Die Daten werden als private in einer Klasse definiert. Es wird eine globale Instanz der Klasse erzeugt und im Programm kann man auf diese dann nur über die Klassenmembers zugreifen. Auf diese Weise ist ''unnötige'' Übergabe von Daten an Funktionen eingespart. Allerdings sind solche Funktionen nicht portabel da sie auf diese globalen Variablen angewiesen sind
-
PAD schrieb:
Oftmals führen globale Variablen, die aus Bequemlichkeit angelegt wurden, wie ein Buffer für irgendwelche ''temporären'' Abeitsvariablen zu äußerst interessanten Nebeneffekten, da sie an Stellen modifiziert werden an denen man es nicht erwartet.
Ich erwarte von Programmen, die nicht richtig funktionieren (warum sollte ich sonst den Quelltext anfassen?) vorsichtshalber überhauptnichts. Wildes Herumspekulieren ist deplaziert, wenn ich herausfinden soll, was das Programm/die Funktion eigentlich macht.
Typischer Fehler mit globalen Variablen genau solche Nebeneffekte führen zu äußert langen Debugsitzungen.
Der Fehler ist, dass Du Dich auf etwas verlässt. Nichts sonst.
Dass diese 'globalen Variablen' (so etwas gibt es in C nicht) auch falsch eingesetzt werden können ist jetzt keine allzu atemberaubende Neuigkeit.Wenn beim ProgrammDesign globale Daten mitgeplant werden, und auch der Zugriff geregelt wird kann, es viele Arbeiten auch deutlich einfacher machen.
Genau. Man darf diese 'globalen' Datenmengen trotzdem so klein wie möglich halten.
Inzwischen bietet da C++ einen vernünftigen Ansatz durch das Klassenkonzept.
Die Daten werden als private in einer Klasse definiert. Es wird eine globale Instanz der Klasse erzeugt und im Programm kann man auf diese dann nur über die Klassenmembers zugreifen. Auf diese Weise ist ''unnötige'' Übergabe von Daten an Funktionen eingespart. Allerdings sind solche Funktionen nicht portabel da sie auf diese globalen Variablen angewiesen sindKannst Du etwas näher ausführen, wie man mithilfe der Klassenmembers auf die privaten Daten einer globalen Instanz einer Klasse unnötige Übergabe von Daten an Funktionen einspart und warum diese Funktionen dann von globalen Variablen, die das Konzept ja eigentlich vermeiden wollte, abhängt?
-
@ Daniel E.
Es geht hier nicht nur um Programme die Fehler haben sondern auch um welche die gerade in der Entwicklung sind.
Die Fragestellung von Holgie beinhaltet auch die Frage warum man keine globalen
Variablen einsetzen soll. Was ich dazu ausführte waren die typischen Fehler die neben Philosopiefragen einen dazu bringen die Nutzung von globalen Variablen zu minimieren.Atemberaubend ist es nicht
Neuigkeit ist es nicht
, aber neben Pointern eins der Probleme die eine Menge Zeit brauchen. Speziell wenn man Programme wartern mußt.
Eine von den schönen Fehlern war. In einem bestehenden Programm hat jemand die Laufvariable i als global deklariert.
Um einen Feature einzubauen hat ein Kollege eine locale Variable i benötigt und vergessen Sie zu deklarieren, somit wurde die globale genutzt, was zu tollen Effekten geführt hat. Weil im ersten Moment kommt keiner auf so einen Blödsinn.
class test { privat: int i; public: void setValue(int val); int getValue(void); .... Konstruktoren,... } test a; main() { int b; ..... a.setValue(33); b=a.getValue(); ... } function1(..) { ... a.setValue(44); } // Hoffentlich sind keine Typos drin, habe den Code nicht getestet
Hier wird ein Datum i aus der Klasse test global genutzt. Die Wahrscheinlichkeit das jemand hier eine Fehlnutzung vornimmt ist für mich geringer als mit einer globalen Variablen i.
-
madys Beispiel ist nicht genau die Antwort auf deine Frage.
Wenn du ein char Blubb[SIZE_A][SIZE_B] verwenden willst, musst du einfach
char *Blubb = malloc( SIZE_A * SIZE_B);
verwenden.
wobei SIZE_A und SIZE_B hier Konstanten oder Variablen sein können.(und natürlich den Rückgabewert auf NULL testen)
-
Geo schrieb:
madys Beispiel ist nicht genau die Antwort auf deine Frage.
Wenn du ein char Blubb[SIZE_A][SIZE_B] verwenden willst, musst du einfach
char *Blubb = malloc( SIZE_A * SIZE_B);
verwenden.
wobei SIZE_A und SIZE_B hier Konstanten oder Variablen sein können.(und natürlich den Rückgabewert auf NULL testen)
hmmm ... aber so ohne weiteres ist dann ein Zugriff auf das Array mit Blubb[x][y] aber nicht möglich. Von anderen Problemen mal abgesehen
-
Geo schrieb:
madys Beispiel ist nicht genau die Antwort auf deine Frage.
Wenn du ein char Blubb[SIZE_A][SIZE_B] verwenden willst, musst du einfach
char *Blubb = malloc( SIZE_A * SIZE_B);
verwenden.
wobei SIZE_A und SIZE_B hier Konstanten oder Variablen sein können.(und natürlich den Rückgabewert auf NULL testen)
Das alloziiert aber keinen Speicher fuer 'Blubb[SIZE_A][SIZE_B]'
mfg
v R
-
Hab das Beispiel von PAD mal ausführlich nachvollzogen, da ich selbst auch immer den einfachen Weg gehe und jede Menge globale Variablen anlege.
Hier das Beispiel von PAD zum direkten übernehmen: int iTest != global
Unit1.cpp
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" #include "MyClass.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; // *** Definition des Objekts "a" der Klasse TMyClass *** TMyClass a; // *** Funktions-Deklarationen *** void Function1( void ); //void Function2( void ); //... //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- // Setze Value direkt void __fastcall TForm1::Button1Click(TObject *Sender) { a.setValue( StrToInt( Edit1->Text ) ); } //--------------------------------------------------------------------------- // Get Value void __fastcall TForm1::Button2Click(TObject *Sender) { int b; b = a.getValue(); Label1->Caption = IntToStr( b ); } //--------------------------------------------------------------------------- // Setze Value via Function1() void __fastcall TForm1::Button3Click(TObject *Sender) { Function1(); } //--------------------------------------------------------------------------- void Function1( void ) { a.setValue( StrToInt( Form1->Edit1->Text ) + 5 ); } //---------------------------------------------------------------------------
Unit1.h
//--------------------------------------------------------------------------- #ifndef Unit1H #define Unit1H //--------------------------------------------------------------------------- #include <Classes.hpp> #include <Controls.hpp> #include <StdCtrls.hpp> #include <Forms.hpp> //--------------------------------------------------------------------------- class TForm1 : public TForm { __published: // Von der IDE verwaltete Komponenten TButton *Button1; TButton *Button2; TButton *Button3; TLabel *Label1; TEdit *Edit1; void __fastcall Button1Click(TObject *Sender); void __fastcall Button2Click(TObject *Sender); void __fastcall Button3Click(TObject *Sender); private: // Anwender-Deklarationen public: // Anwender-Deklarationen __fastcall TForm1(TComponent* Owner); }; //--------------------------------------------------------------------------- extern PACKAGE TForm1 *Form1; //--------------------------------------------------------------------------- #endif
MyClass.cpp
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "MyClass.h" //--------------------------------------------------------------------------- #pragma package(smart_init) //--------------------------------------------------------------------------- // *** Definition des Konstruktors TMyClass *** __fastcall TMyClass::TMyClass( void ) { } //--------------------------------------------------------------------------- // *** Methodendefinitionen von TMyClass *** void __fastcall TMyClass::setValue( int val ) { iTest = val; } //--------------------------------------------------------------------------- // *** Methodendefinitionen von TMyClass *** __fastcall TMyClass::getValue( void ) { return iTest; } //---------------------------------------------------------------------------
MyClass.h
//--------------------------------------------------------------------------- #ifndef MyClassH #define MyClassH //--------------------------------------------------------------------------- // *** Deklaration der Klasse TMyClass *** class TMyClass { private: // *** Eigenschaften *** int iTest; public: // *** Methoden *** void __fastcall setValue( int val ); __fastcall getValue( void ); // *** Konstruktor *** __fastcall TMyClass( void ); }; //--------------------------------------------------------------------------- #endif
Gruß WoWe
-
was heisst fuer dich != global?
du hast fuer mich 2 globale variablen
a und Form1
Form1 muss wohl global sein, da es die VCL vorschreibtaber a??
du hast i in eine klasse gesteckt und nennst es nun nicht mehr global.
genau das ist aber bloedsinn.ich kann immer noch i veraendern wie ich will, ich muss zwar getter und setter verwenden, das ist ne spur besser als richtig global, aber immer noch verdammt mies.
btw:
__fastcall TMyClass::getValue( void )
syntax fehler
return value fehlt.und lass das void weg, in C++ schreibt man das nicht!
btw: Function1() ist ne miese funktion mit seiteneffekten...
-
Hmm, also ich war mir sicher das diese Art richtig ist um "a" als globale Variable zu umgehen.
Dann hab ich die Bitte an dich und korrigiere das Beispiel von mir so das es richtig ist (nicht nur für mich) !
Gruß WoWe
-
machen wirs so:
du gibts mir ein beispiel wo man deiner meinung nach eine globale variable verwenden muss und wir diskutieren es dann aus (wo die nachteile der globalen variablen liegen, wo die vorteile liegen, was man am design aendern koennte, etc).
dein ganzes beispiel ist naehmlich n bisschen bloed.
-
Naja, dann nehmen wir einfach an, dass außer der Variable iTest mehrere Variablen in mehreren Funktionen über mehrere Formulare/Units gelesen und aktualisiert werden. Das sollte ja kein nutzbares Programm werden sondern nur ein Beispiel wie ich mit Variablen arbeiten kann ohne sie global anzulegen und dann mit extern drauf zugreifen.
-
ich wuerde sagen:
MVC-Modell
mit Observer-PatternBTW:
du solltest wirklich nicht die VCL verwenden, wenn du solchen code schreibst...globale variablen, funktionen mit seiteneffekten, code in den forumlaren,... (grausam)
-
hab ich was übersehen oder wieso tuts statt dem *** gehampel kein simples
char* mspeicher =(char*)malloc(sizeof(char[20][40]));
-
dreaddy schrieb:
hab ich was übersehen oder wieso tuts statt dem *** gehampel kein simples
char* mspeicher =(char*)malloc(sizeof(char[20][40]));
Weil Du dann immer noch nicht ohne weiteres mit mspeicher[x][y] auf die einzelnen Elemente zugreifen kannst.