Komische Werte im char array

Gast #3688853
Lesenswert?

Hallo Leute!

Ich möchte aus einem gegebenen char-Array einen bestimmten Teil 
ausschneiden. Dazu suche ich mit einer for-Schleife nach einem 
Trennzeichen (in diesem Fall '.'). Der Inhalt vom Anfang des char-Arrays 
bis zu dem character vor dem Trennzeichen soll über eine weitere 
for-Schleife in einem neuen char-Array gespeichert werden.
Später soll dann mithilfe von atoi() der Inhalt des Arrays in eine 
integer-Zahl umgewandelt werden. Das funktioniert auch soweit.

Allerdings sehe ich beim Debuggen einen komischen Wert im char-Array der 
immer wieder auftaucht. Hier erstmal mein Code:
1
#define SERIAL_BUFFER_SIZE 10
2

3
int main(void) {
4
  const char data[SERIAL_BUFFER_SIZE] = {'1','2','3','4','5','6','.','7','8','\0'};
5
  uint8_t indexDot, length;
6

7
  for(uint8_t i = 0; i < SERIAL_BUFFER_SIZE; i++) {
8
    if (data[i] == '.') {
9
      indexDot = i;
10
    } else if (data[i] == '\0') {
11
      length = i + 1;
12
    }
13
  }
14

15
  char foo1[indexDot];
16
  memset(foo1,0,indexDot); //nullen
17
  for(uint8_t i = 0; i < indexDot; i++) {
18
    foo1[i] = data[i];
19
  }
20

21
  char foo2[SERIAL_BUFFER_SIZE-indexDot-2];
22
  memset(foo2,0,SERIAL_BUFFER_SIZE-indexDot-2); //nullen
23
  for(uint8_t i = 0; i < SERIAL_BUFFER_SIZE-indexDot-1; i++) {
24
        f002[i] = data[indexDot+1+i];
25
  }
26

27
  //Conversion to integer
28
  uint32_t integer_foo1 = atoi(foo1);
29
  uint32_t integer_foo2 = atoi(foo2);
30
}

Die erste for-Schleife findet die Länge des Arrays heraus (hier 
eigentlich unnötig, da sowieso fest) und die Stelle des Trennzeichens 
'.'.

Nachdem aber die zweite for-Schleife durchlaufen ist, wird im letzten 
Schleifendurchlauf immer noch ein '@' an die letzte Stelle hinzugefügt. 
D.h. ich erhalte dann "123456@". Bei der letzten for-Schleife 
funktioniert wieder alles bestens.

Weiß jemand woher dieses Zeichen kommt?

Eine weiter Frage: Ist das Nullen der Arrays mit memset() überhaupt 
nötig? Wie sieht das ganze bei µC aus?

Schon mal vielen Dank! :)
Gast #3688864
Lesenswert?

Andi schrieb:
> Weiß jemand woher dieses Zeichen kommt?

ja weil du keine ende vom String hast. Es fehlt ein 0 Byte.

Aber das ganze ist viel zu kompliziert!

das ganze umkopieren ist überhaupt nicht notwenig, atoi hört von selber 
auf zu lesen wenn kein Digit mehr kommt.
Gast #3688877
Lesenswert?

Peter II schrieb:
> Andi schrieb:
>> Weiß jemand woher dieses Zeichen kommt?
>
> ja weil du keine ende vom String hast. Es fehlt ein 0 Byte.
>
> Aber das ganze ist viel zu kompliziert!
>
> das ganze umkopieren ist überhaupt nicht notwenig, atoi hört von selber
> auf zu lesen wenn kein Digit mehr kommt.

Warum ist dann beim Array foo2 nie so ein Zeichen am Ende?

Danke für den Hinweis mit atoi! Da kann ich mir die Hälfte sparen ;)
Gast #3688880
Lesenswert?

1
#include "string.h"
2

3
#define SERIAL_BUFFER_SIZE 10
4

5
int main(void) {
6
  char data[SERIAL_BUFFER_SIZE] = {'1','2','3','4','5','6','.','7','8','\0'};
7
  uint8_t indexDot;
8

9
  dot = strnchr (data, SERIAL_BUFFER_SIZE, '.');
10
  data [dot] = '\0';
11

12
  uint32_t integer_foo1 = atol(data);
13
  uint32_t integer_foo2 = atol(&data[dot + 1]);

Fehlerbehandlung fehlt natürlich noch.
Gast #3688884
Lesenswert?

Wobei atol natürlich auch ein wenig blöd ist, wenn Du den vollen 
Wertebereich von uint32_t nutzen willst. Aber gut. Das Ganze ist sowieso 
ein Blödsinn - äh, ein Übungscode zum wegschmeissen, da schadet das nun 
auch nichts.
#3688887
Lesenswert?

An dieser Stelle sollte Dein Compiler laut meckern:
1
  char foo1[indexDot];

Wenn Du ein Feld definieren willst muss die Größe zur Compilezeit 
bekannt sein. indexDot ist aber eine Variable. Definiere das Feld auch 
zu SERIAL_BUFFER_SIZE und probiere es noch mal.

Die schon erwähnte Bemerkung mit dem fehlenden '\0' Zeichen stimmt 
natürlich auch. Du müsstest mindestens indexDot + 1 als Feldgröße 
anlegen.
Gast #3688903
Lesenswert?

A. H. schrieb:
> An dieser Stelle sollte Dein Compiler laut meckern:
>   char foo1[indexDot];
>
> Wenn Du ein Feld definieren willst muss die Größe zur Compilezeit
> bekannt sein. indexDot ist aber eine Variable. Definiere das Feld auch
> zu SERIAL_BUFFER_SIZE und probiere es noch mal.
>
> Die schon erwähnte Bemerkung mit dem fehlenden '\0' Zeichen stimmt
> natürlich auch. Du müsstest mindestens indexDot + 1 als Feldgröße
> anlegen.

Der Compiler sagt dazu nichts...seltsam. Ich dachte die Terminierung mit 
dem '\0'-Zeichen wird nur für die Interpretation als String benötigt?
Gast #3688909
Lesenswert?

Bitflüsterer schrieb:
> #include "string.h"
>
> #define SERIAL_BUFFER_SIZE 10
>
> int main(void) {
>   char data[SERIAL_BUFFER_SIZE] =
> {'1','2','3','4','5','6','.','7','8','\0'};
>   uint8_t indexDot;
>
>   dot = strnchr (data, SERIAL_BUFFER_SIZE, '.');
>   data [dot] = '\0';
>
>   uint32_t integer_foo1 = atol(data);
>   uint32_t integer_foo2 = atol(&data[dot + 1]);
>
> Fehlerbehandlung fehlt natürlich noch.

data [dot] = '\0';

ist nicht notwendig, kann sogar stören. Wenn man mit const arbeitet.
#3688965
Lesenswert?

Peter II schrieb:
> A. H. schrieb:
>> An dieser Stelle sollte Dein Compiler laut meckern:
>>   char foo1[indexDot];
>>
>> Wenn Du ein Feld definieren willst muss die Größe zur Compilezeit
>> bekannt sein.
>
> nein muss es nicht. Im Aktuellen C und C++ ist das zulässig.

OK, man lernt nie aus, meine Standards sagen alle noch etwas anderes. 
(Sind aber nicht mehr die neuesten :-) Obwohl ich mir nicht vorstellen 
kann, wie der Compiler das macht. Zumindest dürfte es ja im gleiche 
Stack-Frame keine weiteren Variablen dahinter mehr geben?!

Oder macht er daraus implizit Pointer, initialisert sie zur Laufzeit mit 
dem Stackpointer und schiebt den einfach entsprechend weiter?
#3689008
Lesenswert?

Dirk B. schrieb:
> A. H. schrieb:
>> OK, man lernt nie aus, meine Standards sagen alle noch etwas anderes.
>> (Sind aber nicht mehr die neuesten :-)
>
> VLA (Variable Length Array) gibt es seit C99.
>
> Also auch schon seit 15 Jahren.

Der letzte Standard (C++), den ich hier habe ist von 2003. Angesichts 
der Zeit, die viele Compiler brauchen, um neue Features zuverlässig zu 
implementieren, erachte ich das für die meisten Fälle auch noch als 
ausreichend. (Da wird für die Deklaration eines Arrays auch noch ein 
konstanter Ausdruck verlangt. Wenn es auf die Portabilität des Codes 
ankommt würde ich in diesem Fall auch versuchen, mich darauf zu 
beschränken.)
Gast #3689095
Lesenswert?

Peter II schrieb:
> nein muss es nicht. Im Aktuellen C und C++ ist das zulässig.
1
#include <stdint.h>
2

3
int main(void)
4
{
5
  uint8_t i;
6
  uint8_t array[i];
7
  for(i = 0; i < 10; i++)
8
  {
9
    array[i] = 0;
10
  }
11
  return 0;
12
}
mit gcc 4.8.1, -Wall -Werror -pedantic -pedantic-errors -std=c++11 
compiliert gibt:
1
error: ISO C++ forbids variable length array 'array' [-Wvla]
Scheint also doch nicht ganz so zulässig zu sein.

Andi schrieb:
> Der Compiler sagt dazu nichts...seltsam.
Der compiler sagt da nur was zu wenn du mit -pedantic compilierst. Ohne 
-pedantic hält er schön die klappe.

Grüße
Gast #3689104
Lesenswert?

Kaj schrieb:
> mit gcc 4.8.1, -Wall -Werror -pedantic -pedantic-errors -std=c++11
> compiliert gibt:error: ISO C++ forbids variable length array 'array'
> [-Wvla]
> Scheint also doch nicht ganz so zulässig zu sein.

bei C geht es

-Wall -Werror -pedantic -pedantic-errors -std=c99

test.c:6:11: error: variable 'array' set but not used 
[-Werror=unused-but-set-variable]
   uint8_t array[i];

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