Forum: Mikrocontroller und Digitale Elektronik memcpy Zweidimensionales Array -> Eindimensionales Array


von Alois N. (alois)


Lesenswert?

Hi,

ich habe ein Problem mit memcpy und Array's un komme so nicht weiter.

Ich wollte folgende schreibweise (die funktioniert) vereinfachen:
1
struct ssetup
2
{  
3
  unsigned char nSensors;
4
  unsigned char tSensorsIDs[8][8];    
5
};
1
unsigned char tempID[8];
2
  
3
// erste ID ins RAM holen
4
tempID[0] = setup.tSensorsIDs[i][0];
5
tempID[1] = setup.tSensorsIDs[i][1];
6
tempID[2] = setup.tSensorsIDs[i][2];
7
tempID[3] = setup.tSensorsIDs[i][3];
8
tempID[4] = setup.tSensorsIDs[i][4];
9
tempID[5] = setup.tSensorsIDs[i][5];
10
tempID[6] = setup.tSensorsIDs[i][6];
11
tempID[7] = setup.tSensorsIDs[i][7];

Und hier mein Versuch mit memcopy der den unteren Programmteil ersetzen 
sollte. Klappt nur leider nicht:
1
unsigned char tempID[8];
2
  
3
// erste ID ins RAM holen
4
memcpy(tempID[0], setup.tSensorsIDs[i][0], sizeof(8));

Für eure Lösungsvorschläge wäre ich euch sehr dankbar.

Gruss Alois ;)

von Klaus W. (mfgkw)


Lesenswert?

Alois Neumann schrieb:
> Klappt nur leider nicht:

tja, die übliche aussagekräftige Fehlerbeschreibung...

Vielleicht klappt es so besser:
1
// erste ID ins RAM holen
2
memcpy( &tempID[0], &setup.tSensorsIDs[i][0], 8*sizeof(setup.tSensorsIDs[i][0]));

An memcpy müssen 2 Adressen übergeben werden (wohin? woher?), nicht die 
Werte der Feldelemente - daher die &.

sizeof(8) ist auch ziemlich sinnlos, weil es dir die Größe einer int 
liefert (die Speichergröße der Zahl 8, sizeof(42) wäre gleichwertig).
Stattdessen willstu doch 8*(ein Feldelement) kopieren - deshalb 
8*sizeof(setup.tSensorsIDs[i][0]). Ebensogut würde 8*sizeof(unsigned 
char) funktionieren.

von user (Gast)


Lesenswert?

sizeof(8) gibt nur die größe von 8 an also integer -> 4 -> also nicht 
richtig

richtig wäre:

memcpy(tempID, setup.tSensorsIDs[i], sizeof(tempID));

von Alois N. (alois)


Lesenswert?

Klaus, erstmal vielen Dank für die schnelle Hilfe.

Deine Version funktioniert. Das mit den Pointern hatte ich auch schon 
probiert. Der Knackpunkt war die Übergabe der Grösse.

Was ich immer noch nicht verstehe. tempID[8] ist doch 8Bytes gross, 
oder?
Werden jetzt mit memcpy nur 8 Bytes kopiert, oder 64Bytes?

Gruss Alois

von Klaus W. (mfgkw)


Lesenswert?

Alois Neumann schrieb:
> Deine Version funktioniert. Das mit den Pointern hatte ich auch schon
> probiert.

Die Version von user ist ebenso korrekt.

Alois Neumann schrieb:
> Was ich immer noch nicht verstehe. tempID[8] ist doch 8Bytes gross,
> oder?
> Werden jetzt mit memcpy nur 8 Bytes kopiert, oder 64Bytes?

tempID[8] kann zweierlei sein...

1.
1
unsigned char  tempID[8];

definiert ein Feld mit 8 Elementen.

2.
Nachdem das Feld schon existiert, ist tempID[8] ein Element, nämlich das 
achte nach Feldbeginn (und damit das erste hinter dem Feld):
1
   tempID[8] = 42; // falsch, da hinter Feld!
Hier ist ein Element des Feldes gemeint, wenn auch ein verbotenes, da 
nur [0] bis [7] im Feld liegen.
sizeof(tempID[8]) ist die Größe eines solchen Elements, also 1 (weil ein 
Feldelement vom Typ unsigned char ist und damit 1 Byte groß).

Bei sizeof ist es nicht schädlich, wenn man ein Element außerhalb des 
Feldes angibt statt innnerhalb. Schließlich geht es nur um die Größe 
eines Objekts im Speichers, also um seinen Typ. Wirklich darauf 
zugegriffen wird bei sizeof nicht.

Also: sizeof(tempID[8]) ist hier 1, sizeof(tempID) und 
8*sizeof(tempID[8]) wären 8.

von Alois N. (alois)


Lesenswert?

Hallo Klaus,

ja jetzt wird es klarer. Ich denke ich hab's kapiert.
Danke für die ausführlichen Erklärungen.
Und ja, beide Lösungen funktionieren. Ich hab's getestet.

Gruss Alois ;)

von Daniel Held (Gast)


Lesenswert?

Hallo Forum,
ich bekomme die Warnmeldung:
"..warning: implicit declaration of function 'memcpy'
..warning: incompatible implicit declaration of built-in function 
'memcpy'"

obwohl das Programm funktioniert. Die Meldung wird beim kopieren vom 
eindimensionalen Array in das zweidimensionale Array geworfen.
Wo liegt mein Fehler???

Deklaration:
1
char DisplayBuf[2][16]; // the Display Buffer
2
char TransferBuf[16]; // the Transfer Buffer

hier tritt die Warnung auf:
1
memcpy(&DisplayBuf[i], &TransferBuf, sizeof(TransferBuf));

Transfer Buffer wird gefüllt:
1
sprintf(TransferBuf, "Menu %2d, %2d, %2d", StartPos, CoursorPos, Test->ID);

Danke vorab für Eure Hilfe.

von Klaus W. (mfgkw)


Lesenswert?

Daniel Held schrieb:
> Wo liegt mein Fehler???

1. Fehler: du kaperst einen Thread, der mit deinem Problem nichts zu tun 
hat. Oder seid ihr in der gleichen Klasse und müsst dieselbe Aufgabe 
lösen?

2. Fehler: Du lieferst nicht genügend Info (wo und wie ist bei dir 
memcpy deklariert?). Wo ist der Quelltext? Wahrscheinlich fehlt einfach 
das passende #include.

von Daniel Held (Gast)


Lesenswert?

Hallo Klaus,

kapern wollte ich den Thread nicht, ich dachte das es zum Thema passt.
Gleiche Klasse? Nein, nicht das ich das wüßte.

memcpy wird in der Standard "string.h" deklariert:
1
extern void *memcpy(void *, const void *, size_t);
...und das war auch gleich das Problem, ich dachte eher an die 
pgmspace.h - war aber ein Lesefehler.

Danke trotzdem.

von Klaus W. (mfgkw)


Lesenswert?

Nur zur Sicherheit: die 2 in %2d bewirkt eine Mindestlänge der Ausgabe, 
keine Maximallänge.

D.h. wenn die ausgegebenen Werte zu groß sind (>=100, oder z.B. -10), 
reicht dein Puffer nicht.

von Karl H. (kbuchegg)


Lesenswert?

Daniel Held schrieb:

> memcpy wird in der Standard "string.h" deklariert:
>
1
> extern void *memcpy(void *, const void *, size_t);
2
>
> ...und das war auch gleich das Problem, ich dachte eher an die
> pgmspace.h - war aber ein Lesefehler.

Also ich hätt da ja eher an memory.h gedacht.

string.h      alle str... Funktionen zur Manipulation von Strings
memory.h      alle mem... Funktionen zur Manipulation von Bytefeldern
pgmspace.h    alle pgm... Funktionen zur Manipulation vom Flash


(und ja. memcpy kommt auch in string.h vor)

von Klaus W. (mfgkw)


Lesenswert?

Alle String- und mem*-Funktionen sind im C-Standard m.W. in string.h.
Daß das je nach Implementation in einer memory.h stehen kann und die von 
string.h #includet wird, kann sein. Aber string.h ist die korrekte 
Datei, wenn man memcpy nehmen will.
(HAbe eben auf meinem Linux nachgesehen: dort includet memory.h die 
string.h...)
Die pgmspace-Dinger sind ja eh kein Standard.

von Karl H. (kbuchegg)


Lesenswert?

Klaus Wachtler schrieb:
> Alle String- und mem*-Funktionen sind im C-Standard m.W. in string.h.
> Daß das je nach Implementation in einer memory.h stehen kann

Tatsächlich.
Im C-Standard gibt es keine memory.h

Wieder was gelernt.

von Daniel Held (Gast)


Lesenswert?

Danke Euch.
@Klaus: die "%2d" ist bekannt, die Ausgabe diente nur zu debug Zwecken.

@Kardl-Heinz: selbst in der pgmspace.h gibt es eine Form von memcpy - 
das war der Fehler :-)

von Daniel Held (Gast)


Lesenswert?

@Karl-Heinz: sorry für den Typo

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.