1Dim-Array -> 2Dim-Array
-
Hi,
ich grüble jetzt gefühlte Stunden an einer Sache, die eigentlich kein großes Problem sein sollte.Im Hauptprogramm hab ich ein
unsigned char *pixelarray =(unsigned char*) malloc(großezahl));
also ein Pointer, der auf ein 1Dim-unsigned-char-Array im Heap zeigt, wenn mich nicht alles täuscht.
Dann brauch ich diesen Inhalt des Arrays (das wurde befüllt) in einer Funktion und zwar als 2Dim-Array. (Also ich will es dort so benutzen können array[x][y].)
Die Indexlängen werden mit übergeben.Was ich schon versucht hab ist:
Aufruf:funktion(höhe,breite,pixelarray);
Definition:
void funktion(int höhe, int breite, array[höhe][breite]){}
Das würde glaube ich sogar klappen, aber nur wenn man beim Aufruf Werte für höhe,breite reinsetzt, die defines sind.
Sonst kommt dieser Spruch: array bound is not an integer constant before �]� tokenAber wie geht das sonst?
-
void funktion(int h, int b, unsigned char** pxarray)
sollte es tun.
-
void funktion(int h, int b, unsigned char** pxarray)
Wenn ich das mache, schreibt er dass ein unsigned char* nicht in ein unsigned char** gewandelt werden kann.
Ich spare mir jetzt die Übergabe und machunsigned char *pxarray
global.
Das Problem ist aber immer noch wie ich es schaffe einen Pointer auf ein zweidimensionales Array zu Erstellen und ihm die Adresse aus pxarray zu geben.
Ich habs schon so versuchtunsigned char (*test)[width]; test=pxarray;
und auch so
unsigned char (*test)[height][width]; test=pxarray;
aber der schreibt immer dass die Typen nicht umgewandelt werden können.
Das einzige was funktioniert ist ein 1Dim-Array aus Pointern zu erstellen und die alle mit einer Schleife durchzugehen und jedem Feld den passenden Pointer zu geben. Allerdings ist das eine ganz schlechte Lösung, weil man so sehr viel Platz verbraucht. Ich hatte gehofft, dass man einfach einen Pointer vom Typ eines 2Dim-char-Arrays machen könnte und ihn auf das 1Dim-Array zeigen lässt.
unsigned char *test[height]; //braucht height*4byte Speicherplatz!!! int i=0; for(i;i<height;i++){ test[i]=&pxarray[i*width]; }
-
Dieser Thread wurde von Moderator/in rüdiger aus dem Forum Rund um die Programmierung in das Forum C (C89 und C99) verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.
-
Man kann Arrays durchaus so punnen. In C99 ist es auch mit variablen Grenzen kein Problem; dort ist
void funktion(size_t hoehe, size_t breite, unsigned char array[][breite]) {}
genau richtig. Deine Fehlermeldung sieht nach gcc aus, dem musst du dafür den Schalter -std=c99 mitgeben.
Wenn du auf C90 festgelegt bist (etwa, wenn MSVC eine Zielplattform ist), stehen Arrays mit variabler Länge nicht zur Verfügung. In diesem Fall musst du die Adressierung von Hand vornehmen, etwa
void funktion(size_t hoehe, size_t breite, unsigned char array[]) { ... array[i * breite + j]; /* statt array[i][j] */ }
-
#define _X 123 #define _Y 456 unsigned char array1dim[_X]; unsigned char (*zeigeraufarray1dim)[_X]=&array1dim; unsigned char array2dim[_Y][_X]; unsigned char (*zeigeraufarray2dim)[_Y][_X]=&array2dim;
Was ist daran so schwierig?
Du warst schon kurz davor.
-
Wutz schrieb:
#define _X 123 #define _Y 456
Bezeichner dieser Form sind vom Standard für die Implementation reserviert. Dein Code erzeugt dementsprechend undefiniertes Verhalten.
Der Rest geht herrlich am Problem vorbei, was einer gewissen tragischen Ironie nicht entbehrt, wenn man darunter "Was ist daran so schwierig?" schreibt. Du nimmst lediglich Zeiger auf Arrays, so dass man in Zukunft eine Dereferenzierung mehr braucht:
array2dim[i][j]; /* entspricht */ (*zeigeraufarray2dim)[i][j];
Worum es hier geht, ist aber type punning. Er hat ein flaches Array und will es als zweidimensionales interpretieren, d.h. beispielsweise
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int (*matrix)[3] = (int(*)[3]) array; /* Cast nur zur Unterdrückung der hier üblichen Compilerwarnungen */ /* matrix ist jetzt { { 1, 2, 3 }, * { 4, 5, 6 }, * { 7, 8, 9 } } */
Du warst also zumindest schon kurz davor. Das Problem ist jetzt, dass die Dimensionen nicht zur Compilezeit feststehen - wenn ich das richtig lese, geht es um Bilddaten in Bitmap-Form, und die kommen halt in allen möglichen Größen. In C99 ist das unproblematisch, in C90 gibt es aber noch keine Arrays variabler Länge, weswegen man da die Dereferenzierung von Hand vornehmen (oder sich mit Zeigerarrays herumschlagen) muss.
-
Hallo,
erstmal schonmal vielen Dank für die drei Antworten.
Mit defines konnte ich es leider gar nicht machen (obwohl das anscheinend von der Syntax her wohl funktionieren würde), da es bei meinem Programm wirklich um bitmaps geht und die Größe variabel sein muss.
Mein Compiler ist gcc (also hab netbeans und mingw installiert).
Ob ich jetzt C99 oder ein anderes benutzen sollte weiß ich gar nicht so genau. Das ganze ist eine Schulaufgabe und der Lehrer drückt sich nicht so ganz klar aus. Einerseits müssen wir zwangsläufig mit dynamisch erzeugten Arrays arbeiten (also malloc und dann pointer drauf), andererseits dürfen wir trotzdem nicht for(int i=0... machen und bei mir wird auch überall das include<iostream> mit den ganzen cout und so rot unterstrichen. Obwohl das optisch nach fatal-error aussieht compiliert ders aber trotzdem.Meine erste Idee war auch erst das überall als 1Dim-Array zu benutzen und den Spaltenindex zu berechnen und zu addieren. Also [y*width+x] aber dann wurde mir gesagt dass das total inakzeptabel sei und ich auf jeden Fall ein 2Dim-Array benutzen sollte.Ich bin froh, dass der Lehrer so drauf bestanden hat, denn jetzt ist das ganze Programm wirklich viel verständlicher und auch kürzer geworden.
Gestern hab ich mir das provisorisch so hingebaut dass das 1Dim-Array übergeben wird, ich in der funktion dann ein neues Pointerarray erzeuge und dem mit einer Schleife die Adressen der 1Dim-Array-Felder gebe. Das kostete aber zuviel Speicher und sah so aus:RGBTRIPLE *pixel24array = NULL;//global RGBTRIPLE *abc[height];//in funktion for(i;i<height;i++){ abc[i]=&pixel24array[i*width]; }
Das 1Dim-Array ist bei mir inzwischen global; ist ja auch egal und man spart sich die Übergabe. Außerdem wird so (denke ich) auch der Pointer auf dem Heap abgelegt und nicht auf dem Stack. (es soll bei uns immer alles auf den Heap)
Was eben auf anhieb funktioniert und mir damit jetzt wirklich weitergeholfen hat ist
RGBTRIPLE (*abc)[width]=(RGBTRIPLE(*)[width]) pixel24array;
Das ist genau was ich gesucht hab und wo ich, wenn ich es mir jetzt so angucke, auch nie drauf gekommen wäre, weil ich soeine Syntax mit () noch nie gesehen hab.
Dass ich am Anfang einen Pointer vom Typ eines 1Dim-RGBTRIPLE-Arrays brauche war mir ja klar. Mir hat nur der richtige cast gefehlt.
Wie genau und wo benutzt man dieses () eigentlich? Vielen Dank schonmal;)
-
Die Klammern um (*) sind der Operator-Präzedenz geschuldet. [] bindet stärker als *, d.h.
int *foo[10];
deklariert ein Array von zehn Zeigern auf int. Dagegen ist
int (*foo)[10];
ein Zeiger auf ein Array von 10 Integern - die Klammern bedeuten, dass der *-Operator fester an foo gebunden wird als [10]. In vergleichbarer Weise definiert man Funktionszeiger, so ist
int *foo(void);
eine Funktion, die einen Zeiger auf int zurückgibt, und
int (*foo)(void);
ist ein Zeiger auf eine Funktion, die int zurückgibt. Mir ist bewusst, dass diese Syntax verwirrend aussieht, wenn man nicht an den Umgang damit gewöhnt ist.
In komplexeren Zusammenhängen empfiehlt sich die Verwendung von typedef. Beispielsweise ist die Signatur der signal-Funktion aus der Standardbibliothek sehr unübersichtlich:
void (*signal(int signum, void (*handler)(int)))(int);
Dagegen ist es mit typedef lesbarer:
typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler);
Was den Rest angeht, wenn ihr for(int i=0... nicht benutzen dürft, seid ihr wohl auf C90 festgelegt - C99 kennt diese Syntax. #include <iostream> und alles was daraus kommt dagegen ist kein C, sondern C++. Das sollte gcc aber auch nur mit dem C++-Frontend fressen.
Globale Variablen würde ich mir an deiner Stelle gar nicht erst angewöhnen - du bekommst damit spätestens dann große Probleme, wenn du Multithreading betreibst, und dein Code wird weniger flexibel und unübersichtlicher - wenn du eine globale Variable benutzt, nimmst du dir die Möglichkeit, mehrere Bilder gleichzeitig zu verarbeiten, und wenn du mal eine etwas längere Funktionskaskade hast, suchst du dich beim Debuggen an der falschen Stelle dumm und dämlich. Gegen globale Konstanten ist nichts zu sagen, aber globale Variablen bringen dich früher oder später in Teufels Küche.
-
Folgender Zusammenhang könnte dir vielleicht auch weiterhelfen:
array2d[x][y] <--> array1d[breite * y + x]