[C/C++] 3byte Overhead finden

Dieses Thema im Forum "Programmierung & Entwicklung" wurde erstellt von Smokers, 8. Juni 2010 .

Status des Themas:
Es sind keine weiteren Antworten möglich.
  1. 8. Juni 2010
    3byte Overhead finden

    Also hier mein bisheriger Code :

    Code:
    /*
     * File: main.c
     * Author: Smoki
     *
     * Created on 08. June 2010, 22.45
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    
    /*
     *
     */
    #if defined(_WIN32) || defined(_WIN64)
    
    void clear_screen() {
     system("cls");
    }
    #else
    
    void clear_screen() {
     system("clear");
    }
    #endif
    
    struct satz {
     char name[30];
     char vorname[20];
     char adresse[50];
    };
    void readFileName(char*);
    void printDataSet(unsigned int, char*);
    void writeNewDataToPosition(int, char*);
    
    int main(int argc, char** argv) {
     FILE *fp;
     char *fname;
     char key = '\0';
    
     if (argc > 1) {
     fname = argv[1];
     } else {
     fname = (char *) malloc(sizeof (char) * 61);
     fname[60] = '\0';
     readFileName(fname);
     }
    
    
     printf("Gewaehlte Datei ist : \"%s\".\n\n", fname);
     while (!file_exists(fname)) {
     while (key != '1' && key != '2') {
     printf("Die Datei existiert nicht. Waehlen Sie bitte die Vorgehensweise:\n");
     printf("\n");
     printf("(1) Dateinamen aendern\n");
     printf("(2) Datei erstellen\n");
     fflush(stdin);
     key = getchar();
     fflush(stdin);
     }
     if (key == '1') {
     readFileName(fname);
     }
     if (key == '2') {
     fp = fopen(fname, "a+");
     if (fp) {
     printf("Datei wurde erfolgreich angelegt...\n\n");
     } else {
     printf("Fehler beim erstellen der Datei. Erneuter Versuch!");
     fname[0] = '\0';
     }
     fclose(fp);
     }
     key = '\0';
     }
    
     fflush(stdin);
     clear_screen();
     do {
     while (key != '1' && key != '2' && key != '3' && key != '4') {
     clear_screen();
     printf("Sie arbeiten mit Datei \"%s\".\n", fname);
     printf("Waehlen Sie Ihre naechste Operation...\n\n");
     printf("(1) Neuen Datensaetze eingeben\n");
     printf("(2) Datensatz bearbeiten \n");
     printf("(3) Ausgabe aller Datensaetze aus \"%s\"\n", fname);
     printf("(4) Ausgabe eines speziellen Datensatzes aus \"%s\"\n", fname);
     fflush(stdin);
     key = getchar();
     fflush(stdin);
     }
     if (key == '1') {
     writeNewDataToPosition(0, fname);
    
     }
     if (key == '3') {
     printDataSet(0, fname);
     }
     if (key == '4') {
     int pos = 0;
     while (pos < 1 || pos > 100) {
     printf(">Position(1-100) : ");
     fflush(stdin);
     scanf("%d", &pos);
     fflush(stdin);
     }
     clear_screen();
     printDataSet(pos, fname);
     printf("\n");
     }
     while (key != 'n' && key != 'j') {
     printf("Moechten Sie eine weitere Operation durchfuehren?(j/n)\n");
     key = getchar();
     fflush(stdin);
     }
     } while (key != 'n');
    }
    
    void writeNewDataToPosition(int pos, char* fname) {
     FILE *fp;
    //......coming soon
    
    }
    
    void printDataSet(unsigned int pos, char* fname) {
     struct satz data;
     FILE *fp;
     fp = fopen(fname, "r");
     int i = 1;
     printf("sizeof mal pos : %d\n", (pos - 1) * sizeof (struct satz));
     if (pos > 0) {
     fseek(fp, ((pos - 1) * sizeof (struct satz))+(pos-1)*3, SEEK_SET);
     i = pos;
     }
     while (fread(&data, sizeof (struct satz), 1, fp) > 0 && (i == pos || pos == 0)) {
     printf("Datensatz %d: \n", i);
     printf("\t Name: %s", data.name);
     printf("\t Vorname: %s", data.vorname);
     printf("\t Adresse: %s", data.adresse);
     printf("\n");
     i++;
     }
     fclose(fp);
    }
    
    void readFileName(char* fname) {
     do {
     printf("Bitte geben Sie den Dateinamen ein!\n");
     scanf("%s60", fname);
     } while (strlen(fname) < 1);
     fflush(stdin);
    }
    
    int file_exists(char *file_name) {
     FILE *fp;
     if (fp = fopen(file_name, "r")) {
     fclose(fp);
     return 1;
     } else {
     return 0;
     }
    }
    
    
    Er ist bisher noch nicht fertig und ich weiß er ist für Anfänger,.. ^^ ich bin aber für Ratschläge immer offen.

    Mein Problem ist folgendes.

    Mein Struct vom typ Satz ist eigentlich meiner Meinung nach 100 byte groß.
    Wenn ich spezifische Datensätze auslese bei printDataSet(); habe ich aber das Problem das mein 2ter Datensatz bei (pos-1) * sizeof(struct satz) --> = 100 anfangen müsste.
    Jedoch fängt er erst bei
    (pos-1) * sizeof(struct satz) +(pos-1)*3 --> = 103,206,309,..... an,.....

    Wo kommen die 3 byte overhead her?

    Laut Komolitonen soltlen die eigentlich nicht da sein und bei ihm geht es wohl ohne diese Anweisung.

    Wo liegt der Fehler /rr/ ?;-)
     
  2. 9. Juni 2010
    AW: 3byte Overhead

    Hmm deine Komolitonen haben auch recht. Hab mal dein Code grad schnell mit Visual Studio 2008 Compiliert und dein Programm spuckt das Richtige aus:
    Datensatz -> Position:
    1 -> 0
    2 -> 100
    3 -> 200
    etc.

    Das wird wohl an deinem Compilier liegen, obwohl ich mir das auch nicht vorstellen kann, was für einen benutzt du?

    //Edit: Ok es wird wohl nicht am Compiler liegen sondern an der Datei die du verwendest zum aulsesen, hast du die Datei selbst erstellt oder ist diese Fertig vorgegeben bekommen?
    Am besten ladest du mal deine Testdatei mal hoch.

    Mfg Rushh0ur
     
  3. 9. Juni 2010
    Zuletzt von einem Moderator bearbeitet: 14. April 2017
    AW: 3byte Overhead

    Ich habe sie mittels dem Vorgängerprogramm erstellt und nun für dieses Projekt kopiert.
    Die alte Funktion zum schreiben eines neuen Datensatzes lautete:

    Code:
    void writeNewData(char* fname) {
     FILE *fp;
     fp = fopen(fname, "a+");
     struct satz data;
     printf("Bitte geben Sie den Namen an!\n");
     fgets(data.name, sizeof (data.name), stdin);
     fflush(stdin);
     printf("Bitte geben Sie den Voramen an!\n");
     fgets(data.vorname, sizeof (data.vorname), stdin);
     fflush(stdin);
     printf("Bitte geben Sie die Adresse an!\n");
     fgets(data.adresse, sizeof (data.adresse), stdin);
     fflush(stdin);
     fwrite(&data, sizeof (data), 1, fp);
     fclose(fp);
    }
    Compiler ist : MinGW

    Testdatei:
    No File | xup.in



    // ach ja, Rushour, das Programm spuckt zwar oben aus 100,200,300 etc, jedoch siehst du wenn du die beiden zeilen betrachtest :

    printf("sizeof mal pos : %d\n", (pos - 1) * sizeof (struct satz));
    und
    fseek(fp, ((pos - 1) * sizeof (struct satz))+(pos - 1)*3, SEEK_SET);

    das beim print nur das +(pos-1)*3 fehlt.

    Es werden also die Positionen 103,206,309 etc gelesen.
    Ausgegeben oben wird aber 100,200,300 so wie es sein sollte.
    Mein Fehler das nicht auch zu ändern um es aufzuzeigen....^^°
     
  4. 9. Juni 2010
    Zuletzt von einem Moderator bearbeitet: 14. April 2017
    AW: 3byte Overhead

    Ok hab mal deine Datei mit einem HEX-Editor geöffnet, es liegt wirklich an deiner Datei, deine drei char array sind jeweils um ein Byte zu groß rein geschrieben worden, vondaher die verschiebung um 3Bytes.

    Hier ein Bild wo man es deutlich sieht (Gelb: Überschuss):
    Bild

    Der Fehler liegt an deiner writeNewData function, find aber grad nicht den Fehler, ich meld mich sobald ich was hab, evtl hat jemand bis dahin ja schon die Lösung.

    Mfg Rushh0ur
     
  5. 9. Juni 2010
    AW: 3byte Overhead

    Kann es daran liegen das ich Trottel bisher das \n noch nicht rausgefiltert habe?
    das das in das Array mit reingeschrieben wird, oder sich dadurch das \0 verschiebt?!

    Aber das ist irghendwie so unlogisch ;D wenn ich 30byte array festlege kann es doch dann nicht auf einmal 31 belegen

    // find bisher einfach auch keinen Fehler :-/
     
  6. 9. Juni 2010
    AW: 3byte Overhead

    Hoi,

    ich könnte mir vorstellen, dass es daran liegt, dass die Member des structs im Speicher nicht unbedingt aufeinanderfolgen müssen, sondern dass da Platz dazwischen ist. Beim GCC gibts ein Attribut namens "packed", das genau das verhinden soll:
    gcc attribute overview
     
  7. 9. Juni 2010
    AW: 3byte Overhead

    Das lustige ist, mein Kommolitone nutzt ebenso MinGW und bei Ihm ist es wohl nicht so,... also sollte es doch eigentlich nicht am Compiler liegen oder?!

    Echt kein Plan noch woran es liegen kann
    Aber ich denke er wird mir seine Lösung erstmal wohl nicht geben wollen :-/
     
  8. 9. Juni 2010
    AW: 3byte Overhead

    @pyro
    Also die Daten die im Speicher sind, sind auch richtig im Speicher angeordnet, hab ich geprüft.

    @topic
    Ich hab aber festgestellt das die Function fwrite für den Bytewert 0x0A zwei Bytewerte, und zwar 0D und 0A schreibt. Warum das so ist verstehe ich nicht, das war bei mir noch nie der Fall. Oo

    Das kann doch nicht sein .... müssen evtl. iwelche Compiler-Direktiven gesetzt werden.

    Mfg Rushh0ur
     
  9. 9. Juni 2010
    AW: 3byte Overhead

    Oh, das kann gut sein, 0x0A steht für einen Zeilenumbruch (\n). Unter Windows besteht ein Zeilenumbruch aber aus einem \r gefolgt von einem \n. Deshalb ersetzt der Compiler das \n (==0x0A) mit einem \r\n (0x0D, 0x0A).
    Wie man das umgeht: keine Ahnung
     
  10. 9. Juni 2010
    AW: 3byte Overhead finden

    Äußerst interessant
    Ich glaube ich filter am Besten einfach das \n aus den Datensätzen heraus.
    das \n hat eigentlich keine Bedeutung ich war nur zu faul bisher es herauszuziehen
    ....
     
  11. 9. Juni 2010
    AW: 3byte Overhead

    1) öffne die Datei binär (so bekommst du den Inhalt wie er auch wirklich sein soll, ohne Austausch von \n etc)
    2) scanf > fgets, denn fgets liest auch den Zeilenumbruch mit ein
    3) deine structs sind uninitialisiert, memset() ist dein Freund
    4) die Testdatei ist, wie Rushh0ur gezeigt hat, schon voller Fehler^^

    mfg r90
     
  12. 9. Juni 2010
    AW: 3byte Overhead

    Mhh das ist lustig, es widersprechen sich doe Profis immer wieder,...
    ich hab jetzt schon bestimmt 8 Varianten gehört
    scanf>fgets
    fgets>scanf
    sscnaf > all
    *gets = fail
    *scan* = fail,....
    was ist denn nun richtig

    Ich wollte es halt erst mit scanf einlesen, doch dort fehlt mir die Möglichkeit der Begrenzung wenn ich richtig liege.

    1) kein plan wie das geht, hab mich bisher an die Vorlesung gehalten
    2)siehe absatz hierrüber
    3)structs initialisieren? Bitte erklär mal wofür bzw wo der Unterschied liegt, in der Vorlesung haben wirs noch nie genutzt / erwähnt bekommen :-/

    Ja den Fehler versuch ich gerade zu beheben indem ich die von fgets gelesenen Strings durchsuche und das \n durch \0 ersetze.

    Danke razor90, ich bin wirklich offen für Tips nur ich weiß echt nicht was ich machen soll wenn sich alle widersprechen oder ichs noch nicht beigebracht bekommen hab ^^°
     
  13. 10. Juni 2010
    AW: 3byte Overhead

    1) scanf("%30s", str); liest maximal 30 Zeichen ein und hört bei whitespaces auf

    2) Schau einfach nach, welche Funktion dir das bietet, was du brauchst. Klick! Ist zwar für C++, geht aber auch in C so.

    3) Wenn du eine struct deklarierst, wird der Speicher den sie belegt vorher nicht gelöscht. Deshalb sind in der Datei auch viele seltsame Zeichen. Es ist halt Praxis die Variablen vor der Nutzung zu initialisieren (da sollte der compiler auch ne Warnung ausspucken). Bei structs/arrays mit memset(&struct, 0, sizeof(struct)) und bei normalen Variablen mit = 0 oder whatever.
     
  14. 11. Juni 2010
    AW: 3byte Overhead finden

    Okay dann eine letzte Frgae bevor ich mal schließe.
    Ich brauche also eine Funktion die nur bestimmte Anzahl an Zeichen einliest MIT Leertaste!, also wie scanf und fgets und die KEIN \n einliest.

    Was nehmen ich nun :-/
     
  15. 11. Juni 2010
    AW: 3byte Overhead finden

    hatte das erst falsch verstanden ^^ dachte du willst einfach über leerzeichen hinweg einlesen, das kannst du mit fread ganz gut. aber fgets macht das ja auch...

    du kannst einfach dem index, wo das '\n' sitzt das '\0' zuweisen.

    deinString[strlen(deinString)-1]= '\0'
     
  16. 11. Juni 2010
    AW: 3byte Overhead finden

    Okay kann man daraus schließen das es keine Funktion gibt die das bequem erledigt?!
    Also , einlesen, mit ner max länge, mit whitespaces und ohne \n ?^ ^°
     
  17. 11. Juni 2010
    AW: 3byte Overhead finden

    ich befürchte nein ^^

    aber das selbst zu schreiben ist ein 3-zeiler einfach in ner selbstdefinierten funktion mit exakt den selben parametern wie fgets (nur mit anderem namen, weil c keine überladung kennt) halt fgets ganz normal aufrufen und den string nach der methode oben verkürzen.

    // was solls, mir is eh grad langweilig ^^

    Code:
    void fgetsAdvanced(char *str, int len, FILE *fp) {
     fgets(str, len, fp);
     str[strlen(str)-1]= '\0';
    }
     
    
     
  18. 11. Juni 2010
    AW: 3byte Overhead

    Omg, das gebts nicht kein schei** Seite betont das man zwischen zwei Modusen wählen kann: Binär und Text

    Der Wiki Eintrag hat mich wieder an die Lösung erinnert, und steht sogar in diesem drinn:
    C-Programmierung: Dateien – Wikibooks, Sammlung freier Lehr-, Sach- und Fachbücher

    Da die Daten im Textmodus geschrieben werden wird für manche Zeichen(Bytes) eine andere Byte-Sequenz geschrieben -> ein schreiben und lesen im Binärmodus löst das Problem.... ^^

    So sollte das öffnen durchgeührt werden, wenn man will das die Daten hargenau so in die Datei reinkommen wie sie auch im Arbeitsspeicher sind:
    Code:
    fp = fopen(fname, "a+[B][COLOR="Red"]b[/COLOR][/B]");
    
    Mfg Rushh0ur
     
  19. 11. Juni 2010
    AW: 3byte Overhead finden

    Das was du da machst, ist aber keine gute Idee
    strlen() findet die Länge des Strings raus, indem es alle Zeichen vor dem \0-Byte setzt. Du benutzt strlen() aber, um die stringlänge rauszufinden und setzt erst dann das 0-Byte ^^

    Das was Smokers sucht ist fread():
    Beispiel:
    Code:
    char data[30];
    size_t len = fread(data, 30, sizeof(char), fp);
    data[len] = '\0';
     
  20. 11. Juni 2010
    AW: 3byte Overhead finden

    stimmt, fread war schon richtig ^^ dickes fail

    die idee kam aus nem anderen zusammenhang, hatte das mal so verwendet als wir von der konsole eingelesen haben, da gehts dann natürlich auch weil \n durchs enter drücken noch im sring mit drin ist.
     
  21. Video Script

    Videos zum Themenbereich

    * gefundene Videos auf YouTube, anhand der Überschrift.