Char Array in einzelne Variable

Gast #3917817
Lesenswert?

char und char* sind 2 dinge.
char ist ein 8-bit wert, char* ist ein pointer (eine Adresse im 
Speicher) ab der mehrere chars zu finden sind (ein String).
Was du offenbar verwenden möchtest ist ein Pointer auf einen String 
(char*).
Und da hat dir Mark Brandis verraten, wie man diesen definiert:
char *test="987654";

"test" enhält dann also die Adresse vom ersten Byte ("9") von "987654".
Gast #3917908
Lesenswert?

Wenn die Daten als Array vorhanden sind, und du die Hash Funktion 
aufrufen sollst, indem du ihr dieses Array übergibst, dann geht das ganz 
einfach so:
1
unsigned long meineHashFunktion(char* arg) {
2
   ...
3
};
4

5
char buffer[100];
6

7
meineHashFunktion(buffer);

Denn buffer kann wahlweise als array von chars oder als pointer auf 
chars verwendet werden. Die Hash Funktion könnte auch beide Varianten 
als Argument erwarten - letztendlich ist es das Selbe.

Die folgende Code-Fragmente sinnd alle syntaktisch korrekt:
1
void meineHashFunktion(char* buffer) {
2
  while (*buffer != 0) {
3
     char zeichen=*buffer;
4
     // mach was mit dem zeichen
5
     buffer++;
6
  }
7
}
8

9
void meineHashFunktion(char[] buffer) {
10
  int i=0;
11
  while (buffer[i] != 0) {
12
     char zeichen=buffer[i];
13
     // mach was mit dem zeichen
14
     i++;
15
  }
16
}
17

18
void meineHashFunktion(char[] buffer) {
19
  while (*buffer != 0) {
20
     char zeichen=*buffer;
21
     // mach was mit dem zeichen
22
     buffer++;
23
  }
24
}
25

26
void meineHashFunktion(char* buffer) {
27
  int i=0;
28
  while (buffer[i] != 0) {
29
     char zeichen=buffer[i];
30
     // mach was mit dem zeichen
31
     i++;
32
  }
33
}

Wobei die unteren beiden Beispiele natürlich nicht sehr elegant sind.

Die Array Syntax (zeichen=buffer[i]) hat in der Wiederholschleife einen 
Vorteil: Sie weiß wie groß die Elemente des Arrays sind und verrechnet 
den Zeiger korrekt mit dem Index.

Die Pointer Syntax (buffer++) geht stillschweigend davon aus, dass ein 
char ein byte groß ist und dass der Zeiger beim Incrementieren auf das 
nächste Byte Zeigt. Das sind gleich zwei Annahmen, die bei 
ungewöhnlicher Hardwarearchitektur nicht zutreffen könnten.

Es könnte z.B. sein, dass der Speicher 32 Bit breit ist. Dann ergeben 
sich mehrere Möglichkeiten:

a) Eine Speicherzelle kann 4 Zeichen speichern. Wenn das so genutzt 
wird, dann würde das Incrementieren des Zeigers nicht zum nächsten 
zeichen führen, sondern drei zeichen überspringen.

b) Man könnte aber auch einfach nur 8 von den 32 Bit nutzen, dann klappt 
das Incrementieren wieder.

c) Oder der Pointer zeigt beim Incrementieren gar nicht auf die nächste 
Reihe von 32 Bits, sondern bleibt in der gleichen Reihe und zeigt an, 
dass nun das zweite Bytes der Reihe gemeint ist. (Ich glaub' so läuft 
das auf PC's).

d) Und was, wenn ein char gar nicht 8 bit Groß ist? Chinesen könnten 16 
bit bevorzugen, selbst auf einem 8 bit Mikrocontroller. Dann müsste man 
den Pointer doppelt incrementieren.

Da stellt sich mir die Frage, wie eigentlich mein Laptop Zeichen 
speichert. Viele Bits hat ein zeichen wirklich im Speicher, und hängt 
das vielleicht sogar von der Programmiersprache ab?

Fragen über Fragen. Besser nutzt man die Array Syntax (zumindest 
innerhalb der Widerholschleifen), um Zeichenketten abzuarbeiten.
#3917952
Lesenswert?

