C: beliebige Matrix ausgeben, ohne VLA

Gast #6084292
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!
Gast #6084319
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?
#6084372
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.
#6084383
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.
#6084390
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.
#6086900
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)
Gast #6086939
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.
#6087075
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren