Forum: PC-Programmierung C: beliebige Matrix ausgeben, ohne VLA


von zitter_ned_aso (Gast)


Lesenswert?

Hallo und frohe Weihnachten!


Was macht man, wenn man eine Funktion braucht, die z.B. eine Matrix 
ausgeben soll und diese Matrix kann verschiedene Dimensionen haben (3x4, 
4x3, ....).

Ich kann ja mit VLA's sowas schreiben:
1
 void print_mat(int rows, int cols, int mat[rows][cols]){            
2
      for(int i=0; i<rows; i++){                                      
3
          for(int j=0; j<cols; j++){                                  
4
              printf("%d\t", mat[i][j]);                              
5
          }                                                           
6
          puts("");                                                   
7
      }                                                               
8
 }

Aber wie geht es ohne VLA's?

Auch bei einem Zeiger muss man ja die Spaltenzahl gleich mitangeben
1
int (*p_mat)[42] = mat_2D;
Und wenn die Anzahl der Spalten variabel ist?

Danke!

von nfet (Gast)


Lesenswert?

Was hinter dem Zeiger steht bestimmst du? Nimm einen void pointer und 
interpretierte ihn einfach als 2D array? Das dürfte der klassische 
Ansatz sein.

von zitter_ned_aso (Gast)


Lesenswert?

ja, mit einem Zeiger funktioniert's.

ich behandle die Matrix wie ein Array ;-)
1
void print_mat(int *mat, int rows, int cols) {                      
2
   for (int i = 0; i < rows; i++) {                                  
3
       for (int j = 0; j < cols; j++) {                                
4
           printf("%d\t", *((mat + i * cols) + j));                      
5
       }                                                               
6
           puts("");                                                       
7
    }                                                                 
8
 }

und dann der Aufruf mit
1
print_mat( &mat[0][0], r,c);

Gibt es noch andere Möglichkeiten?

von Taiga Wutzzz (Gast)


Lesenswert?

> print_mat( &mat[0][0], r,c);

print_mat(mat[0], r,c);

von NurEinGast (Gast)


Lesenswert?

VLA ?

von Dirk B. (dirkb2)


Lesenswert?

In deinem Beispiel benutzt du nur Zeiger auf VLA (variable length array)
Das ist ok, da dort ja kein Speicher verbraucht wird.

Dort macht der Compiler die Berechnung für dich, die du beim zweiten 
Beispiel mühsam schreiben musstest.

Eine andere Möglichkeit wäre noch ein Pointer-Array auf die 
Zeilen-Arrays

Das ganze noch in einer struct verpackt, in der noch die Dimensionen 
stehen.

Den Speicher für die Matrix kannst du per malloc besorgen, egal ob als 
ein Block oder als Pointer-Array.

von Taiga Wutzzz (Gast)


Lesenswert?

> VLA ?

Das ist von den Linuxkommunisten erfundenes Teufelswerk, dass jeder
aufrechte, in der Tradition von K&R stehende C-Programmierer meiden
sollte wie der Vampir das Sonnenlicht.

von Wilhelm M. (wimalopaan)


Lesenswert?

Der Array-Bezeichner zerfällt (fast immer) als Argument einer Funktion 
zu einem Zeiger und als Wert dem Zeiger auf das erste Element. Damit ist 
die Dimension weg, und man hat nur einen Zeiger. Das es nun in C keine 
templates gibt, bleibt dir nur, für entsprechende (dyn.) Arrays ein 
C-sturct zu schreiben mit dem Pointer und  Dimensionen darin. Falls das 
typsicher sein, brauchst Du dann eben für N-Elementtypen und 
M-Dimensionen N*M unterschiedlicher Strukturen.

von Taiga Wutzzz (Gast)


Lesenswert?

Eine lineare Liste mit Pointern auf das Array und die Dimensioen
und einem Nullpointer wenn Ende erspart Templates alle mal.
Was soll daran nicht typsicher sein?

von Wilhelm M. (wimalopaan)


Lesenswert?

Egal ob Du nun mit zwei Iteratoren oder einem Iterator und Anzahl 
arbeitest. Um auf den cast zu void* zu verzichten, brauchst Du eben dann 
die unterschiedlichen Strukturen (konkret, nicht generisch). Für einen 
Pointer nach void* muss Du den Rückcast einbauen, der muss vom User-Code 
zur Laufzeit (also ohne Compiler-Check) gemacht werden. Deswegen 
typunsicher.

von Wilhelm M. (wimalopaan)


Lesenswert?

BTW: ab C99 geht auch bounds-cheking im callee:
1
void f(double a[static 10])

von A. S. (Gast)


Lesenswert?

Int *p=mat;

Und im printf statt der ganzen Array-Rechnerei:

*p++

von PittyJ (Gast)


Lesenswert?

Für solche Probleme wurde die C++ Erweiterung entwickelt.
Klassen für Matrizen sind möglich, in std:: gibt es bestimmt etwas, 
etc...

von Oliver S. (oliverso)


Lesenswert?

zitter_ned_aso schrieb:
> Ich kann ja mit VLA's sowas schreiben:
>  void print_mat(int rows, int cols, int mat[rows][cols]){

Das hat mit VLA nix zu tun. Seit Anbeginn der Zeitrechnung „zerfällt“ 
ein Array als Funktionsargument in einen Zeiger, und genau ja das 
passiert da auch. Daher musst du ja auch die Arraydimensionen zusätzlich 
mitgegeben.

Oliver

von mh (Gast)


Lesenswert?

Oliver S. schrieb:
> Das hat mit VLA nix zu tun.

Doch es ist ein VLA. Guck dir an, wie mat benutzt wird.

Damit du es auch glaubst, zitiere ich clang (als C++ compiliert)
1
warning: variable length arrays are a C99 feature
2
int print_mat(int rows, int cols, int mat[rows][cols]){

von Dirk B. (dirkb2)


Lesenswert?

Oliver S. schrieb:
> zitter_ned_aso schrieb:
>> Ich kann ja mit VLA's sowas schreiben:
>>  void print_mat(int rows, int cols, int mat[rows][cols]){
>
> Das hat mit VLA nix zu tun. Seit Anbeginn der Zeitrechnung „zerfällt“
> ein Array als Funktionsargument in einen Zeiger, und genau ja das
> passiert da auch. Daher musst du ja auch die Arraydimensionen zusätzlich
> mitgegeben.
>
> Oliver

Aber ohne VLA ist die Angabe der Dimension als Variable nicht möglich 
(bei der Definition von mat)

von DPA (Gast)


Lesenswert?

Ich hab schon länger ein Dilemma mit den VLAs als Funktionsparameter. 
Ich geb immer gerne mit, welcher Parameter die Grösse angibt, aber bei 
vielen Funktionen ist die per konvention leider nach dem pointer. "void 
f(int x[s], int s)" geht aber wohl nicht. Zu K&R Zeiten wäre das 
vermutlich noch kein Problem gewesen:
1
void f(x,s)
2
  int s;
3
  int x[s];
4
{}
Aber da gabs ja noch keine VLAs, und die Notation ist glaub ich in c99 
nicht mehr erlaubt.

von Dirk B. (dirkb2)


Lesenswert?

DPA schrieb:
> Ich geb immer gerne mit, welcher Parameter die Grösse angibt,

so soll es sein (zumindest, wenn schreibend auf das Array zugegriffen 
wird)

> aber bei
> vielen Funktionen ist die per konvention leider nach dem pointer. "void
> f(int x[s], int s)" geht aber wohl nicht.

Bei 1D-Arrays ist das auch egal (es wird ja nicht zur Laufzeit auf 
Überlauf geprüft). x ist ein int*.

Bei 2D-(und mehr)-Arrays macht es aber den Zugriff übersichtlicher, da 
die Indexberechnung vom Compiler versteckt wird.

Manche Funktionen wollen halt kompatibel zu C89 bleiben, zumal VLA ab 
C11 auch wieder optional sind.

Deine Funktionen kannst du schreiben wie du willst.

von zitter_ned_aso (Gast)


Lesenswert?

aber anscheinend wollen sie die Reihenfolge doch irgendwie "festlegen".

"In particular, the order of parameters in function declarations should 
be arranged such that the size of an array appears before the array."

https://en.wikipedia.org/wiki/C2x

von zitter_ned_aso (Gast)


Lesenswert?

A. S. schrieb:
> Und im printf statt der ganzen Array-Rechnerei:
>
> *p++

Ja, das ist besser als meine unnötige Rechnerei ;-) Danke!

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.