Parse error?

Hallo,

ich muß eine C Methode zum multiplizieren von zwei 2x2 Matrizen schreiben, aber ich bekomme beim kompilieren immer einen parse error.
Ist bestimmt nur ne Kleinigkeit, aber ich komme nicht auf den Fehler.
Habe vorher nur Java programmiert…
Hier ist der Quelltext der Methode:

int[][] mult(int a[2][2], int b[2][2]){
int ergebnis[2][2];
for(int zeile=0;zeile

int[][] mult(int a[2][2], int b[2][2]){

Das int[][] kann nicht funktionieren, da in C in der definition eines Arrays zumindest die zweite Dimension spezifiziert werden muss.

Zweites Problem: Du definierst die lokale Variable ergebins und lieferst einen Zeiger darauf zurück. Das geht so nicht, da der Speicherplatz nach Verlassen der Funktion freigegeben wird. Wenn du mit Zeiger-Typen arbeiten willst, musst du entweder der Funktion ein Ergebnis-Array übergeben, oder innerhalb der Funktion ein Array dynamisch allokieren und einen Pointer auf dieses Array zurückgeben (dieser Speicher muss natürlich dann außerhalb der Funktion wieder freigegeben werden!)

Mein Vorschlag:

// Umrechnung einer Zeilen/Spalten-Adresse auf eindimensionales Array
// ts := Anzahl der Spalten
inline int rc2a( int z, int s, int ts ) {
 return z\*ts+s;
}

void mult( int\* a, int\* b, int\* ergebnis ) {
 for(int zeile=0;zeile

Wenn du C++ verwendest (nehme ich mal an, da du die Zählvariablen innerhalb des Schleifenkopfes definierst...), solltest du eventuell Vektor- und Matrixklassen schreiben, um das zu kapseln. Damit kannst du dir die Pointer-Spielereien später sparen, wenn du das Zeug benutzt.

Hallo,

ich muß eine C Methode zum multiplizieren von zwei 2x2
Matrizen schreiben, aber ich bekomme beim kompilieren immer
einen parse error.
Ist bestimmt nur ne Kleinigkeit, aber ich komme nicht auf den
Fehler.
Habe vorher nur Java programmiert…
Hier ist der Quelltext der Methode:

int[][] mult(int a[2][2], int b[2][2]){
int ergebnis[2][2];
for(int zeile=0;zeile

Hallo RBr000

ich muß eine C Methode zum multiplizieren von zwei 2x2
Matrizen schreiben, aber ich bekomme beim kompilieren immer
einen parse error.

Ist klar.

Ist bestimmt nur ne Kleinigkeit, aber ich komme nicht auf den
Fehler.

:wink:))

Wenn ein Guru einen Fortgeschrittenen testen würde,
nähme er exakt diese Fragestellung.

int[][] mult(int a[2][2], int b[2][2]){

Die Deklaration einer Funktion, die ein
Array von int[2][2] liefert, ist streng-
genommen:

 int mult(int a[2][2], int b[2][2]) [2][2]
{
}

ABER(!)

C/C++ erlaubt die Rückgabe eines Feldes ‚per value‘ nicht!
Die heiligen Weisen von C/C++ empfahlen mir seinerzeit
drei Lösungen:

  1. Einpacken des Arrays in eine ‚struct‘ (C/C++)
  2. Rückgabe des Arrays als Referenz (C++)
  3. Rückgabe eines Zeigers auf ein 2x2-Arrays (C/C++)

int ergebnis[2][2];

Das ist o.k., da Du ja vorhattest, das
Array ‚per value‘ zurückzugeben.

for(int zeile=0;zeilereturn ergebnis;

Hier ist eben das Problem. Wie gesagt, erlauben
C/C++ keine ‚per value‘-Arrayrückgabe. Ausserdem
kann man ein Array als formalen Parameter (a und b)
auch nicht ‚per value‘ an die Funktion übergeben.
der Ausdruck mult(int a[2][2], int b[2][2])
bedeutet bereits, dass die Arrays ‚per reference‘
(Also nur die Feldadressen!) übergeben werden.

Der schnellste ‚hack‘ für Deine Zwecke besteht darin,
das Ergebnis-Array als formalen Parameter aufzuführen
(und nicht als lokale Variable).

int mult(int a[2][2], int b[2][2], int ergebnis[2][2])

wie von ‚wortfuchs‘ vorgeschlagen.

Wenn Du gerne das Array per value zurückgeben
möchtest, musst Du es in eine Struktur packen:

strcut ARR2X2 {
int f[2][2];
};

und dann kannst Du sowas wie

 ARR2X2 mult(ARR2X2 a, ARR2X2 b) 
{
 ARR2X2 ergebnis;
 ...
 return ergebnis
}

machen.

Grüße

CMБ

Jetzt hab ichs verstanden! :wink:
Also ich habe das Gefühl in diesem Fall macht C, wegen den ganzen Pointer Sachen die Aufgabe nur komplizierter.
In Java würde das im Prinzip so funktionieren…
Danke für die Hilfe.

Robert

Hi,

Der Rückgabetyp deiner Funktion ist int[][], damit wird der
Compiler seine Schwierigkeiten haben. Stattdessen solltest du
besser int* zurück geben. Allerdings geht das nicht, wenn du
eine lokale Variable zurück geben willst, hier musst du mit
malloc arbeiten.

Wie wäre es mit:

 int (\*mult(int a[2][2], int b[2][2])) [2][2]
{
 static int ergebnis[2][2]; /\* Achtung! nicht reentrant \*/
 for(int zeile=0; zeileerg = mult(ma, mb);
 ...
 /\* Zugriff: \*/
 /\* (\*erg)[0][0] = ... \*/
 /\* (\*erg)[0][1] = ... \*/
 /\* (\*erg)[1][0] = ... \*/
 ...

:wink:

Grüße

CMБ

Wie wäre es mit:

int (*mult(int a[2][2], int b[2][2])) [2][2]
{
static int ergebnis[2][2]; /* Achtung! nicht reentrant */
for(int zeile=0; zeile

Vielleicht kannst du Sinn und Zweck dieses Konstrukts etwas näher erläutern:

int (*mult(int a[2][2], int b[2][2])) [2][2]

Ein „int (foo*)(int[2][2])“ dürfte so machen ja noch klar sein,
aber „void foo() [1]“ ist imho schon etwas völlig anderes.

Bin schon auf deine Erläuterung gespannt! :o)

Gruß Markus

Wenn ein Guru einen Fortgeschrittenen testen würde,
nähme er exakt diese Fragestellung.

int[][] mult(int a[2][2], int b[2][2]){

Die Deklaration einer Funktion, die ein
Array von int[2][2] liefert, ist streng-
genommen:

int mult(int a[2][2], int b[2][2]) [2][2]
{
}

Ist das so korrekt? Ich meine mich zu erinnern, dass es auch mögich war
„void foo() [0]“ du deklarieren und später dann mit dem entsprechenden Index
aufzurufen. So konnte eine Funktion mit mehreren Indizes implementiert werden.
Oder kam das erst mit C++ dazu?

[…]

und dann kannst Du sowas wie

ARR2X2 mult(ARR2X2 a, ARR2X2 b)
{
ARR2X2 ergebnis;

return ergebnis
}

machen.

Wobei diese Art der Implementierung die Performance mit Füssen tritt. Erst einmal werden die Felder per Value übergeben, das heisst einmal umkopiert, dann wird ein lokales Ergebnis errechnet, welches am Ende Der Funktion noch einmal umkopiert wird. Und die Funktion, die das Ergebnis auffängt, kopiert noch einmal.
Tipp: Anschauen, schmunzel und schnell wieder vergessen!

Gruß Markus

Hallo wortfuchs,

int (*mult(int a[2][2], int b[2][2])) [2][2]
{
static int ergebnis[2][2]; /* Achtung! nicht reentrant */
for(int zeile=0; zeile

foo() eine Funktion
foo()[1] die ein 1D-Feld der Größe 1 liefert,
void foo()[1] dessen Feldelemente ‚void‘ sind.

analog:
f(int a, int b) eine Funktion mit zwei Parametern
*f(int a, int b) die einen Zeiger
(*f(int a, int b))[2][2] auf ein 2x2 Array
int (*f(int a, int b))[2][2] vom Typ ‚int‘ liefertjetzt verstanden :wink:

Grüße

CMБ

Hi,

Die Deklaration einer Funktion, die ein
Array von int[2][2] liefert, ist streng-
genommen int mult(int a[2][2], int b[2][2]) [2][2]

Ist das so korrekt? Ich meine mich zu erinnern, dass es
auch mögich war „void foo() [0]“ zu deklarieren und später
dann mit dem entsprechenden Index aufzurufen. So konnte
eine Funktion mit mehreren Indizes implementiert werden.
Oder kam das erst mit C++ dazu?

Mit void* statt void geht das wunderbar.

 void\*(\*foo()) [0]
{
 static char \*ptr[]={
 "aleph",
 "beth",
 "gimel",
 "daleth",
 "he",
 "vav"
 };
 return (void \*\*)&ptr;
}

 void main()
{
 printf("%s\n", (\*foo())[0]);
 printf("%s\n", (\*foo())[1]);
 printf("%s\n", (\*foo())[2]);
 /\*...\*/
}

Mit char* void* sparst Du Dir eine
Indirektion (ein * weniger überall).

und dann kannst Du sowas wie
ARR2X2 mult(ARR2X2 a, ARR2X2 b)
{
ARR2X2 ergebnis;

return ergebnis
}
machen.

Wobei diese Art der Implementierung die Performance mit Füssen
tritt. Erst einmal werden die Felder per Value übergeben, das
heisst einmal umkopiert, dann wird ein lokales Ergebnis
errechnet, welches am Ende Der Funktion noch einmal umkopiert
wird. Und die Funktion, die das Ergebnis auffängt, kopiert
noch einmal.

Das ist egal. Ein double-Array 2x2 hat 4*64 = 256 Byte, das ist
4 x eine L1-‚cacheline‘ beim Athlon, das trashed den L1 also kaum
und bleibt mit den anderen Arrays dort liegen, bis die Berech-
nungen durch sind. Insgesamt haben wir einen „Kopierbedarf“
von 4 x 256 Bytes. Das ist nichts gegen die Frage „Klarheit
vs. Effizienz“.

Tipp: Anschauen, schmunzel und schnell wieder vergessen!

Bei einem 2x2-Array halte ich die(se) Kopiererei für vollkommen
legitim, sofern es sich nicht um zeitkritischen Code handelt.

Grüße

CMБ

OK, mal der Reihe nach.

foo() eine Funktion
foo()[1] die ein 1D-Feld der Größe 1 liefert,
void foo()[1] dessen Feldelemente ‚void‘ sind.

Ok, aber C++ kann keine Arrays ganzer Typen, also int[3], zurück geben, sondern nur einen Zeiger vom Typ Array of …

Richtig?

> analog:  
> f(int a, int b) eine Funktion mit zwei  
> Parametern  
> \*f(int a, int b) die einen Zeiger  
> (\*f(int a, int b))[2][2] auf ein 2x2 Array  
> int (\*f(int a, int b))[2][2] vom Typ 'int'  
> liefert

jetzt verstanden :wink:

Das mit den Zeigern ist mir jetzt klar, glasklar sozusagen :o)

Danke, Markus