Forum: PC-Programmierung strstr() & strncpy()


von Welle 🧐 S. (w3llschmidt)


Lesenswert?

Ich raffs nicht ...

ich erstell mir einen Zeiger aus einem FD auf ein String,

1
ptr=strstr(buffer, "1-0:21.7.0*255");
2
printf(ptr);

1-0:21.7.0*255(+00023*W)
1-0:21.7.0*255(+00023*W)
1-0:21.7.0*255(+00023*W)

Super! Aber nun will ich die Zahl in den Klammern extrahieren mit

1
char value[6];         
2
strncpy(value, ptr+16, 5);

Und egal was ich mache -> Segmentation fault.

:-/

von Rolf M. (rmagnus)


Lesenswert?

Henrik Wellschmidt schrieb:
> Ich raffs nicht ...
>
> ich erstell mir einen Zeiger aus einem FD auf ein String,

Was ist denn ein "Zeiger aus einem FD"?

> ptr=strstr(buffer, "1-0:21.7.0*255");
> printf(ptr);
>
> 1-0:21.7.0*255(+00023*W)
> 1-0:21.7.0*255(+00023*W)
> 1-0:21.7.0*255(+00023*W)
>
> Super! Aber nun will ich die Zahl in den Klammern extrahieren mit
>
> char value[6];
> strncpy(value, ptr+16, 5);
>
> Und egal was ich mache -> Segmentation fault.

Hast du auch daran gedacht, das '\0' anzuhängen?

von Peter II (Gast)


Lesenswert?

welchen datentype hat ptr?

von Welle 🧐 S. (w3llschmidt)


Lesenswert?

Rolf Magnus schrieb:
> Was ist denn ein "Zeiger aus einem FD"?

Hallo Rolf,

also ich lese mit read() aus einem 'File Fescriptor' in ein
char array (buffer) ...

strstr() liefert dann einen Zeiger auf die Fundstelle
im char array (buffer).

Das wollte ich damit sagen ;-)

von Welle 🧐 S. (w3llschmidt)


Lesenswert?

Peter II schrieb:
> welchen datentype hat ptr?

char *ptr;

von Volkmar D. (volkmar)


Lesenswert?

Hast Du Rolfs Frage gesehen?

Rolf Magnus schrieb:
>> Und egal was ich mache -> Segmentation fault.
>
> Hast du auch daran gedacht, das '\0' anzuhängen?

Was kommt noch nach der strncpy-Anweisung, eine Ausgabe mit printf?

Volkmar

von Welle 🧐 S. (w3llschmidt)


Lesenswert?

Volkmar Dierkes schrieb:
> Hast Du Rolfs Frage gesehen?

Ja, kann ich aber noch nicht zuordnen ...

> Was kommt noch nach der strncpy-Anweisung, eine Ausgabe mit printf?

Erstmal noch nischt ... ich wollte dann mit atof[] in ein Float wandeln
und dann ein eine andere Funktion schicken ...

1
        while (1) {
2
3
                res = read(fd, buffer, sizeof(buffer) -1);
4
5
                if (res >=0) {
6
                buffer[res]=0;
7
8
                ptr=strstr(buffer, "1-0:21.7.0*255");
9
10
                char value[6]; 
11
                strncpy(value, ptr+16, 5);
12
13
                }
14
        }

von Rolf M. (rmagnus)


Lesenswert?

Henrik Wellschmidt schrieb:
> Volkmar Dierkes schrieb:
>> Hast Du Rolfs Frage gesehen?
>
> Ja, kann ich aber noch nicht zuordnen ...

Strings müssen nullterminiert sein. Ein strncpy kopiert zwar ein \0 des 
Originalstrings mit, wenn es einen kompletten String kopiert, aber wenn 
der Quellstring länger ist als die angegebene Maximallänge, dann hängt 
es keins an.

>> Was kommt noch nach der strncpy-Anweisung, eine Ausgabe mit printf?
>
> Erstmal noch nischt ...

Dann dürfte aber auch kein Segfault passieren. Der kommt erst, wenn du 
mangels String-Ende-Zeichen über das Ende hinaus liest.

von Welle 🧐 S. (w3llschmidt)


Lesenswert?

Rolf Magnus schrieb:
> Strings müssen nullterminiert sein. Ein strncpy kopiert zwar ein \0 des
> Originalstrings mit, wenn es einen kompletten String kopiert, aber wenn
> der Quellstring länger ist als die angegebene Maximallänge, dann hängt
> es keins an.

Ahh!

1-0:21.7.0*255(+00023*W)

|1|-|0|:|2|1|.|7|.|0|*|2|5|5|(|+|0|0|0|2|3|*|W|)|\0

strncpy(value, ptr+16, 5);

| | | | | | | | | | | | | | | | |0|0|0|2|3| | | |\0

Fehlt also hier                            ^

|0|0|0|2|3|

Ich wollte aber danach eigentlich gleich:

1
double w = atof(value);

ranhängen ?!

von Karl H. (kbuchegg)


Lesenswert?

Henrik Wellschmidt schrieb:


> Fehlt also hier                            ^
>
> |0|0|0|2|3|
>
> Ich wollte aber danach eigentlich gleich:
>
>
>
1
> double w = atof(value);
2
>
>
> ranhängen ?!

Na dann setz halt hinten in value ein 0 Byte ein

    strncpy(value, ptr+16, 5);
    value[5] = '\0';


Egal was strncpy gemacht hat, jetzt ist das Zeug im Array value ganz 
sicher ein String, weil sichergestellt ist, dass da auf jeden Fall eine 
0-Terminierung existiert.

Und du solltest den Pointer, den dir strstr gegeben hat, 
sicherheitshalber auch gegen NULL prüfen :-)

PS: Wärs nicht besser und auch einfacher, nach der öffnenden Klammer '(' 
suchen zu lassen?

von Welle 🧐 S. (w3llschmidt)


Lesenswert?

Karl Heinz Buchegger schrieb:
>
>     strncpy(value, ptr+16, 5);
>     value[5] = '\0';
>
>
> Egal was strncpy gemacht hat, jetzt ist das Zeug im Array value ganz
> sicher ein String, weil sichergestellt ist, dass da auf jeden Fall eine
> 0-Terminierung existiert.
>
> Und du solltest den Pointer, den dir strstr gegeben hat,
> sicherheitshalber auch gegen NULL prüfen :-)
>
> PS: Wärs nicht besser und auch einfacher, nach der öffnenden Klammer '('
> suchen zu lassen?

Hallo  Karl Heinz ...

