mikrocontroller.net

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


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von zitter_ned_aso (Gast)


Bewertung
0 lesenswert
nicht 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:
 void print_mat(int rows, int cols, int mat[rows][cols]){            
      for(int i=0; i<rows; i++){                                      
          for(int j=0; j<cols; j++){                                  
              printf("%d\t", mat[i][j]);                              
          }                                                           
          puts("");                                                   
      }                                                               
 }

Aber wie geht es ohne VLA's?

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

Danke!

von nfet (Gast)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht lesenswert
ja, mit einem Zeiger funktioniert's.

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

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

Gibt es noch andere Möglichkeiten?

von Taiga Wutzzz (Gast)


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

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

von NurEinGast (Gast)


Bewertung
0 lesenswert
nicht lesenswert
VLA ?

von Dirk B. (dirkb2)


Bewertung
0 lesenswert
nicht 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)


Bewertung
-3 lesenswert
nicht 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)


Bewertung
1 lesenswert
nicht 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)


Bewertung
1 lesenswert
nicht 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)


Bewertung
1 lesenswert
nicht 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)


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

von A. S. (achs)


Bewertung
0 lesenswert
nicht lesenswert
Int *p=mat;

Und im printf statt der ganzen Array-Rechnerei:

*p++

von PittyJ (Gast)


Bewertung
0 lesenswert
nicht 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)


Bewertung
-1 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)
warning: variable length arrays are a C99 feature
int print_mat(int rows, int cols, int mat[rows][cols]){

von Dirk B. (dirkb2)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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:
void f(x,s)
  int s;
  int x[s];
{}
Aber da gabs ja noch keine VLAs, und die Notation ist glaub ich in c99 
nicht mehr erlaubt.

von Dirk B. (dirkb2)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


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

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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.