Forum: Compiler & IDEs pointer in struct / initialisierung / zugriff


von gert (Gast)


Lesenswert?

folgende definitionen / initalisierung:

typedef struct {
  CHAR cTest[5 + 1];
} T_TEST;

T_TEST xTestA[] = {
  {"12345"},
};

T_TEST xTestB[] = {
  {"67890"},
  {"55555"},
};

typedef struct {
  UCHAR ucKey;
  T_TEST *pTest;
} T_TEST_TBL;

T_TEST_TBL xTestTbl[] = {
  {1, (T_TEST *)&xTestA},
  {2, (T_TEST *)&xTestB}
}

wie kann ich nun zb. in einer schleife strlen von cTest aller elemente 
von xTestTbl ausgeben, dh:

KEY -> CTEST -> LEN
1 -> 12345 -> 6
2 -> 67890 -> 6
2 -> 55555 -> 6

danke

von gert (Gast)


Lesenswert?

LEN natürlich 5 ;)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

gert wrote:

> T_TEST_TBL xTestTbl[] = {
>   {1, (T_TEST *)&xTestA},
>   {2, (T_TEST *)&xTestB}
> }

Die Typecasts sind überflüssig.

> wie kann ich nun zb. in einer schleife strlen von cTest aller elemente
> von xTestTbl ausgeben, dh:

Gar nicht.  Du hast Tabellen dynamischer Größe, hast aber weder deren
Länge irgendwo festgehalten noch ein Endekennzeichen in jeder Tabelle
hinterlassen.  Damit kann man beim Blick ,,von oben'' nicht mehr
wissen, auf wie viele Tabellenelemente der jeweilige Zeiger nun wirklich
zeigt.

p.s.: Bitte Code-Markierungen benutzen.

von gert (Gast)


Lesenswert?

ok dann mit counter - typecast brauche ich, sonst schreit compiler
1
typedef struct {
2
  CHAR cTest[5 + 1];
3
} T_TEST;
4
5
T_TEST xTestA[] = {
6
  {"12345"},
7
};
8
9
T_TEST xTestB[] = {
10
  {"67890"},
11
  {"55555"},
12
};
13
14
typedef struct {
15
  UCHAR ucKey;
16
  UCHAR ucCnt;
17
  T_TEST *pTest;
18
} T_TEST_TBL;
19
20
T_TEST_TBL xTestTbl[] = {
21
  {1, sizeof(xTestA)/sizeof(T_TEST), (T_TEST *)&xTestA},
22
  {2, sizeof(xTestB)/sizeof(T_TEST), (T_TEST *)&xTestB}

von gert (Gast)


Lesenswert?

ja geht auch ohne typecast
1
T_TEST_TBL xTestTbl[] = {
2
  {1, sizeof(xTestA)/sizeof(T_TEST), xTestA},
3
  {2, sizeof(xTestB)/sizeof(T_TEST), xTestB}
4
};

von Stefan E. (sternst)


Lesenswert?

1
int i,ii;
2
3
for (i=0;i<sizeof(xTestTbl)/sizeof(T_TEST_TBL);++i)
4
  for (ii=0;ii<xTestTbl[i].ucCnt;++ii)
5
      printf ("%d -> %s -> %d\n",
6
              xTestTbl[i].ucKey,
7
              xTestTbl[i].pTest[ii].cTest,
8
              strlen(xTestTbl[i].pTest[ii].cTest));

von gert (Gast)


Lesenswert?

danke so hab ichs auch gemacht - nun habe ich den fehler gefunden:
1
T_TEST xTestA[] = {
2
  {"12345"},
3
};

wurde immer mit 0 initialisiert und nicht "12345"

habe umgeschrieben auf:
1
static const T_TEST xTestA[] = {
2
  {"12345"},
3
};

dann plötzlich wurde richtig initialisiert ???

von gert (Gast)


Lesenswert?

ist compiler/sdk spezifisch

von Oliver (Gast)


Lesenswert?

>ist compiler/sdk spezifisch

warum sollte das so sein? C ist C, das muß erst einmal jeder Compiler 
gleich verstehen.

Mich stört zwar das Komma am Ende von "{"12345"},", aber den Compiler 
anscheinend nicht. Funktionieren sollte die erste Variante auch.

Ich hab hiermit ein Problem:
1
T_TEST_TBL xTestTbl[] = {
2
{1, (T_TEST *)&xTestA},
3
{2, (T_TEST *)&xTestB}
4
}
&xTestA ist KEIN T_TEST*, sondern ein T_TEST**, deshalb hast du wohl 
auch die (eigentlich überflüssigen) Typecasts eingefügt. Gemeint ist 
wohl:
1
T_TEST_TBL xTestTbl[] = {
2
  {1, xTestA},
3
  {2, xTestB}
4
};


Oliver

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Oliver wrote:

> &xTestA ist KEIN T_TEST*, sondern ein T_TEST**

Nein, die Adresse eines Arrays ist die Adresse seines ersten Elements.

Überflüssig ist das & natürlich trotzdem, und es deutet darauf hin,
dass derjenige, der es geschrieben hat, die ganze Pointer&Array-
Geschichte noch nicht verstanden hat, sondern trial&error benutzt.

von gert (Gast)


Lesenswert?

ich habs eh ohne cast gemacht, es war nur zuerst das const drinnen und 
der compiler hat bei der initialisierung natürlich gemeckert (looses 
const qualifier)

von gert (Gast)


Lesenswert?

zur info : (T_TEST *)&xTestA == xTestA

von Simon K. (simon) Benutzerseite


Lesenswert?

gert wrote:
> looses const qualifier
Ja zu Recht! Und anstatt deinen Fehler zu beheben, benutzt du die 
Allzweckwaffe Cast um die Symptome zu vertuschen. TZTZTZ!

von gert (Gast)


Lesenswert?

das war nur für einen schnellen test...
ok &xTestA[0] == xTestA

von yalu (Gast)


Lesenswert?

>> &xTestA ist KEIN T_TEST*, sondern ein T_TEST**
>
> Nein, die Adresse eines Arrays ist die Adresse seines ersten
> Elements.

Der numerische Wert von &xTestA und xTestA ist zwar der gleiche, der
Datentyp aber ein anderer:

xTestA ist ein T_TEST-Array und somit vom Typ T_TEST[] bzw. T_TEST[1].
Es kann verwendet werden wie ein konstanter Zeiger auf das erste
Element, also wie ein T_TEST*.

&xTestA hingegen ist ein Zeiger auf ein T_TEST-Array (nicht auf das
erste Element) und somit vom Typ T_TEST(*)[] bzw. T_TEST(*)[1]. Für
diesen Datentyp gibt es im vorliegenden Programm aber keine sinnvolle
Verwendung.

von Simon K. (simon) Benutzerseite


Lesenswert?

Und damit du das const nicht weg-casten musst (was übrigens 
programmiertechnisch eine ziemliche Schweinerei ist!), musst du folgende 
Definition ändern:
1
typedef struct {
2
  UCHAR ucKey;
3
  const T_TEST *pTest; /* Zeiger auf ein konstantes T_TEST */
4
} T_TEST_TBL;

von A. N. (netbandit)


Lesenswert?

Moment mal... xTestA ist doch ein Array (T_TEST*), also steht in xTestA 
die Adresse des ersten Elementes des Arrays.

Um den Wert dieses Elementes zu ändern kann ich
*xTestA oder xTestA[0] benutzen.

Wenn ich &xTestA schreibe bekomme ich die Adresse des Zeigers, der auf 
die Adresse des ersten Elementes des Arrays zeigt.. also durchaus ein 
T_TEST**

Oder hab ich da was nicht ganz verstanden?

von yalu (Gast)


Lesenswert?

> Moment mal... xTestA ist doch ein Array

Bis hierher ist es richtig.

> (T_TEST*),

T_TEST* ist kein Array, sondern ein Zeiger. Array-Variablen können
zwar in vielen Kontexten wie Zeiger benutzt werden, trotzdem sind das
zwei unterschiedliche Dinge. So hat bspw. ein Zeiger die Größe einer
Adresse auf dem Zielsystem, die Größe eines Arrays hängt von der
Anzahl und der Größe der Elemente ab. Einer Zeigervariable kann
ein Wert zugewiesen werden, einer Arrayvariable nicht (nur deren
Elementen).

> also steht in xTestA die Adresse des ersten Elementes des Arrays.

Nein, in xTestA stehen die Arrayemelente. Erst wenn man bspw. p=xTestA
schreibt, wird xTestA durch die Adresse des ersten Elements ersetzt
und p zugewiesen.

> Um den Wert dieses Elementes zu ändern kann ich *xTestA oder
> xTestA[0] benutzen.

Richtig.

> Wenn ich &xTestA schreibe bekomme ich die Adresse des Zeigers, der
> auf die Adresse des ersten Elementes des Arrays zeigt.. also
> durchaus ein T_TEST**

Nein, das ist einer der Fälle, wo xTestA nicht durch einen Zeiger
auf das erste Elemente ersetzt wird, sondern ein Array bleibt. Somit
ist &xTestA kein Zeiger auf einen Zeiger das erste Element (T_TEST**),
sondern ein Zeiger auf das ganze Array(T_TEST(*)[] oder T_TEST(*[1]).
Wie schon oben geschrieben sind diese beiden Zeiger numerisch
natürlich gleich, trotzdem sind es aber zwei unterschiedliche
Datentypen.

> Oder hab ich da was nicht ganz verstanden?

Jetzt hoffentlich schon ;-)

von A. N. (netbandit)


Lesenswert?

Ah ja, diese Sonderrolle der statischen Arrays war mir nicht bewusst. 
Ich dachte bis jetzt immer, dass "int a[5];" dazu führt, dass ein 
konstanter Zeiger auf ein Integer mit dem Namen a angelegt wird, 5 mal 
ein Integer im Speicher reserviert wird und die Adresse des ersten 
Integers in a gespeichert wird.
Also so wie man es dynamisch machen würde, nur dass halt der Compiler 
die Arbeit erledigt.

Man lernt nie aus, danke yalu!

Ganz durchdacht finde ich die Sache dann allerdings nicht. Wenn es hier 
also eh einen eigenen Datentypen gibt und sizeof(a) sogar die komplette 
Arraygröße zurückliefert, dann hätte man doch in die Compiler auch noch 
eine Bereichsprüfung für den [] Operator einbauen können, so dass bei 
statischen Arrays eben a[5] = ... nicht mehr möglich ist.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

A. N. wrote:

> Ganz durchdacht finde ich die Sache dann allerdings nicht. Wenn es hier
> also eh einen eigenen Datentypen gibt und sizeof(a) sogar die komplette
> Arraygröße zurückliefert, dann hätte man doch in die Compiler auch noch
> eine Bereichsprüfung für den [] Operator einbauen können, so dass bei
> statischen Arrays eben a[5] = ... nicht mehr möglich ist.

C besitzt von der Sprachdefinition einfach mal kein Laufzeitsystem,
was derartige Überprüfungen hergeben könnte (anders als bspw. Pascal).
Allerdings verbietet der Standard einer Implementierung nicht, ein
derartiges Feature anzubieten.  Es wird nur in der Regel nicht gemacht,
weil es einfach Performance kostet.

von A. N. (netbandit)


Lesenswert?

Ja das zur Laufzeit ist mir schon klar, aber wenigstens bei 
offensichtlichen Bereichsüberschreitungen müsste der Compiler beim 
Compelieren meckern.
z.B.
a[5] = 1;
bei nur 5 Elementen im Array.

Aber egal, hier ging es ja um ein anderes Thema :)

von gert (Gast)


Lesenswert?

@Simon:

das mit dem const zeiger hatte ich schon hinzugefügt bei mir - danke 
trotzdem ;)
1
const T_TEST *pTest;

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.