C Werte von einem gegebenen Pointer auslesen

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Hallo Forumsgemeinde, insbesondere an C Freak's

    Bitte nicht auslachen, aber ich lerne noch.

    Folgendes Problemchen.

    Ich lese Temp.Sensoren für ein Steuerprojekt.
    Soweit so gut. Funktioniert erstmal grob.

    Habe ein Verständnisproblem mit diesem Pointer:

    Beispiel: nur ein Teilstück

    Wenn ich das recht verstehe, ist fptr ein Zeiger auf gptr , wenn gefunden.
    Aber der printf(........ fptr), zeigt mir die restlichen Zeichen ab "ts=" in dieser gelesenen Zeile.
    Ausgabe ist dann z.B. "ts=22015" also tausenstel Grad
    Ich hätte da ne Zahl erwartet, nämlich die, die auf "t=" zeigt.
    Hintergrund:
    Ich möchte die Zahlen ab (fptr + 2), bis ZeilenEnde als Integer.

    Was mache ich für einen Denkfehler ? :wallbash:
    Besten Dank im voraus.
    Gruß root

    Einmal editiert, zuletzt von root (21. Februar 2014 um 01:30)

  • Hey ...

    Code
    if( (fptr = strstr(*gptr, "t=")) )                    
       printf("WasserTemp Zelle(n) : \033[32m%s\033[0m °C\n", fptr+2);

    zunächst mal macht es durchaus Sinn, den Pointer (fptr) zu checken. Wenn nämlich "t=" nicht gefunden wird, erhälst Du einen NULL-Pointer und dann raucht Dein Programm schon mal ab.
    Zudem: strstr() zeigt nach erfolgreicher Rückkehr auf das erste Zeichen des gesuchten Ausdrucks in gptr. Da musst Du noch die Länge des gesuchten Ausdrucks dazuzählen um den Zahlenwert zu erhalten.

    Nur mal so auf die Schnelle ... gesamter Code (z.B. in einem spoiler) wäre trotzdem hilfreich.

    Saludo,
    -ds-

  • Moin dreamshader..

    Spoiler ? ... sry finde ich nciht, aber egal.

    Hier mal die komplette Sub.:
    Ich habe versucht alle möglichen Eventualitäten auszuschliesen ... es funktioniert.

    Grob gesagt :
    Wenn ein Sensor nach nem Neustart nicht da ist ... err,,,
    Wenn er während der Laufzeit nicht mehr reagiert ... err,,,

    etc .

    Nur dieser blöde fptr....
    Grß root

    Einmal editiert, zuletzt von root (21. Februar 2014 um 02:21)

  • Ja hi,

    da hast Du Dir ja was lustiges ausgedacht.
    So fungiert das ja gleich gar nicht ;) ...

    Also, dann fangen wir mal an:

    Zitat


    If *lineptr is set to NULL and *n is set 0 before the call, then
    getline() will allocate a buffer for storing the line, which should
    be freed by the user program.


    Das heisst für Dich:

    Das hier:

    Code
    char **gptr = malloc(sizeof(char*));
    *gptr = NULL;


    wird zu:

    Code
    char *gptr = NULL;


    und das hier:

    Code
    size_t *t = malloc(0);

    wird zu:

    Code
    size_t t = 0;


    Dann in der if-Abfrage wird:

    Code
    if (status == 0) {
            while( (nRet=getline(gptr, t, fd)) > 0) {
                r_line++;
                if (r_line == 1) {
                    fptr = strstr(*gptr, "YES");
                    if (fptr == NULL)
                        err_nr = 2;
                }

    zu:

    Code
    if (status == 0) {
            while( (nRet=getline(&gptr, &t, fd)) > 0) {
                r_line++;
                if (r_line == 1) {
                    fptr = strstr(gptr, "YES");
                    if (fptr == NULL)
                        err_nr = 2;
                }


    So, und da fehlt mir irgendwie was.
    Wann hört die while-Schleife auf bzw. wann soll sie aufhören.
    getline() allokiert den Speicher für den Datenstring selbst mit malloc(), wenn Du gptr auf NULL und t auf 0 setzt.
    Da getline() zudem so schlau ist, dass es den übergebenen Buffer mit realloc() neu holt, falls der aktuell übergebene zu klein ist, klappt das in der Schleife.
    Allerdings musst Du gptr irgendwo wieder freigeben. Das geschieht hier nicht. Das Programm liest bis zum Ende der Datei ohne eine Zeile mit free() freizugeben.
    Sowas nennt man memory-leak!


    Schliesslich werden im case/switch:

    Code
    fptr = strstr(*gptr, "t=");

    zu:

    Code
    if( (fptr = strstr(gptr, "t=")) )
        fptr += 2;


    So, ich hoffe, ich hab' jetzt nix vergessen oder selbst einen Denkfehler reingebracht.


    Apropo spoiler. Das sieht so aus:

    Spoiler anzeigen


    Das ist Text im Spoiler ...


    und steht zwischen "eckige Klammer auf, dem Wort spoiler, eckige Klammer zu" einen weiteren Tag "eckige Klammer auf, Schrägstrich, dem Wort spoiler und dann eckige Klammer wieder zu".
    Wenn ich mich recht erinnere, dann hat ps915 mal solche Dinge irgendwo gepostet ... das müsste ich jetzt aber auch erst suchen und dazu bin ich im Moment zu faul :fies: ...


    cheerio,
    -ds-

  • tach dreamshader,

    Ich sach ma so .... halbkalt erwischt ...

    Das mit dem File-öffnen, pointer zuordnen, speicher freihalten etc.. habe ich aus so'nem schlauen
    C Handbuch.
    Sicher musss das nicht das gelbe von Ei sein, aber irgendwie muss man ja anfangen.

    Ich bin davon ausgegangen, dass am Ende der Routine mit fcloseall(), return zur main()
    das von alleine passiert.
    Aber ok, lasse mich gerne belehren.
    Werde mich mit dem Thema mal genauer auseinandersetzen.

    Aber nicht's desto trotz

    Code
    if( (fptr = strstr(gptr, "t=")) )
       fptr +=2


    war genau das, das ich suchte.

    ich hab die getline() routine etwas geändert da selbst wenn das CRC ok war, "t=" nicht zwingend gefunden werden muss.

    ... und es tut...
    hier die routine:

    Spoiler anzeigen


    if (status == 0) {
    while( (nRet=getline(gptr, t, fd)) > 0) {
    r_line++;
    if (r_line == 1) {
    if( (fptr = strstr(*gptr, "YES")) )
    err_nr = 0;
    else
    err_nr = 2;
    }
    if( (r_line == 2) && (err_nr == 0) ) {
    if( (fptr = strstr(*gptr, "t=")) ) {
    fptr += 2;
    switch (file_nr) {
    case 1:
    cursor (12,25);
    printf("WasserTemp Zelle(n) : \033[32m%s\033[0m ", fptr);
    break;
    case 2:
    cursor (14,25);
    printf("WasserTemp Speicher : \033[32m%s\033[0m ", fptr);
    break;
    case 3:
    cursor (16,25);
    printf("Temperatur aussen : \033[32m%s\033[0m ", fptr);
    break;
    case 4:
    cursor (18,25);
    printf("Temperatur innen : \033[32m%s\033[0m ", fptr);
    }
    }
    }
    }
    }

    Zitat


    So, und da fehlt mir irgendwie was.
    Wann hört die while-Schleife auf bzw. wann soll sie aufhören.


    ähm... wüsste nicht, was ich da falschmache.(abgesehen von dem evtl. memory leak)
    wenn status 0 ist, war fopen ok.
    wenn getline die 1. Zeile gelesen hat, prüfe ich nur ob das CRC auf "YES" steht, ansonsten wird err gesetzt, dann kommt durch die while loop das nächste getline.
    dann prüfe ich, ob es die 2.Zeile ist, und err noch 0 ist.
    wenn "t=" gefunden wird, dann fptr += 2.
    switch file nutze ich nur, um herauszufinden welches file denn offen ist.
    die while loop ist damit beendet, weil ein neuer versuch von getline fehlschlägt.
    denn.....

    Code
    while( (nRet=getline(gptr, t, fd)) > 0) {


    greift nicht mehr.

    den Rest habe ich erstmal gelassen.... siehe above....
    da muss ich genauer dahintersteigen.
    apropos spoiler .. hab den post von ps915 gefunden ...kann jetzt auch "spoilern" , :lol:

    besten Dank für die Hinweise.

    gruß root


    Nachtrag:
    Habe das Proggi nebenbei laufen (ich greife per RDP auf die Himbeere zu), Du scheinst Recht zu haben .... es schmiert regelmäßig nach ca einer std. ab.
    Es knallt sie zwar nicht an die Wand, aber ich kriege bei allen Sensoren " ......not avail", und das konstant. Das Prog an sich läuft weiter.
    Will heisen: Er kann (aus welchen Gründen auch immer) das File nicht öffnen.
    CTRL C und Neustart des Progs haben nach ca 1 Std. das gleiche Ergebnis.
    Das ist denke ich ein Hinweis auf Memory leak.... gut , da beiss ich mich durch..

    cheer's-

    sodele:
    Hab mal versucht mich darüber bischen schlauer zu machen.
    Hab die eine Routine entsprechend geändert

    Spoiler anzeigen


    if (status == 0) {
    while( (nRet=getline(&gptr, &t, fd)) > 0) {
    r_line++;
    if (r_line == 1)
    if( (fptr = strstr(gptr, "YES")))
    err_nr = 0;
    else
    err_nr = 2;
    if( (r_line == 2) && (err_nr == 0) ) {
    if( (fptr = strstr(gptr, "t=")) ) {
    fptr += 2;
    switch (file_nr) {
    case 1:
    cursor (12,25);
    printf("WasserTemp Zelle(n) : \033[32m%s\033[0m ", fptr);
    break;
    case 2:
    cursor (14,25);
    printf("WasserTemp Speicher : \033[32m%s\033[0m ", fptr);
    break;
    case 3:
    cursor (16,25);
    printf("Temperatur aussen : \033[32m%s\033[0m ", fptr);
    break;
    case 4:
    cursor (18,25);
    printf("Temperatur innen : \033[32m%s\033[0m ", fptr);
    }
    }
    }
    }
    free(gptr);
    }

    d.h nach EOF wird wieder freigegeben.
    mal sehen, ob jetzt Ruhe ist.
    Dazu gleich ne Frage:
    Ich habe mehrere Beispiele zu getline() und free() gelesen.
    Einer macht nach EOF den free(), der andere nach jedem getline(), aber keiner sagt warum ???...Ich meine.. was ist denn jetzt richtig.
    Fein, ich hab mich mal nach dem EOF entschieden .

    Gruß root

    Einmal editiert, zuletzt von root (23. Februar 2014 um 04:52)

  • Ja hallöchen ...

    vielleicht mal zunächst was zu dem getline():

    Mir fallen da so ad hoc drei Varianten ein, wie Du das getline() richtig handeln kannst:

    1. Du weisst wie lang eine Zeile maximal sein kann:
    Dann allokierst Du gleich am Anfang des Programms einmal mit malloc(), calloc() ... einen etwas grösseren Buffer, also z.B. 4k.
    Rufst Du jetzt getline() auf und übergibst den Buffer als auch die allokierte Länge als Argument, dann checkt getline lediglich ob die
    Länge ausreicht. Da Du das auf jeden Fall vorher verifiziert hast, passiert sonst nix.
    Jetzt kannst Du problemlos Deine Schleife laufen lassen und am Ende des Programms Deinen Buffer freigeben.

    2. Du hast keine Ahnung wi lang der maximale Buffer sein kann:
    Dann setzt Du den Buffer auf NULL und die Länge auf 0.
    Beim ersten Aufruf von getline() wird dann von dieser Funktion selbst ein entsprechend grosser Buffer allokiert.
    Ab dann läuft alles wie in 1 -> Schleife, Programm-Ende

    3. Du gibts den Buffer nach jedem getline() frei.
    Das ist imho die programmtechnisch unglückliste Lösung, da sie das System unnötig belastet. Es kann aber auch Ausnahmen geben.
    Zunächst mal musst Du in diesem Fall den Buffer vor jedem weiteren getline() freigeben und die Länge auf 0 setzen.
    Sinn macht das, wenn Du die gelesene Zeile in einer Funktion oder was auch immer weiter verarbeitest und in der Zwischenzeit
    einen anderen getline() machen willst.

    so long,
    -ds-

  • Tachle dreamshader.

    Das war ne vernünftige Erklärung.Besten Dank mal.

    Ich habe mich mal für Varante 2 entschieden.
    Der Erfolg war durchschlagend. Nach ca. ner Std. kracht es im Gebälk.. wie gehabt. :wallbash:
    So, wie finde ich raus, ob er wirklich kontinuierlich Speicher verbrät.
    Im Proggi habe ich nichts gefunden, was falsch sein könnte.
    Dann hatte ich ne Idee.

    Ich klinke mich per RDP auf den raspi, und lande auf der GUI.
    Dort ein Terminalfenster öffnen, das Proggi starten und laufen lassen.
    Dann ein 2. Terminalfenster öffnen und mir "free" den Speicher beobachten, währen das Proggi läuft.
    Das Ergebnis hat es gezeigt.

    RAM Verlauf

    Den "free" hat ich alle 10 Minten +- gemacht.
    Und siehe da...da klaut mir alle 10 Minten einer ca. 2,5+-KB Ram.
    Wenn ich allen 10 sec. lese, die Filegröße mit einbeziehe, bei 4 Sensoren, komme ich grob auf diesen Wert.
    voilá...:D... ergo muss mein free() ins Leere gehen.

    Gut... das finde ich.

    Also...
    Ich hab nicht vor, diesen Thread unnötig in die Länge zu ziehen, und andauernd jemanden mit Fragen löchern.
    Ich weiss, C Anfänger stellen sich oft unnötig selbst Fallen aber ok, da muss man durch.

    Sich werde ich wieder Fragen haben,und auch fragen :)

    Ich bin erstmal ein ganzes Stück weitergekommen.

    Werde dann mal sagen, wie ich es hinbekommen habe.
    Besten Dank erstmal:thumbs1:

    Gruß root

    Einmal editiert, zuletzt von root (24. Februar 2014 um 01:01)

  • Na hi,

    um Fragen zu beantworten ist so ein Forum doch da ... oder seh' ich das falsch.
    Ausserdem bleibt es jedem selbst überlassen ob er auf ein Thema eingeht oder nicht.
    Da brauchst Du Dir keinen Kopf drum machen ;) ...

    Schau mal nach, ob Du gdb installiert hast:

    schlecht zu finden: wenn der Prompt kommt, gdb mit 'q' verlassen.
    Dann ruf mal Dein Programm im gdb auf:


    Dann poste mal die Fehlermeldung bzw. Ausgabe von gdb (ach ja: Gnu DeBugger) ...

    cheers,

    -ds-

  • hi,
    da hast auch wieder recht... muss ja keiner antworten ...:D

    sodele, jetzt wird's etwas lustig .. copy & paste geht über RDP nicht.

    also: ich hab das gemacht.
    erstens

    dann das
    zweitens

    wenn ich jetzt "r" eingeben... rennt das Programm, und tut eben ....

    wenn ich jetzt CTRL C drücke.. kommt das

    drittens

    das sieht bischen zerissen aus, aber das die die Maske vom Programm.

    Ich kann hier abbrechen dann isser drausen, oder "n" sagen dann steht er bei (gdb)

    :lol:

    gruß root

  • Loooool .....:lol:... hab sowas geahnt... *gg

    Ich geh jetzt innen Keller und hol mir 2 (Bitte ein Bit).... und geniese die noch... *gg

    adios
    gruß root

    Nachtrag:
    Im Moment trete ich absolut auf der Stelle.
    Also, ich hab das Proggi über "gbd" nach reboot neu gestartet, dann nach dem Motto "Warten auf Godot" ne Std. gewartet.
    Das Prob ist , ist schmiert ja in dem Sinne nicht komplett ab.
    Wenn ich ein File nicht öffnen kann, fange ich das mit ner err_nr ab, und mache weiter.
    Er sagt mir, dass alle 4 Sensoren nicht gelesen werden können, obwohl die Files definitiv vorhanden sind ....ich seh sie ja im 2. Term-Fenster.
    Die Maske zeigt mir dann, welches File nicht geöffnet werden konnten.
    gbd geift logischweise nicht, das ja im Prinzip nix abschmiert.
    das sieht dann so aus:
    ungeregelt
    Ich hab das so gemacht: Wenn die Rücklauftemperatur der Zellen 65° übersteigt (die liegt im Moment ber der Sonneneintrahlung bei 68,5°),
    schalte ich eine Zelle auf Strom um.(das war die letzte erfolgreiche Messung).
    Die PID Regelung greift dann nicht mehr, ich lasse den Rest der Zellen in Ruhe,da ich keine Rückmeldung mehr bekomme.

    Kurz zu dem WatchDog Status:Wenn ich die Akkus lade,oder im Idealfall gar auf Akku umschalte, steuere ich ein Zeitrelais an, das 1 Minute hält.
    Wenn das Proggi abschmieren sollte, oder sonst was passiert, wird das Relais nicht neu getriggert und fällt ab.
    d.h. Alles fällt in den Grundzustand zurück, und gut ist..... Bin also erstmal auf der sicheren Seite... ist getestet, und funkioniert

    Im Normalzustand.. nach eben neustart sieh das ganze so aus:
    So sollte es sein
    Außerdem hab ich festgestellt, dass das erste "read" nach nem reset, irgendwie Schmarrn ist , das ignoriere ich.
    Jetzt nochwas.
    Bis zu der berühmten Stunde nimmt das RAM ja stetig ab.
    Dann die Errors, ..... und das freie RAM NIMMT WIEDER ZU .....:wallbash:

    heilig's Blechle.. da hab ich mir was angetan ..... *ggg
    ich glaub, ich brauch ne Pause..das Leben ist hart am Limit ... aber es ist herrlich ..:lol:.. und wunderbar..

    grüßle root :D

    Einmal editiert, zuletzt von root (24. Februar 2014 um 14:51)

  • Sodele....

    Ich habe jetzt die Puffergröße selbst festgelegt (+ bißchen Sicherheit)
    und Ruhe ist...

    ...nichts mehr läuft voll.

    gruß root

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!