Array initialisieren
-
Hi Leute!
Warum kann ich arrays nicht so initialiseren?
int **graph1 = {{0,1,1,0,0,0,1,0,0}, {0,0,0,1,0,0,0,0,0}, {1,0,0,1,1,0,0,0,0}, {0,0,0,0,0,0,1,0,0}, {1,0,0,0,0,1,0,0,1}, {0,0,1,1,1,0,0,1,0}, {0,0,0,0,0,0,0,1,0}, {0,0,0,1,0,0,0,0,1}, {0,0,0,0,0,1,0,0,0}};Eine Initialisierung der Form
graph1[9][9]funktioniert aber so. Warum geht das so mit Pointern nicht?
Dann hab ich noch eine Funktion
void bfs(**graph1)deklariert, die das int-Array erhalten soll. Wie bewerkstellige ich das am Besten?
Wenn ich das als
graph1[9][9]deklarierte int-Array an
void bfs(graph1[9][9])übergebe, dann klappt das nämlich auch wieder!
-
vip@r schrieb:
Warum geht das so mit Pointern nicht?
Weil Pointer böse sind.
-
Btw: Mach graph1 global, das ist am wenigsten Stress.
-
Sehr gut!
Lange schon nicht mehr so gelacht!
Den kannte ich noch gar nicht 
-
ich hab graph1 momentan in der aufrufende main Funktion deklariert. Die Methoden (FUnktionen) kommen bei mir hier ja aus einer Klasse!
-
Brignts was wenn ich die Deklaration von graph1 in den Konstruktor schiebe?
-
vip@r schrieb:
Eine Initialisierung der Form
graph1[9][9]funktioniert aber so. Warum geht das so mit Pointern nicht?
** bedeutet nicht 2d-Array. Viele Leute denken fälschlicherweise, hinter ** steckt immer ein **, das ist Unsinn. ** ==> Zeiger auf Zeiger, nicht mehr und nicht weniger.
vip@r schrieb:
Dann hab ich noch eine Funktion
void bfs(**graph1)deklariert, die das int-Array erhalten soll. Wie bewerkstellige ich das am Besten?
Nutze einfach array-to-pointer-decay: int-Array ==> int*
Wie du siehst, ist das gar nicht so einfach und stark fehleranfällig. Wieso machst du dir das Leben dann nicht mit std::array, std::tr1::array oder std::vector einfacher?
-
out schrieb:
vip@r schrieb:
Eine Initialisierung der Form
graph1[9][9]funktioniert aber so. Warum geht das so mit Pointern nicht?
** bedeutet nicht 2d-Array. Viele Leute denken fälschlicherweise, hinter **
steckt immer ein **, das ist Unsinn....steckt immer ein 2d-Array...

-
vip@r schrieb:
Die Methoden (FUnktionen) kommen bei mir hier ja aus einer Klasse!
Klasse! Ja, dann mach doch eine Klasse draus.
struct Graph { adj[9][9]; }; void bfs(Graph& graph); Graph graph1 = {{{0,1,1,0,0,0,1,0,0}, {0,0,0,1,0,0,0,0,0}, {1,0,0,1,1,0,0,0,0}, {0,0,0,0,0,0,1,0,0}, {1,0,0,0,0,1,0,0,1}, {0,0,1,1,1,0,0,1,0}, {0,0,0,0,0,0,0,1,0}, {0,0,0,1,0,0,0,0,1}, {0,0,0,0,0,1,0,0,0}}}; bfs(graph1);
-
mit vorgefertigten Bibliotheken möchte ich an dieser STelle nicht arbeiten.
Ich hab mich nun dafür entschieden, dass ich mit der Initialisierung graph1[9][9] arbeite. Jetzt hab ich aber ein weiteres Problem: Ich hab mich nun auch dafür entschieden, dass array, also graph1 im Konstruktor deklarieren zu lassen.
Das sieht nun so aus:
class graphAlgo { private: int graph1[9][9]; int graph2[9][9]; void bfs(int **graph1); //Breitensuche void dfs(int **graph2); //Tiefensuche public: graphAlgo(); ~graphAlgo(); void breitensuche(); //Breitensuche void tiefensuche(); //Tiefensuche };//Konstruktor graphAlgo::graphAlgo() { //deklaration des gerichteten und ungewichteten Graphen graph1[9][9] = {{0,1,1,0,0,0,1,0,0}, {0,0,0,1,0,0,0,0,0}, {1,0,0,1,1,0,0,0,0}, {0,0,0,0,0,0,1,0,0}, {1,0,0,0,0,1,0,0,1}, {0,0,1,1,1,0,0,1,0}, {0,0,0,0,0,0,0,1,0}, {0,0,0,1,0,0,0,0,1}, {0,0,0,0,0,1,0,0,0}}; //deklaration des gerichteten und gewichteten Graphen graph2[9][9] = {{0,1,2,0,0,0,5,0,0}, {0,0,0,6,0,0,0,0,0}, {2,0,0,5,4,0,0,0,0}, {0,0,0,0,0,0,2,0,0}, {3,0,0,0,0,2,0,0,4}, {0,0,1,7,2,0,0,2,0}, {0,0,0,0,0,0,0,1,0}, {0,0,0,3,0,0,0,0,5}, {0,0,0,0,0,3,0,0,0}}; }Ich kann aber hier jetzt nicht auf die private Variablen graph1 und graph2 zugreifen. Muss ich diese dann publich setzen? Was muss ich machen, damit ich diese Variablen dennoch unter private deklarieren kann?
-
Zur Erklärung, warum das mit int **graph nicht so funktioniert, wie du es dir denkst:
Typsystem 102: Arrays (und der Zusammenhang mit Zeigern)
Ein Array ist ein Aggregattyp, der aus einer festen Anzahl von Objekten eines anderen Typs besteht. Diese Teilobjekte liegen im Speicher direkt hintereinander, ihre Gesamtheit ist das Array, und die Einzelobjekte sind über einen Index ansprechbar:
int arr[4] = { 3, 1, 4, 1 }; führt zu: | <------- arr--- ----> | +-----+-----+-----+-----+ | 3 | 1 | 4 | 1 | +-----+-----+-----+-----+ ^ ^ ^ ^ | | | | arr[0] | | | arr[1] | | arr[2] | arr[3]Zwei- und mehrdimensionale Arrays sind Arrays von Arrays, also:
int arr[3][2] = { { 3, 1 }, { 4, 1 }, { 5, 9 } }; führt zu: | <------------- arr -------------> | | arr[0] | arr[1] | arr[2] | +-----+-----+-----+-----+-----+-----+ | 3 | 1 | 4 | 1 | 5 | 9 | +-----+-----+-----+-----+-----+-----+ ^ ^ ^ ^ ^ ^ | | | | | | arr[0][0]| | | | | | arr[0][1] | | | | arr[1][0] | | | arr[1][1] | | arr[2][0] | arr[2][1]In diesem Fall sind arr[0], arr[1] und arr[2] jeweils vom Typ int[2]. So ist
// param ist eine Referenz auf ein int-Array der Länge 2 void foo(int (¶m)[2]) { } int main() { int arr[3][2] = { { 3, 1 }, { 4, 1 }, { 5, 9 } }; foo(arr[0]); }völlig in Ordnung. std::end(arr[0]) etc. werden ebenfalls funktionieren.
Als Besonderheit zerfallen Arrays in der Verwendung in einen Zeiger auf den Typ, den es beinhaltet. So kann ich
int arr[4] = { 3, 1, 4, 1 }; int *ptr = arr; assert(*(ptr + 2) == 4);schreiben, oder
int arr[3][2] = { { 3, 1 }, { 4, 1 }, { 5, 9 } }; int (*ptr)[2] = arr; assert((*(ptr + 2))[0] == 5 && (*(ptr + 2))[1] == 9);Dieser Zerfall geschieht übrigens auch bei
arr[2], welches als
(*(arr + 2))ausgewertet wird.
Gleichwohl ist ein Array etwas anderes als ein Zeiger, und ein Array von Arrays etwas anderes als ein Array von Zeigern. In C (und schlechtem C++) sieht man manchmal Code der Art
int **arr; arr = malloc(sizeof(int*) * x); // bzw. das selbe mit new[] for(int i = 0; i < x; ++x) { arr[i] = malloc(sizeof(int) * y); } arr[0][1] = foo(); // Später Aufräumen nicht vergessen, und Exceptionsicherheit...also besser // mit std::vector<std::vector<foo> >, wenn es denn unbedingt sein muss.Dies sieht im Speicher dann etwa so aus:
arr [0] [1] [2] [3] +---+ +---+---+---+---+ | |-------->| | | | | +---+ +---+---+---+---+ | | | | +---+---+---+ | | | +--->| 3 | 1 | 4 | | | | +---+---+---+ | | | | | | +---+---+---+ | | +------->| 1 | 5 | 9 | | | +---+---+---+ | | | | +---+---+---+ | +----------->| 2 | 6 | 5 | | +---+---+---+ | | +---+---+---+ +--------------->| 3 | 5 | 8 | +---+---+---+Hierbei ist arr vom Typ int**, und arr[0], arr[1] etc. sind int* (nicht int[3]!). Es handelt sich um ein gänzlich anderes (und komplexeres) Biest als ein einfaches zweidimensionales Array, und deshalb kann man einen Zeiger auf Zeiger nicht initialisieren wie ein mehrdimensionales Array.
-
vip@r schrieb:
mit vorgefertigten Bibliotheken möchte ich an dieser STelle nicht arbeiten.
Tust du ja auch nicht. Das ist Teil der c++ Standardbibliothek. Was nutzt du denn zur Bildschirmausgabe? Garantiert std::cout. Und wenn du das nicht nutzt, wirst du die WinAPI nutzen müssen oder etwas vergleichbares. Du kommst um Bibliotheken nicht herum; erfinde das Rad nicht unnötig neu.
Und std::vector ist was tolles. Dynamisch wachsende Arrays, die soviel Speicher haben, wie du brauchst. Kein Gefriemel (?) mehr mit new[] oder new.Das sieht nun so aus:
...Ich kann aber hier jetzt nicht auf die private Variablen graph1 und graph2 zugreifen. Muss ich diese dann publich setzen? Was muss ich machen, damit ich diese Variablen dennoch unter private deklarieren kann?
Doch kannst du.
In allen Memberfunktionen kannst du auf private Variablen zugreifen.
Und deine Aufteilung bfs(int**) und breitensuche ist auch relativ sinnfrei. Nutze gleich breitensuche und arbeite dort direkt mit dem Member.