Segmentation fault :(


1
        while (1) {
2
3
                res = read(fd, buffer, sizeof(buffer) -1);
4
5
                if (res >=0) {
6
                buffer[res]=0;
7
8
                ptr = strstr(buffer, "1-0:21.7.0*255");
9
10
                char value[10];
11
                strncpy(value, ptr+14,5);
12
                value[5] = '\0';
13
14
15
                }
16
        }

Ich denke das liegt an dem zeiger ptr 'strncpy(value, ptr+14,5);'

In den beispielen verwenden die immer 'char arrays' keine pointer
auf ein 'char arry' ...

Mist.

von Thomas M. (thomil)


Lesenswert?

In deinem letzten Code:

Liest read() genug Zeichen ein? Wenn read() einen Fehler zurückliefert, 
dann wird 'buffer' nie 0-Terminiert und du liest u.U. über das buffer 
ende.

Findet strstr() auch wirklich den gesuchten string? Ansonsten ist ptr 
ein NULL pointer der beim Zugriff zu einem segfault führt.

von W.S. (Gast)


Lesenswert?

Henrik Wellschmidt schrieb:
> Ich raffs nicht ...

Tja, Stringverarbeitung war schon immer eine der besonderen Stärken von 
C.

W.S.
(dem heut abend beim Tempranillo nach Stänkern zumute ist)

Apropos char* Pointer: versuche es doch mal mit

strncpy(value, &buffer[16], 5);

vielleicht verschafft dir das ne Erkenntnis.

von Welle 🧐 S. (w3llschmidt)


Lesenswert?

Thomas Miletich schrieb:
> In deinem letzten Code:
>
> Liest read() genug Zeichen ein? Wenn read() einen Fehler zurückliefert,
> dann wird 'buffer' nie 0-Terminiert und du liest u.U. über das buffer
> ende.
>
> Findet strstr() auch wirklich den gesuchten string? Ansonsten ist ptr
> ein NULL pointer der beim Zugriff zu einem segfault führt.

Ja, das passt alles ... ich greif ja nur auf buffer zu
wenn 'if (res >=0)'

1
res = read(fd, buffer, sizeof(buffer) -1);
2
3
if (res >=0) {
4
buffer[res]=0;

Das kommt 5sekündlich über die Schnittstelle rein ->

1
/HAG5eHZ010C_EHZ1WA02
2
3
1-0:0.0.0*255(1095110000152759)
4
1-0:1.8.0*255(000005.2786)
5
1-0:96.5.5*255(82)
6
0-0:96.1.255*255(0000152759)
7
1-0:32.7.0*255(232.15*V)
8
1-0:52.7.0*255(232.16*V)
9
1-0:72.7.0*255(000.00*V)
10
1-0:31.7.0*255(000.10*A)
11
1-0:51.7.0*255(000.21*A)
12
1-0:71.7.0*255(000.00*A)
13
1-0:21.7.0*255(+00023*W)
14
1-0:41.7.0*255(+00042*W)
15
1-0:61.7.0*255(+00000*W)
16
1-0:96.50.0*0(67)
17
1-0:96.50.0*1(07CF)
18
1-0:96.50.0*2(19)
19
1-0:96.50.0*3(09)
20
1-0:96.50.0*4(25)
21
1-0:96.50.0*5(1A)
22
1-0:96.50.0*6(003D381B300AF9003D00490200009F80)
23
1-0:96.50.0*7(00)
24
!

Und

ptr = strstr(buffer, "1-0:21.7.0*255");
printf(ptr);

sucht mir schoen das was ich brauche ...
1
1-0:21.7.0*255(+00023*W)
2
1-0:21.7.0*255(+00023*W)
3
1-0:21.7.0*255(+00023*W)
4
1-0:21.7.0*255(+00023*W)
5
1-0:21.7.0*255(+00023*W)
6
1-0:21.7.0*255(+00023*W)
7
1-0:21.7.0*255(+00023*W)
8
1-0:21.7.0*255(+00023*W)
9
1-0:21.7.0*255(+00023*W)
10
1-0:21.7.0*255(+00023*W)
11
1-0:21.7.0*255(+00023*W)
12
1-0:21.7.0*255(+00023*W)

Und dann verlässt es mich ...

von Volkmar D. (volkmar)


Lesenswert?

Hallo,

Henrik Wellschmidt schrieb:
1
>                 char value[10];
2
>                 strncpy(value, ptr+14,5);
3
>                 value[5] = '\0';

versuche mal das hier, achte auf das '&' bei value.
1
                 char value[10];
2
                 strncpy(&value, ptr+14,5);
3
                 value[5] = '\0';

Wenn ich mich nicht irre, mußt Du der strncpy-Funktion ja eine Adresse 
übergeben, wo der String hingeschrieben werden soll. Aber da value kein 
Pointer ist, sondern eine Array of char, brauchst Du die Adresse davon.

Volkmar

von Karl H. (kbuchegg)


Lesenswert?

Henrik Wellschmidt schrieb:

> Und dann verlässt es mich ...

Das einzige was dich verlässt ist, dass dein printf offenbar eine 
Sicherung gegen NULL-Pointer hat ....
  UND DEIN CODE NICHT !

Frag jetzt endlich mal den Pointer ab, den du von strstr kriegst. Denn 
das kann ich aus 300km Entfernung sehen, dass in der Hälfte deiner Daten 
der Suchstring gar nicht vorkommt. Und in dem Fall liefert dir strstr 
einen NULL-Pointer! Und mit einem NULL Pointer kannst du nicht weiter 
arbeiten!

Bei ausnahmslos jeder Suche muss man immer damit rechnen, dass der 
gesuchte Wert nicht vorhanden ist! Auch du musst damit rechnen! So wie 
alle anderen auch!

Und buffer ist hoffentlich ein char Array!
(Immer diese HickHack Technik nur Ausschnitte aus einem Programm zu 
zeigen. Was ist da so toll drann? Ist das wirklich cool, wenn wir auf 
der anderen Seite des Monitors Rätselspielchen spielen müssen?)

1
   char buffer[100];
2
3
...
4
5
   while (1) {
6
7
     res = read(fd, buffer, sizeof(buffer) -1);
8
9
     if (res > 0) {
10
       buffer[res] = '\0';
11
12
       printf( "received >%s<\n", buffer );
13
14
       ptr = strstr( buffer, "1-0:21.7.0*255" );
15
       if( ptr != NULL ) {
16
         char value[6]; 
17
         strncpy( value, ptr + 16, 5 );
18
         value[5] = '\0';
19
20
         printf( "'%s' -> '%s'\n", buffer, value );
21
       }
22
     }
23
   }


Und ich schätze mal, das alles funktioniert überhaupt nicht, weil gar 
nicht garantiert ist, dass read immer eine komplette Zeile liefert. 
read() interessieren deine Zeilen nämlich nicht, der liefert was da ist, 
bzw. füllt dir den Buffer randvoll an. Verwende fgets. Dann bist du 
zumindest dieses Problem los. fgets teilt die eingehenden Daten schön in 
Zeilen auf und liefert dir immer eine komplette Zeile.

Wenn du fgets nimmst, musst du deinen open durch einen fopen austauschen 
und den close gegen einen fclose.

von Karl H. (kbuchegg)


Lesenswert?

Volkmar Dierkes schrieb:
> Hallo,
>
> Henrik Wellschmidt schrieb:
>
1
>                 char value[10];
2
>>                 strncpy(value, ptr+14,5);
3
>>                 value[5] = '\0';
4
>
>
> versuche mal das hier, achte auf das '&' bei value.

Quatsch


> übergeben, wo der String hingeschrieben werden soll. Aber da value kein
> Pointer ist, sondern eine Array of char, brauchst Du die Adresse davon.

Kauf dir ein C-Buch und lies mal nach wie Arrays übergeben werden.

von Thomas M. (thomil)


Lesenswert?

Henrik Wellschmidt schrieb:
> Thomas Miletich schrieb:
>> In deinem letzten Code:
>>
>> Liest read() genug Zeichen ein? Wenn read() einen Fehler zurückliefert,
>> dann wird 'buffer' nie 0-Terminiert und du liest u.U. über das buffer
>> ende.
>>
>> Findet strstr() auch wirklich den gesuchten string? Ansonsten ist ptr
>> ein NULL pointer der beim Zugriff zu einem segfault führt.
>
> Ja, das passt alles ... ich greif ja nur auf buffer zu
> wenn 'if (res >=0)'

Stimmt. Hab ich aufgrund der fehlerhaften Formatierung falsch gelesen.

von Welle 🧐 S. (w3llschmidt)


Lesenswert?

Karl Heinz Buchegger schrieb:
>
>
1
> 
2
> ...
3
> 
4
>    while (1) {
5
> 
6
>      res = read(fd, buffer, sizeof(buffer) -1);
7
> 
8
>      if (res > 0) {
9
>        buffer[res] = '\0';
10
> 
11
>        printf( "received >%s<\n", buffer );
12
> 
13
>        ptr = strstr( buffer, "1-0:21.7.0*255" );
14
>        if( ptr != NULL ) {
15
>          char value[6];
16
>          strncpy( value, ptr + 16, 5 );
17
>          value[5] = '\0';
18
> 
19
>          printf( "'%s' -> '%s'\n", buffer, value );
20
>        }
21
>      }
22
>    }
23
>

Danke Karl Heinz!!!! Das rockt!!!

1
00023
2
00023
3
00023
4
00023
5
00023
6
00023
7
00023

Karl Heinz Buchegger schrieb:
>Und mit einem NULL Pointer kannst du nicht weiter arbeiten!

Jetzt verstehe ich ....

(null)(null)(null)(null)(null)(null)(null)(null)(null)(null)(null)(null) 
(null)(null)(null)(null)(null)(null)(null)(null)(null)(null)(null)1-0:21 
.7.0*255(+00000*W)

von Welle 🧐 S. (w3llschmidt)


Lesenswert?

Thomas Miletich schrieb:
> Stimmt. Hab ich aufgrund der fehlerhaften Formatierung falsch gelesen.

Ich weiss, ich habe da grosse Differenzen zum Standard ;-)

von Karl H. (kbuchegg)


Lesenswert?

Es hilft alles nichts. Du brauchst ein C-Buch und musst es 
durcharbeiten. Diese Try&Error Programmierung, das Zusammenkopieren von 
Code, das funktioniert vielleicht bei kleinen Programmen (und auch da 
nicht besonders gut), aber irgendwann ist ein Punkt erreicht, an dem man 
ohne solide gelernte Grundlagen nicht weiter kommt.


> Ich weiss, ich habe da grosse Differenzen zum Standard ;-)
Und warum tust du dann nichts dagegen?
Wenigstens Einrückungen richtig zu stellen, kostet dir nichts. Die sind 
aber ein solides und erprobtes Mittel um { } Fehler zu sehen und zu 
finden. Erfordert Dispziplin, schon klar. Aber im Vergleich zu dem, was 
dir die restliche Programmierung an Disziplin abverlangt, ist das 
Pipifax.

von Welle 🧐 S. (w3llschmidt)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Es hilft alles nichts. Du brauchst ein C-Buch und musst es
> durcharbeiten. Diese Try&Error Programmierung, das Zusammenkopieren von
> Code, das funktioniert vielleicht bei kleinen Programmen (und auch da
> nicht besonders gut), aber irgendwann ist ein Punkt erreicht, an dem man
> ohne solide gelernte Grundlagen nicht weiter kommt.

Ich habe 4 C-Bücher :-)

Aber es ist halt zu verlockend sich vor den Rechner zu setzen.

Ich verstehe ja ganz gut was hier geschrieben wird und lerne dabei.

Klar, blind Code kopieren wäre wirlich blöde.

von Welle 🧐 S. (w3llschmidt)


Lesenswert?

Karl Heinz Buchegger schrieb:
> bzw. füllt dir den Buffer randvoll an. Verwende fgets. Dann bist du
> zumindest dieses Problem los. fgets teilt die eingehenden Daten schön in
> Zeilen auf und liefert dir immer eine komplette Zeile.

Hallo Karl Heinz,

Ich habe noch nirgens gesehen, wie man fopen() und tcsetattr() zusammen
bekommt ...

http://en.wikibooks.org/wiki/Serial_Programming/termios

...

von DirkB (Gast)


Lesenswert?

Henrik Wellschmidt schrieb:
> Ich habe noch nirgens gesehen, wie man fopen() und tcsetattr() zusammen
> bekommt ...

Das sollte über die Funktion fileno() gehen.

von Karl H. (kbuchegg)


Lesenswert?

Henrik Wellschmidt schrieb:

> Ich habe 4 C-Bücher :-)
>
> Aber es ist halt zu verlockend sich vor den Rechner zu setzen.

Ich kann das ja verstehen.
Aber es bringt nichts. Dafür, dass du 4 Bücher hast, schwächelst du 
extrem. Um es mal freundlich auszudrücken.

Du musst die Dinger auch durcharbeiten! In einem guten Buch sind am Ende 
eines jeden Kapitels Übungen drinnen mit denen man kontrollieren kann, 
ob man alles verstanden hat.

> Ich verstehe ja ganz gut was hier geschrieben wird und lerne dabei.

Das was hier geschrieben wird, ist noch nicht mal ein matter Abklatsch 
dessen, was es zu den Themenkreisen Files, Strings, deren Zusammenspiel, 
Textparsing, Konvertierungen, Pointer, Arrays und der Zusammenhang 
Pointer zu Arrays, ... zu sagen gibt. Und das sind in deinem Code gerade 
mal 8 Zeilen, die in den Büchern aber 3 bis 5 komplette Kapitel 
(teilweise auch kapitelübergreifend) in Anspruch nehmen, mit allem drum 
und drann. In Programmiersprachen ist es oft so, dass die Dinge 
zusammenhängen, wie Zahnräder in einem Getriebe. Man kann ein Getriebe 
nicht dadurch verstehen, indem man sich jedes Zahnrad einzeln ansieht. 
Es ist die Gesamtheit aller Räder, die ein Getriebe ausmachen.

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.