Forum: Mikrocontroller und Digitale Elektronik Feld Array Dynamisch Statisch Compiler C


von maddin (Gast)


Lesenswert?

Hallo,

ich habe unten mal ein kleines c beispiel angehängt, in dem ein 2dim. 
feld auf 2 unterschiedliche arten un weisen angelegt wird, einmal 
statisch und einmal dynamisch.

wenn ein 2dim. feld statisch angelegt wird, dann liegen die zellen ja 
alle hintereinander im speicher :

feld[2][3];

speicher:
00
01
02
10
11
12

wenn das ganze jetzt dynamisch angelegt wird, dann kann man, so wie ich 
jetzt ja, vorerst speicher für ein eind. feld voller zeiger allokieren, 
die dann jeweils auf speicher zeigen indem die eigentlichen daten 
liegen, siehe bsp.:


#define DIMX 2
#define DIMX 3

voif function(void)
{
  int  x[DIMX][DIMY];
  int  **y;
  int i;

  y=(**int)malloc(DIMX*sizeof(*int));
  for (i=0; i<DIMX; i++)
  {
    y[i] =(*int)malloc(DIMY*sizeof(int));
  }
}

meine frage, wie bekommt der kompiler die umsetzung von :

g=x[1][2];
und
g=y[1][2];

auf die reihe, da dahinter ja eigentlich zwei völlig unterschiedliche 
strukturen:


y[c][d] entspricht *(*(y+a)+b)
x[c][d] entspricht *(x + (a*DIMY) + b)

liegen hin!?

m.

von Karl H. (kbuchegg)


Lesenswert?

maddin wrote:

<Im Prinzip korrekter Source Code. Die Syntax Fehler
 ignorieren wir mal. Du solltst dir aber abgewöhnen, den
 Returnwert von malloc zu casten.>

>
> meine frage, wie bekommt der kompiler die umsetzung von :
>
> g=x[1][2];
> und
> g=y[1][2];
>
> auf die reihe, da dahinter ja eigentlich zwei völlig unterschiedliche
> strukturen:

Der Compiler weiss aber, dass
x als 2-D Array definiert wurde

> x[c][d] entspricht *(x + (a*DIMY) + b)

Ganz genau. Das kann er Compiler aber nur machen, wenn
er weiss, dass x als
   T x[][]
angelegt wurde

> y[c][d] entspricht *(*(y+a)+b)

Yep.

von Karl H. (kbuchegg)


Lesenswert?

Man kanns auch so sehen (und so wird es der Compiler auch machen)

Die Ersetzung

    c[d]   <->  *(c + d)

gilt nur bei 'einfachen' Datentypen wie int, char, Pointer, etc.

Das Datentypergebnis von
   x[c]
ist aber, in deinem Fall,  int[]. Und damit kann diese
Äquivalenz nicht benutzt werden.

von maddin (Gast)


Lesenswert?

Hallo KHB,
>> Du solltst dir aber abgewöhnen, den
 Returnwert von malloc zu casten<<

danke für den hinweis, auch wenn ich selbst in meinem "nur beispiel" 
nicht weis wo du dieses problem gefunden hast, habe ich das übersehen!?

>>Der Compiler weiss aber, dass
x als 2-D Array definiert wurde<<

das habe ich mir auch schon gedacht, compiler sind echt eine komplexe 
erfindung, ich bewundere immer wieder was alles möglich ist.

>>Ganz genau. Das kann er Compiler aber nur machen, wenn
er weiss, dass x als
   T x[][]
angelegt wurde<<

was meinst du mit T? ein struktur!?

gruß,
m.

von maddin (Gast)


Lesenswert?

Hi,
>>Man kanns auch so sehen (und so wird es der Compiler auch machen)

Die Ersetzung

    c[d]   <->  *(c + d)

gilt nur bei 'einfachen' Datentypen wie int, char, Pointer, etc.

Das Datentypergebnis von
   x[c]
ist aber, in deinem Fall,  int[]. Und damit kann diese
Äquivalenz nicht benutzt werden.<<

darüber muss ich einen moment grübeln.

m.

ps.: die sache mit dem c und d kam dadurch das ich es mit a und b hier 
nicht posten konnte da das forum der meinung war ich würde spam posten 
:-)

von Karl H. (kbuchegg)


Lesenswert?

maddin wrote:
> Hallo KHB,
>>> Du solltst dir aber abgewöhnen, den
>  Returnwert von malloc zu casten<<
>
> danke für den hinweis, auch wenn ich selbst in meinem "nur beispiel"
> nicht weis wo du dieses problem gefunden hast, habe ich das übersehen!?

zb. hier:

 y=(**int)malloc(DIMX*sizeof(*int));

(wenn wir mal von der falschen Pointer Syntax absehen)

Den Return Wert von malloc nie casten.
In C ist der cast unnötig. malloc liefert einen void* und
der ist in C zuweisungskompatibel zu allen Pointern.
Auf der anderen Seite kann dieser cast einen Fehler verstecken.
Nämlich dann, wenn kein Protoyp für malloc in Sicht ist.
Dann muss der Compiler laut C Regeln davon ausgehen, dass
malloc einen int zurückliefert. Ein int muss aber nicht
unbedingt dieselbe Größe wie ein Pointer haben. Ist der
cast nicht da, dann bemerkt das der Compiler und gibt einen
Fehler. Mit dem cast jedoch, wird das Typprüfsystem übergangen
und der Compiler akzeptiert diese Zuweisung wieder besseren Wissens.
Ein Cast ist immer eine Waffe! Man muss ihn weise und sparsam
einsetzen. Ist ein Cast unnötig, dann ist es immer besser
ihn wegzulassen.

Wenn dein Compiler aber ohne Cast meckert, dann ist das dann kein
C Compiler, sondern ein C++ Compiler. In dem Fall sollte man
aber malloc überhaupt nicht benutzen (es gibt auch Ausnahmen),
sondern stattdessen mit new arbeiten.

>
>>>Der Compiler weiss aber, dass
> x als 2-D Array definiert wurde<<
>
> das habe ich mir auch schon gedacht, compiler sind echt eine komplexe
> erfindung, ich bewundere immer wieder was alles möglich ist.
>
>>>Ganz genau. Das kann er Compiler aber nur machen, wenn
> er weiss, dass x als
>    T x[][]
> angelegt wurde<<
>
> was meinst du mit T? ein struktur!?

Ein Datentyp. T steht für die 'einfachen' Datentypen, wie
int, char, Pointer, float, double, struct ...

von Karl H. (kbuchegg)


Lesenswert?

maddin wrote:
>
> darüber muss ich einen moment grübeln.

Das ist wie in der Physik. Will man schnell abklären, ob eine
Formel grundsätzlich stimmen kann, dann vergleicht man einfach
die Einheiten.

  Bsp: Symbol   Bedeutung            Einheit
          s       Weg                m (Meter)
          t       Zeit               s (Sekunde)
          v       Geschwindigkeit    m/s
          a       Beschleunigung     m/s^2

   s = v * t

kann daher stimmen. Links steht als Einheit m. Rechts steht
als Einheit  m/s * s -> m. Auf beiden Seiten ergibt sich also
für die Einheit m

   s = v / t

kann daher nicht stimmen.
Linke Seite:   m
rechte Seite:  m/s / s -> m / s^2
Damit unterscheiden sich die linke und die rechte Seite in
den Einheiten und die Formel ist daher Quatsch

Ähnlich hier. Nur heist das nicht Einheit sondern Datentyp

  T * a;    (a ist ein Pointer auf T, T steht wieder für int,
             char, etc.)

  *a
da a ein Pointer auf T ist, ergibt *a das T selbst.
(int * b;      wenn b den Datentyp int* hat, dann hat *b den
               Datentyp int)

  T a[];

a ist ein Array von T. Ein einzelnes Element von A hat daher den
Datentyp T.

  T b[][];

b ist ein 2D Array von T. Eine Zeile des Arrays hat daher den
Typ  T[]. Ein einzelnes Element wiederrum davon hat den Typ T

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.