In C Werte aus Protokoll einlesen und z.B. Mittelwert berechnen

Jennesta

Erfahrenes Mitglied
Hallo,

ich habe mir dein Programm einmal angesehen und bei mir ist es nichtmal soweit gelaufen. Ich vermute es liegt an dem undefinierten Verhalten, wie ComFreek bereits geschrieben hat.

Am besten initialisierst du alle Variablen vor der ersten Benutzung. Zahlen am besten mit 0 (auch wenn es der Compiler wahrscheinlich selbst macht ist es eine gute Angewohnheit). Und Alle Zeiger mit NULL.

Mit dem scanf habe ich dir ein Beispiel gemacht, wie du es verwenden kannst.

C:
    if(fp == NULL) {
        printf("Fehler beim oefffnen");
    } else {
        while(6 == fscanf(fp, "%s %s %s %f %f %f\n", Datum, Uhrzeit, Adresse, &Druck, &Strom, &Leistung)) {
            printf("%s, %s, %s, %f, %f, %f\n", Datum, Uhrzeit, Adresse, Druck, Strom, Leistung);
           
            // Auswertung
        }
    }

Eine weitere Sache ist noch dein Puffer. Du hast ihn auf 48 gelegt. Ich würde den an deiner Stelle größer wählen.
Auch wenn der Puffer für deine Zeilen bisher reichen wird, ist kein Platz für weitere Zeicehn vorhanden. Insbesondere bei generierten Dateien die evtl. durch andere Hände gehen, gehe immer davon aus, dass diese fehlerhaft sind. Es könnte aber auch sein, dass du anstelle von 55.83 den Wert 101.82 bekommst. Dann hast du ein Problem.
 

ComFreek

Mod | @comfreek
Moderator
fscanf mit %s zu verwenden ist grundsätzlich ein Problem und eine Sicherheitslücke zugleich. Einfach den Format Specifier mit Längenangabe nutzen, siehe meinen Link oben :)
 

R4TFIV3

Grünschnabel
Ich bringe gute Neuigkeiten!!

Es funktioniert!! :love: Ich Danke euch!!

Hier mein Code:

C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

    char puffer[50];
    char *ptr1=NULL, *ptr2=NULL, *ptr3=NULL, *ptr4=NULL;
    char Datum[11]= {'\0'};
    char Uhrzeit[16]= {'\0'};
    char Adresse[3]= {'\0'};
    char cDruck[6];
    float Druck=0;
    float Strom=0;
    float Leistung=0;
    float sumDruck05=0;
    float sumDruck06=0;
    int i=0;
    int k=0;
    
    char Leerzeichen[] = " ";
    char Adresse05[] = "05";
    char Adresse06[] = "06";


int main() {
    FILE *fp = fopen("Test_Daten.txt", "r");

    

    if(fp == NULL) {
        printf("Fehler beim oefffnen");
    } else {
        while(6 == fscanf(fp, "%11s %16s %3s %6s %f %f\n", Datum, Uhrzeit, Adresse, cDruck, &Strom, &Leistung))
            {

            // printf("%s %s %s %s %.2f %.2f\n", Datum, Uhrzeit, Adresse, cDruck, Strom, Leistung);
            ptr1 = strtok(Datum, Leerzeichen);
            ptr2 = strtok(Uhrzeit, Leerzeichen);
            ptr3 = strtok(Adresse, Leerzeichen);
            ptr4 = strtok(cDruck, Leerzeichen);

                if(strcmp(ptr3,Adresse05)==0)
                {
                Druck = atof(ptr4);
                strcpy(Datum,ptr1);
                strcpy(Uhrzeit,ptr2);
                strcpy(Adresse,ptr3);
                sumDruck05+=Druck;
                }

                if(strcmp(ptr3,Adresse06)==0)
                {
                Druck = atof(ptr4);
                sumDruck06+=Druck;
                strcpy(Datum,ptr1);
                strcpy(Uhrzeit,ptr2);
                strcpy(Adresse,ptr3);
                }

            }
        }
    
            fclose(fp);
            fp=NULL;
            
            printf("Summe Druck von Adresse 05: %.2f\n",sumDruck05);
            printf("Summe Druck von Adresse 06: %.2f\n",sumDruck06);
            // Speicher freigeben
    
    return 0;

}
//Programm Ende

Hier die Ausgabe:
Summe Druck von Adresse 05: 11.86
Summe Druck von Adresse 06: 11.68

Es funktioniert zwar das mit dem größten Druck nicht mehr, aber darum kümmer ich mich später wieder.
Ich versuche jetzt noch das ganze in Funktionen aufzuteilen um dem ganzen noch den letzten Glanz zu geben.
Verbesserungsvorschläge gerne :)
Vielen Dank für eure Hilfe!! Ich melde mich wenn ich wieder hänge.
 

ComFreek

Mod | @comfreek
Moderator
Dein fscanf-Aufruf ermöglicht ist immer noch hoch problematisch :) Wenn du einen Speicherplatz hast, der x chars fasst, dann musst du fscanf %s[x-1]s übergeben (ohne die eckigen Klammern natürlich; edit: hier war vorher ein Fehler!). D.h. für Datum musst du %s10 hernehmen. Daran siehst eher du schon, dass C eine eher schlechtere Sprache ist: sehr subtile Sicherheitslücken können sehr einfach implementiert werden. Ich musste auch erstmal nachlesen, was genau die Zahl nach %s zählt.

Siehe Read no more than size of string with scanf().

Dann beheb das mal, lager in Funktionen auf, formatier schön deinen Code und dann können wir dir noch Verbesserungsvorschläge geben :) Ich freu mich!
 
Zuletzt bearbeitet:

Technipion

Erfahrenes Mitglied
dann musst du fscanf %s[x+1]s übergeben
Da ist glaube ich %[x-1]s gemeint. Wie hier zu lesen:
A format specifier for fscanf follows this prototype:

%[*][width][length]specifier

Where the specifier character at the end is the most significant component
sString of charactersAny number of non-whitespace characters, stopping at the first whitespace character found. A terminating null character is automatically added at the end of the stored sequence.

Übrigens: Sofern man jetzt nicht gerade einen Mikrocontroller programmiert, sondern eine Maschine mit i.d.R. mehreren GB RAM, kann man imho auch größere Puffer wählen: char buffer[1024] = {'\0'};.
Selbst mit perf wird es schwer, die "Performanceeinbußen" hier nachzumessen.

Ich versuche jetzt noch das ganze in Funktionen aufzuteilen um dem ganzen noch den letzten Glanz zu geben.
Verbesserungsvorschläge gerne
Klar, fröhliches Coden!

Gruß Technipion
 

R4TFIV3

Grünschnabel
Hallo zusammen.
Ich möchte euch nun mein "fast" fertiges Programm vorstellen. Es ist ein großer Erfolg für mich, da dies mein erstes Programm ist, das ich auf die Beine gestellt habe. Für manch einen von euch wahrscheinlich nichts besonderes aber für mich ein großer Meilenstein :love:
Leider ist das Programm natürlich nicht perfekt. Ich hätte gerne noch eine malloc Funktion mit eingebracht um eine dynamische Speicherverwaltung zu implementieren, aber das hat sich momentan noch als Problem in der Umsetzung herausgestellt. Ebenso ist mir nicht bewusst wie ich in einer Funktion mehrere Werte ausgeben kann. Vielleicht lässt sich das später auch noch implementieren wenn ich mehr Wissen gewonnen habe.


Hier mein Code:

C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

    //Array05 und Array06 müssen an Datenmenge angepasst werden!
    float array05[1250],array06[1250];
    float Druck=0;
    float Strom=0;
    float Leistung=0;
    float Druck05=0,sumDruck05=0, maxDruck05=0, smallDruck05=0,Mittelwert05=0;
    float Druck06=0,sumDruck06=0, maxDruck06=0, smallDruck06=0,Mittelwert06=0;
    float varianz05=0, Standardabweichung05=0;
    float varianz06=0, Standardabweichung06=0;

    char *ptr1=NULL, *ptr2=NULL, *ptr3=NULL, *ptr4=NULL, *fp=NULL;
    char Datum[11] = {'\0'}, maxDatum[11]={'\0'}, smallDatum[11]={'\0'};
    char Uhrzeit[16]= {'\0'}, maxUhrzeit[16]={'\0'}, smallUhrzeit[16]={'\0'};
    char Adresse[3]= {'\0'}, maxAdresse[3]={'\0'}, smallAdresse[3]={'\0'};
    char cDruck[6];
    char Leerzeichen[] = " ";
    char Adresse05[] = "05";
    char Adresse06[] = "06";

    int i=0,j=0,k=0,l=0,m=0,n=0,o=0;
   