Stefan us schrieb:
> Die Pointer Syntax (buffer++) geht stillschweigend davon aus, dass ein
> char ein byte groß ist und dass der Zeiger beim Incrementieren auf das
> nächste Byte Zeigt. Das sind gleich zwei Annahmen, die bei
> ungewöhnlicher Hardwarearchitektur nicht zutreffen könnten.

So ein quatsch!

Auch in der Pointersyntax weiss der Compiler, wie gross ein char ist und 
ändert den Zeiger so dass er auf das nächste char zeigt.
Gast #3918712
Lesenswert?

> Auch in der Pointersyntax weiss der Compiler, wie
> gross ein char ist und ändert den Zeiger so dass er
> auf das nächste char zeigt.

Ich weiss, das das bei allen mir bekannten Mikrocontrollern und auch 
beim PC der Fall ist.

Aber ist dieses verhalten auch wirklich standarisiert? Gilt es wirklich 
für jeden denkbaren Computer? Was passiert, wenn ein zeichen kleiner 
ist, als die kleinstmögliche Schrittweite der Pointer-Erhöhung (z.B. 
wenn das zeichen 8bit ist, die Speicherzellen jedoch 16bit)?
#3918716
Lesenswert?

Stefan us schrieb:
>> Auch in der Pointersyntax weiss der Compiler, wie
>> gross ein char ist und ändert den Zeiger so dass er
>> auf das nächste char zeigt.
>
> Ich weiss, das das bei allen mir bekannten Mikrocontrollern und auch
> beim PC der Fall ist.
>
> Aber ist dieses verhalten auch wirklich standarisiert?

Das sollte im C Standard so drin stehen.

Ein größerer Schritt als nötig sollte nichts ausmachen, das merkt man 
nicht. Das verschwendet lediglich Speicher.
#3918738
Lesenswert?

Stefan us schrieb:

> Aber ist dieses verhalten auch wirklich standarisiert?

Ist es.

> für jeden denkbaren Computer? Was passiert, wenn ein zeichen kleiner
> ist,

wäre denkbar.
Nichts desto trotz muss dieses Zeichen ja im Speicher gespeichert werden 
können. Und dieser Speicher wird ja irgendwie ja adressiert.

> als die kleinstmögliche Schrittweite der Pointer-Erhöhung (z.B.
> wenn das zeichen 8bit ist, die Speicherzellen jedoch 16bit)?

Dann muss sich der Compiler was einfallen lassen, wie er dieses Problem 
löst. Zum Beispiel indem er 16 Bit für ein char verschwendet. Zum 
Beispiel indem er 2 Zeichen in jede 16 Bit Speicherzelle packt und 
programmintern mit einer 8 Bit Adressierung rechnet, jeweils ein 16 Bit 
Wort aus dem Speicher holt und die nicht relevanten 8 Bits ausmaskiert 
und den Rest geeignet zurechtschiebt.
Insbesondere letzteres muss ein Compiler sowieso können, der Code für 
eine Architektur produziert, bei der es Alignment-Restriktionen gibt von 
denen der Compilerbauer das Gefühl hat, dass er seinem Programmierer 
auch eine Möglichkeit anbieten will, sich davon zu befreien.
Gast #3918766
Lesenswert?

Stefan us schrieb:
> Die Pointer Syntax (buffer++) geht stillschweigend davon aus, dass ein
> char ein byte groß ist und dass der Zeiger beim Incrementieren auf das
> nächste Byte Zeigt. Das sind gleich zwei Annahmen, die bei
> ungewöhnlicher Hardwarearchitektur nicht zutreffen könnten.

Blödsinn. C setzt char mit Byte gleich. Es kann in C kein char geben, 
der nicht ein Byte groß ist. Definitionsgemäß.
Gast #3918861
Lesenswert?

Freddie schrieb:
> Stefan us schrieb:
>> Die Pointer Syntax (buffer++) geht stillschweigend davon aus, dass ein
>> char ein byte groß ist und dass der Zeiger beim Incrementieren auf das
>> nächste Byte Zeigt. Das sind gleich zwei Annahmen, die bei
>> ungewöhnlicher Hardwarearchitektur nicht zutreffen könnten.
>
> Blödsinn. C setzt char mit Byte gleich. Es kann in C kein char geben,
> der nicht ein Byte groß ist. Definitionsgemäß.

Das ist Blödsinn. Ich hatte Prozessoren, da hatte jede Speicherzelle 16 
Bit. Ein char hatte auch 16 Bit. Byteweise Adressierung gibt es da 
nicht. Alles 16 Bit.

Schau die mal die TI 28xx Serie an. Wird hier öfter im DSP-Forum 
benutzt.
#3918876
Lesenswert?

PittyJ schrieb:
> Freddie schrieb:
>> Stefan us schrieb:
>>> Die Pointer Syntax (buffer++) geht stillschweigend davon aus, dass ein
>>> char ein byte groß ist und dass der Zeiger beim Incrementieren auf das
>>> nächste Byte Zeigt. Das sind gleich zwei Annahmen, die bei
>>> ungewöhnlicher Hardwarearchitektur nicht zutreffen könnten.
>>
>> Blödsinn. C setzt char mit Byte gleich. Es kann in C kein char geben,
>> der nicht ein Byte groß ist. Definitionsgemäß.
>
> Das ist Blödsinn. Ich hatte Prozessoren, da hatte jede Speicherzelle 16
> Bit. Ein char hatte auch 16 Bit. Byteweise Adressierung gibt es da
> nicht. Alles 16 Bit.

Vorsicht.
Das was C unter einem Byte versteht ist nicht dasselbe was gemeinhin 
unter einem Byte verstanden wird.
In C ist ein 'Byte' einfach nur die kleinste Einheit. Damit ist nicht 
gesagt, dass 1 Byte aus 8 Bit bestehen muss.
Gast #3918895
Lesenswert?

Okey danke für eure Antworten, allerdings reichte es die vergessene Null 
Termination für das char Array zu ergänzen.


Nun hat sich schon das nächste Problem angekündigt:
1
  #include <SPI.h>        
2
  #include <Ethernet.h>
3
  #include <EthernetUdp.h>
4
  #include <MD5.h>
5

6
  
7
  
8
  //Variablen definieren:
9
  
10
  int udppacket;
11
  int packetbytes=0;
12
  byte zahlhalter=0;
13

14
    
15
  byte zaehler=0;
16
  unsigned long clienttime=0;
17
  
18

19
  //Verbindungseinstellungen
20
  
21
  //Server
22
  byte servermac[] = { 0xDE, 0xAD, 0xCE, 0xEF, 0xFE, 0xEA }; //Generierte MAC-Adresse
23
  IPAddress serverip(192, 168, 3, 1); //IP-Adresse
24
  IPAddress serversubnet(255, 255, 255, 0); //Subnetzmaske
25
  unsigned int serverport = 8001;      //Serverport: Für alle weiteren Clientports gilt 800*
26

27

28
//Clients
29

30
  IPAddress clientip(192, 168, 3, 2); //ClientIP
31
  IPAddress clientsubnet(255, 255, 255, 0); //Subnetzmaske
32
  unsigned int clientport=8002; //Clientport
33

34

35
  char packetbuffer[UDP_TX_PACKET_MAX_SIZE]; //Bufferspeicher um Empfangene Pakete bis zur Bearbeitung zu speichern.
36
  EthernetUDP Udp; //Beginnt eine UDP-Instanz
37

38

39
  void setup() {
40
  
41
  //Starte Ethernet & UDP Libary
42
  Ethernet.begin(servermac,serverip,serversubnet);
43
  Udp.begin(serverport);
44
  Serial.begin(9600);
45
}
46

47

48
  void loop() {
49
  
50
  
51
  int udppacket = Udp.parsePacket();
52
  if(udppacket){
53
  Serial.println(udppacket);
54
  char zeitarray[udppacket+1]; //Die empfangenen Bytes werden in ein Array geschrieben, und dieses wird um 1 erhöht für die Null Terination.
55
  Serial.println(udppacket+1);
56

57

58
    
59
   Udp.read(packetbuffer,UDP_TX_PACKET_MAX_SIZE);
60
   Serial.println(packetbuffer);
61
   
62
   for(int i=0; i<udppacket; i++) {
63
     
64
     zeitarray[i]=packetbuffer[i];
65
     Serial.print("Empfangene Zeit:");
66
     Serial.println(packetbuffer[i]);
67
     zaehler++;
68
  }
69

70
   
71
   if(zaehler==udppacket){
72
     
73
     
74
     //generate the MD5 hash for our string
75
    unsigned char* hash=MD5::make_hash(zeitarray);
76
    //generate the digest (hex encoding) of our hash
77
    char *md5str = MD5::make_digest(hash, 16);
78
    free(hash);
79
    Serial.println(md5str);
80
  //Give the Memory back to the System if you run the md5 Hash generation in a loop
81
    free(md5str);
82
    Serial.println(md5str);
83
    zaehler=0; 
84
   }  
85
  }
86
}


Das empfangen etc. funktioniert problemlos es werden auch 
unterschiedliche Hashes generiert jedoch sind diese falsch.


Ich nehme an es liegt an dieser Zeile:
1
 char zeitarray[udppacket+1]; //Die empfangenen Bytes werden in ein Array geschrieben, und dieses wird um 1 erhöht für die Null Terination.

Hier wird das array definiert und als größe die empfangene Byteanzahl 
genommen, dann wird diese um 1 addiert um das Array zu 
terminieren..Stimmt daran etwas nicht?
Gast #3918978
Lesenswert?

An das Array wird ein Byte angehangen, um es zu terminieren. Das 
funktioniert nur, wenn in den Nutzdaten kein NULL Zeichen vorkommt. 
Außerdem darf die Hash Funktion dieses abschließende Zeichen natürlich 
nicht mit verrechnen.

Ich fürchte, dass deine Nutzdaten ein Byte mit dem Wert 0 enthalten.
Gast #3919042
Lesenswert?

Ich habe das gerade ausgetestet,in diesem Array ist keine 0 und es 
funktioniert trotzdem nicht.

1
 
2
  #include <SPI.h>        
3
  #include <Ethernet.h>
4
  #include <EthernetUdp.h>
5
  #include <MD5.h>
6

7
   char zeitarray[6]={'1','2','3','4','5','6'}; 
8
   int test=6;
9

10
void setup() {
11
  
12
  Serial.begin(9600);
13
  char zeitarray[test+1];
14

15

16
  //generate the MD5 hash for our string
17
  unsigned char* hash=MD5::make_hash(zeitarray);
18
  //generate the digest (hex encoding) of our hash
19
  char *md5str = MD5::make_digest(hash, 16);
20
  free(hash);
21
  //print it on our serial monitor
22
  Serial.println(md5str);
23
  //Give the Memory back to the System if you run the md5 Hash generation in a loop
24
  free(md5str);
25
  Serial.println(md5str);
26
  
27
  
28
  
29
}
30

31
void loop() {
32
 
33
}
#3919103
Lesenswert?

Paul schrieb:
> in diesem Array ist keine 0 und es
> funktioniert trotzdem nicht.
Vllt. weil in dem Array gar nichts ist, bzw. nur das was davor in den 
Speicherzellen stand steht. Wenn du eine globale Variable innerhalb 
einer Funktion noch mal deklarierst, wird diese neu auf dem Stack 
angelegt und die globale ist in der Funktion nicht sichtbar.
#3919239
Lesenswert?

Paul schrieb:
> Ich habe das gerade ausgetestet,in diesem Array ist keine 0 und es
> funktioniert trotzdem nicht.
>

Das hier

>    char zeitarray[6]={'1','2','3','4','5','6'};

ist ja wieder nicht 0-terminiert!

Sorry, wenn ich das so sage. Aber wenn diese Funktion hier

>   unsigned char* hash=MD5::make_hash(zeitarray);

einen String haben will, dann musst du ihr auch einen String geben. Wenn 
in deinen zu verhashenden Daten ein Byte mit dem binären Wert 0 
vorkommen kann, dann hast du eben keinen C-String mehr und du kannst 
diese Funktion nicht benutzen. So einfach ist das.

Die Leute haben schon recht damit, wenn sie sagen, dass es ohne 
Grundlagen einfach nicht geht. Ein C-String hat genau definierte und 
bestimmte Eigenschaften. Kannst du die nicht erfüllen, dann hast du 
keinen C-String und kannst auch keine Funktionen benutzen, die von einem 
C-String ausgehen.
Gast #3920766
Lesenswert?

Ok, ich habe mich mal eingelesen und übe die Grundlagen.

Ein char-Dateityp ist also (meist?) mit 1 Byte Speichergröße definiert 
und hat einen Wertebereich von -128 bis 127 (also insgesamt 255 wie 
byte) und kann einen Buchstaben oder Zahlen von -128 bis 127 speichern.

Ein String ist entweder eine eigener Dateityp oder eine Zeichenkette in 
einem Dateityp z.B. in einem char?


Kann man einem char Array einfach eine Zahl mitgeben? Also:
1
char test[1]
2
test[0]=1;

Das Array test wurde mit der Größe zwei erstellt (0,1) wenn ich nur 0 
befülle ist dieses Null-Terminiert.

Liege ich richtig?
Gast #3920794
Lesenswert?

Paul schrieb:
> Liege ich richtig?

nein. Ein char[1] ist nur ein Array mit einem element.

> Ein char-Dateityp ist also (meist?) mit 1 Byte Speichergröße definiert
> und hat einen Wertebereich von -128 bis 127 (also insgesamt 255 wie
> byte) und kann einen Buchstaben oder Zahlen von -128 bis 127 speichern.

nein. ein char kann je Einstellung vom Compiler 0-255 oder -128 - 127 
gehen.
#3920807
Lesenswert?

Peter II schrieb:
> nein. ein char kann je Einstellung vom Compiler 0-255 oder -128 - 127
> gehen.

eben und das verstehe ich immer noch nicht weil -char keinen Sinn 
ergibt, manche Compiler auf unsigned char bestehen was aber Unsinn ist, 
besser verständlich finde ich uint8_ und int8_t und was ist mit dem 
ASCII Code der nur 7-bit kennt

Paul schrieb:
> Ah ok, Fehler bemerkt auch wenn das Array[1] ist, beginnt dieses bei 0.

stimmt doch eine Var im Array Länge 1 Index 0
Gast #3920808
Lesenswert?

Joachim B. schrieb:
> eben und das verstehe ich immer noch nicht weil -char keinen Sinn
> ergibt, manche Compiler auf unsigned char bestehen was aber Unsinn ist,
> besser verständlich finde ich uint8_ und int8_t und was ist mit dem
> ASCII Code der nur 7-bit kennt

es spielt doch keine rolle welche zahlen man ein char speichern kann.

char ist für Buchstaben.

char c = 'x'

ob es nun unsigned oder signed ist spielt dafür kein rolle.

Wenn man zahlen braucht, nimmt man kein char.
Gast #3921207
Lesenswert?

Max H. schrieb:
>> Wenn man zahlen braucht, nimmt man kein char.
> Wieso nicht? Ich verwende immer char wenn wenn ich nur kleine Zahlen
> brauche.

wenn die Zahlen < 128 sind ist es ja ok. Wenn du bis 256 brauchst dann 
ist char falsch denn es ist nicht festgelegt ob es signed oder unsigned 
ist.
#3921220
Lesenswert?

Peter II schrieb:
> ob es nun unsigned oder signed ist spielt dafür kein rolle.
>
> Wenn man zahlen braucht, nimmt man kein char.

wo steht das denn?

warum soll ich für Zahlen im Bereich 0-255 ein int oder uint 
reservieren, unter der Voraussetzung das die meisten int/uint als 16 Bit 
betrachten.

Beim MC oder PC ist das sowas von Speicherplatzverschwendung.
Nun kommt mir nicht mit Speicher ist egal, warum müssen denn die PC 
immer jedes Jahr um GHz oder Core wachsen wenn wir heute immer noch 
dieselben Briefe schreiben oder eine simple Tablle bearbeiten wie anno 
1990.

Wir sind doch mit dem üppigen Umgang von Speicher selbst Schuld wenn wir 
alle Nase lang neue Platten brauchen und uns DSL768 nicht mehr schnell 
genug ist, bzw. uns klicki bunti Browser mit animierter Werbung 
volllabern wo wir eigentlich nur im forum lesen wollen, OK ab und an mal 
ein Bild dazu aber was machen wir? ohne Denken mal eben 12MB aus dem 
Handy einstellen mit Informationsgehalt vom analog TV 320*240 Pix
Gast #3921250
Lesenswert?

Dirk B. schrieb:
> Der Standard verlangt mindestens  0-255 für unsigned char und -127 bis
> 127
> für signed char.

richtig, es hat auch niemand was anders behauptet.

Es geht um char und hier weiß man erst mal nicht ob es signed oder 
unsigned ist damit kann man nicht einfach 190 drin speichern.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren