Forum: Mikrocontroller und Digitale Elektronik strstr() gibt keinen NULL pointer zurück? (atmega 2560)


von Hans L. (haled)


Lesenswert?

Hallo zusammen,

ich habe folgendes Problem:
Ich sende einen String den ich aus einer Datei lese per UART an den MCU 
(atmega 2560). Dort will ich aus diesem mit strstr() X und Y Koordinaten 
extrahieren.
Leider bleibt der Code in der While-Schleife hängen da scheinbar 
strstr() nie einen NULL Pointer zurück gibt. Ist der NULL Character '\0' 
zur Beendung des Strings falsch gesetzt?
Ich kann meinen Fehler leider nicht finden. Vielleicht könnt ihr mir 
helfen!?

Ich sende den String: "G01 X69.204775 Y23.337389 Z-0.100000 G01 
X80.964849 Y21.666507 Z-0.100000 G00 Z0.100000 (End cutting path id: 
path4285"

Zurück bekomme ich am Serial Port:
1
G01 X69.204775 Y23.337389 Z-0.100000 G01 X80.964849 Y21.666507 Z-0.100000 G00 Z0.100000 (dppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp
 usw.

Mein Code sieht folgendermaßen aus ( zu beachten USART_Transmit('p'); um 
das while loop zu zeigen):
1
void USART_Init(unsigned int ubrr); 
2
void USART_Transmit(unsigned char data); 
3
unsigned char USART_Receive( void );
4
char uart_char;
5
char uart_string[100] = {""};
6
7
int main(void) 
8
{ 
9
  int char_counter = 0;
10
  USART_Init(MYUBRR); 
11
  while(uart_char != '('){
12
    uart_char = USART_Receive();
13
    uart_string[char_counter] = uart_char;
14
    char_counter++;
15
  }
16
  uart_string[char_counter] = '\0';
17
  
18
  for(int i = 0;i<sizeof(uart_string);i++){
19
    USART_Transmit(uart_string[i]);
20
  }
21
22
  char *hier;
23
  char x_values[50][7];
24
  char y_values[50][7];
25
  int number_of_coordinates = 0;
26
  USART_Transmit(sizeof(uart_string));
27
  while( (hier = strstr(uart_string, "G01 X")) != NULL){
28
    strncpy(x_values[0],hier+5,6);
29
    strncpy(y_values[0],hier+5+11,6);     
30
    number_of_coordinates++;
31
    USART_Transmit('p');
32
  }
33
  USART_Transmit('r');
34
  uint8_t coordinates [number_of_coordinates][2];
35
  for(int i=0;i<number_of_coordinates;i++){
36
    coordinates[i][0] = (int) atof(x_values[i]);
37
    coordinates[i][1] = (int) atof(y_values[i]);
38
  }
39
}

von Stefan F. (Gast)


Lesenswert?

Hans L. schrieb:
1
while( (hier = strstr(uart_string, "G01 X")) != NULL) {
2
    strncpy(x_values[0],hier+5,6);
3
    strncpy(y_values[0],hier+5+11,6);
4
    number_of_coordinates++;
5
    USART_Transmit('p');
6
}

Da du innerhalb der while Schleife den gefundenen String nicht aus 
uart_string entfernst, findest du ihn immer wieder erneut.

von Lutz B. (lutzbroszio)


Lesenswert?

strstr liefert nur zurück ob der gesuchte String enthalten ist. Der 
String ändert sich auch nicht, deswegen hängst du in deiner while 
Schleife.

Auch solltest du überprüfen, ob der empfangene String größer als dein 
Buffer ist.

von GEKU (Gast)


Lesenswert?

Hans L. schrieb:
> while( (hier = strstr(uart_string, "G01 X")) != NULL){
>     strncpy(x_values[0],hier+5,6);
>     strncpy(y_values[0],hier+5+11,6);
>     number_of_coordinates++;
>     USART_Transmit('p');
>   }
Suche wird immer an der gleichen Stelle fortgesetzt!
1
char *pNext;   // !!!!
2
3
int main(void) 
4
{ 
5
  int char_counter = 0;
6
  USART_Init(MYUBRR); 
7
  while(uart_char != '('){
8
    uart_char = USART_Receive();
9
    uart_string[char_counter] = uart_char;
10
    char_counter++;
11
  }
12
  uart_string[char_counter] = '\0';
13
  
14
  for(int i = 0;i<sizeof(uart_string);i++){
15
    USART_Transmit(uart_string[i]);
16
  }
17
18
  char *hier;  
19
  char x_values[50][7];
20
  char y_values[50][7];
21
  int number_of_coordinates = 0;
22
  USART_Transmit(sizeof(uart_string));
23
24
  pNext=uart_string; //!!!!
25
26
  while( (hier = strstr(pNext, "G01 X")) != NULL){ //!!!!
27
    strncpy(x_values[0],hier+5,6);
28
    strncpy(y_values[0],hier+5+11,6);     
29
    number_of_coordinates++;
30
    USART_Transmit('p');
31
    pNext=hier; // !!!! hier wird bei der Suche weiter gesprungen
32
  }
33
  USART_Transmit('r');
34
  uint8_t coordinates [number_of_coordinates][2];
35
  for(int i=0;i<number_of_coordinates;i++){
36
    coordinates[i][0] = (int) atof(x_values[i]);
37
    coordinates[i][1] = (int) atof(y_values[i]);
38
  }
39
}

So sollte es gehen.

von GEKU (Gast)


Lesenswert?

GEKU schrieb:
> pNext=hier; // !!!! hier wird bei der Suche weiter gesprungen

Blödsinn,

natürlich

pNext=hier+1;

von Hans L. (haled)


Lesenswert?

Vielen Dank!!! :-)
Jetzt macht es Sinn!!

habe es jetzt so umgesetzt und es funktioniert:
1
  while( (hier = strstr(uart_string, "G01 X")) != NULL){
2
    strncpy(x_values[number_of_coordinates],hier+5,6);
3
    strncpy(y_values[number_of_coordinates],hier+5+11,6);
4
    strcpy(uart_string,hier+5);     
5
    number_of_coordinates++;
6
  }

von Stefan F. (Gast)


Lesenswert?

Der Kopiervorgang ist allerdings wesentlich teurer, als den Zeiger zu 
versetzen.

von GEKU (Gast)


Lesenswert?

Stefanus F. schrieb:
> Der Kopiervorgang ist allerdings wesentlich teurer, als den Zeiger zu
> versetzen.

Das ist der Grund warum C schneller ist als so mach andere Sprache ist. 
Zeiger machen es möglich. Aber es ist gefährlich wenn man nicht weiß was 
man damit anstellt.

von Dirk B. (dirkb2)


Lesenswert?

Hans L. schrieb:
> strncpy(x_values[0],hier+5,6);

Das funktioniert nicht so, wie du dir das vorstellst.

Wenn in den 6 Zeichen keine '\0' gefunden wird, wird auch keine kopiert.
Der String in x_Values ist nicht terminiert.

Warum überhaupt der Umweg über das 2D-char-Array.
atof hört da auf, wo es keine gültig Zahl erkennt.

Warum überhaupt atof, wenn du eigentlich atoi möchtest.
besser noch strtoul.

von GEKU (Gast)


Angehängte Dateien:

Lesenswert?

Es geht kürzer und klarer.
Das Einfügen der Z-Koordinaten sind jetzt ein Kinderspiel.

1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <string.h>
4
#include <math.h>
5
6
char uart_string[]="G01 X69.204775 Y23.337389 Z-0.100000 G01 X80.964849 Y21.666507 Z-0.100000 G00 Z0.100000";
7
8
int main(void)
9
{
10
    char *px;
11
    float coordinates[10][2];
12
13
    int number_of_coordinates = -1;
14
15
    px=uart_string;
16
17
    memset(coordinates,0,sizeof(coordinates));
18
19
    while (*px)
20
    {
21
        switch (*px)
22
        {
23
            case 'G':
24
                number_of_coordinates++;
25
                break;
26
27
            case 'X':
28
                px++;
29
                coordinates[number_of_coordinates][0]=atof(px);
30
                break;
31
32
            case 'Y':
33
                px++;
34
                coordinates[number_of_coordinates][1]=atof(px);
35
                break;
36
37
            default:
38
                break;
39
        }
40
        px++;
41
    }
42
43
    for (number_of_coordinates=0;number_of_coordinates<10;number_of_coordinates++)
44
    {
45
        printf("%d\tx=%f\t\ty=%f\r\n",number_of_coordinates,coordinates[number_of_coordinates][0],coordinates[number_of_coordinates][1]);
46
    }
47
}

Vorteil :

-weniger Variable
-weniger Code
-vermutlich wesentlich schneller
-leichtere Ausbaufähigkeit

Auch für Prozessoren mit wenig SRAM geeignet, da strstr() ein 
Speicherfresser ist.

von GEKU (Gast)


Angehängte Dateien:

Lesenswert?

Beispiel mit Z-Koordinate

von GEKU (Gast)


Angehängte Dateien:

Lesenswert?

GEKU schrieb:
> while (*px)

man könnte auch mit "while (uart_char)" direkt die Zeichen vom UART 
einlesen und im SWITCH die Abbruchbedingung exekutieren.

von GEKU (Gast)


Lesenswert?

GEKU schrieb:
> man könnte auch mit "while (uart_char)" direkt die Zeichen vom UART
> einlesen und im SWITCH die Abbruchbedingung exekutieren.

Vergessen , geht nicht so einfach, da mehrere Zeichen für FLOAT 
Variable gelesen werden müssen

von Hans L. (haled)


Lesenswert?

Hallo zusammen,

vielen Dank, dass ihr euch so viel Zeit genommen habt und meine Frage so 
detailliert beantwortet habt!
Ihr habt mir sehr geholfen und ich konnte auch viel dabei lernen!
Ich habe es jetzt so umgesetzt wie oben vorgeschlagen.

Echt klasse!!!

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.