//Funktionen

float sumAdresse05()
{
                Druck = atof(ptr4);

                k++;
               
return Druck05+=Druck;
}

float sumAdresse06()
{
                Druck = atof(ptr4);
               

                j++;
return Druck06+=Druck;
}

float groessterDruck05()
{
if(i==0)
{
    strcpy(maxDatum,ptr1);
    strcpy(maxUhrzeit,ptr2);
    strcpy(maxAdresse,ptr3);
    maxDruck05=atof(ptr4);
   

}else
{
    if(atof(ptr4)>maxDruck05)
    {
        maxDruck05 = atof(ptr4);
        strcpy(maxDatum,ptr1);
        strcpy(maxUhrzeit,ptr2);
        strcpy(maxAdresse,ptr3);      
    }
}

   
return maxDruck05;

}

float groessterDruck06()
{
if(i==0)
{
    strcpy(maxDatum,ptr1);
    strcpy(maxUhrzeit,ptr2);
    strcpy(maxAdresse,ptr3);
    maxDruck06=atof(ptr4);


}else
{
    if(atof(ptr4)>maxDruck06)
    {
        maxDruck06 = atof(ptr4);
        strcpy(maxDatum,ptr1);
        strcpy(maxUhrzeit,ptr2);
        strcpy(maxAdresse,ptr3);      
    }
}

   
return maxDruck06;
}

float kleinsterDruck05()
{
    if(i==0)
{
    strcpy(smallDatum,ptr1);
    strcpy(smallUhrzeit,ptr2);
    strcpy(smallAdresse,ptr3);
    smallDruck05=atof(ptr4);


}else
{
    if(atof(ptr4)<smallDruck05)
    {
        smallDruck05 = atof(ptr4);
        strcpy(smallDatum,ptr1);
        strcpy(smallUhrzeit,ptr2);
        strcpy(smallAdresse,ptr3);      
    }
}
    return smallDruck05;
}

float kleinsterDruck06()
{
    if(i==0)
{
    strcpy(smallDatum,ptr1);
    strcpy(smallUhrzeit,ptr2);
    strcpy(smallAdresse,ptr3);
    smallDruck06=atof(ptr4);


}else
{
    if(atof(ptr4)<smallDruck06)
    {
        smallDruck06 = atof(ptr4);
        strcpy(smallDatum,ptr1);
        strcpy(smallUhrzeit,ptr2);
        strcpy(smallAdresse,ptr3);      
    }
}
    return smallDruck06;
}

float var05()
{  

            for(n=0;n<l;++n)
            {
                varianz05+=pow((array05[n]-Mittelwert05),2);
            }
                n++;
            return varianz05;
}

float var06()
{  

            for(o=0;o<m;++o)
            {
                varianz06+=pow((array06[o]-Mittelwert06),2);
            }
            o++;  
            return varianz06;
}

float stdAbweichung05()
{
Standardabweichung05=sqrt(varianz05/k);

return Standardabweichung05;
}

float stdAbweichung06()
{
Standardabweichung06=sqrt(varianz06/j);

return Standardabweichung06;
}

//Hauptprogramm

int main() {
    FILE *fp = fopen("b01_b02.txt", "r");

    if(fp == NULL) {
        printf("Fehler beim oefffnen");
    } else {

        while(6 == fscanf(fp, "%10s %15s %2s %5s %f %f\n", Datum, Uhrzeit, Adresse, cDruck, &Strom, &Leistung))
            {
            printf("%s %s %s %s %.2f %.2f\n", Datum, Uhrzeit, Adresse, cDruck, Strom, Leistung);

            ptr1 = strtok(Datum, Leerzeichen);
            ptr2 = strtok(Uhrzeit, Leerzeichen);
            ptr3 = strtok(Adresse, Leerzeichen);
            ptr4 = strtok(cDruck, Leerzeichen);

                if(strcmp(ptr3,Adresse05)==0)
                {
                    sumDruck05 = sumAdresse05(ptr4);
                    maxDruck05 = groessterDruck05();
                    smallDruck05 = kleinsterDruck05();
                    smallDruck06 = kleinsterDruck06(); //Warum muss das hier her??
                    array05[l]=atof(ptr4);
                    l++;
           
                }
                if(strcmp(ptr3,Adresse06)==0)
                {
   
                     sumDruck06 = sumAdresse06(ptr4);
                     maxDruck06 = groessterDruck06();
                     smallDruck06 = kleinsterDruck06();
                     array06[m]=atof(ptr4);
                     m++;
                }
            i++;
            }
        }

            Mittelwert05=sumDruck05/k;
            Mittelwert06=sumDruck06/j;

            varianz05=var05();
            Standardabweichung05=stdAbweichung05();
            varianz06=var06();
            Standardabweichung06=stdAbweichung06();
            fclose(fp);
            fp=NULL;

            //Anlage 05
            printf("\nAnlage 05:\n");
            printf("Summe Druck von Anlageadresse 05: %.2f\n",sumDruck05);
            printf("Anzahl Zeilen von Anlageadresse 05: %d\n",k);
            printf("Mittelwert von Anlageadresse 05: %.2f\n",Mittelwert05);
            printf("max. Druck von Anlageadresse 05: %.2f\n",maxDruck05);
            printf("min. Druck von Anlageadresse 05: %.2f\n",smallDruck05);
            printf("Varianz von Anlageadresse 05: %lf\n",varianz05/k);
            printf("Standardabweichung von Anlageadresse 05: %lf\n",Standardabweichung05);
            //Anlage 06
            printf("\nAnlage 06:\n");
            printf("Summe Druck von Adresse 06: %.2f\n",sumDruck06);
            printf("Anzahl Zeilen von Adresse 06: %d\n",j);
            printf("Mittelwert von Adresse 06: %.2f\n",Mittelwert06);
            printf("max. Druck von Adresse 06: %.2f\n",maxDruck06);
            printf("min. Druck von Adresse 06: %.2f\n",smallDruck06);
            printf("Varianz von Adresse 06: %lf\n",varianz06/j);
            printf("Standardabweichung von Adresse 06: %lf\n",Standardabweichung06);

    return 0;
}
//Main Programm Ende

Die Ausgabe sieht wie folgt aus:

Anlage 05:
Summe Druck von Anlageadresse 05: 7434.05
Anzahl Zeilen von Anlageadresse 05: 1250
Mittelwert von Anlageadresse 05: 5.95
max. Druck von Anlageadresse 05: 6.04
min. Druck von Anlageadresse 05: 5.59
Varianz von Anlageadresse 05: 0.006961
Standardabweichung von Anlageadresse 05: 0.083434

Anlage 06:
Summe Druck von Adresse 06: 7451.92
Anzahl Zeilen von Adresse 06: 1250
Mittelwert von Adresse 06: 5.96
max. Druck von Adresse 06: 6.05
min. Druck von Adresse 06: 5.54
Varianz von Adresse 06: 0.005621
Standardabweichung von Adresse 06: 0.074973



Mir ist bewusst das es sehr viele Initialisierungen gibt aber für mich ist das komplett überschaubar.

Falls ihr Tipps oder Anmerkungen habt, gerne!!

Vielen Dank für eure Hilfe und Anmerkungen!!

Grüße
 

Jennesta

Erfahrenes Mitglied
Hallo,
generell sieht dein Programm schon einmal ganz gut aus.
Ich kenne deinen Lernplan nicht genau, aber zu Übungszwecken könntest du sonst auch privat noch folgende Dinge ausprobieren. Folgende Verbesserungsvorschläge wären erstmal nur Kür.

Um Variablen zu "sparen" könntest du dir einmal structs anschauen, um zusammenhängene Variablen zu einem Objekt zu gruppieren.​

Desweiteren könntest du noch versuchen häufig vorkommenden Code in Funktionen auszulagern, bswp. die printf Ausgaben am Ende. Ich habe mir das nicht bis ins Detail angesehen, aber es kommen sehr häufig 3 strcpy Aufrufe hintereinander, die sich nur leicht unterscheiden. Da könnte man z.B. Funktionen mit Parametern verwenden.​

Viele Grüße
 
Zuletzt bearbeitet: