Zufällig eine Konstante aussuchen



  • Servus,
    da z.Zt. mal wieder etwas Langeweile angesagt ist, dachte ich mir ich schreibe mal ein kleines Quiz-Programm. Das Grundgerüst steht schon -> sprich Frage aussuchen, Antwort tippeln, Anwort vergleichen, Ausgabe ob richtig oder falsch.
    Jetzt ist es so, dass ich 5 Dateien hab:

    • 1 - questions.dat (beinhaltet die Fragen; eine Zeile entspr. eine Frage)
    • 2 - answers.dat (beinhaltet die Anworten; Formatierung wie questions.dat)
    • 3 - qoffsets.h (beinhaltet die Offsets der Fragen)
    • 4 - aoffsets.h (beinhaltet die Offsets der Antworten)
    • 5 - Quiz.c (na ja .. die Quelltextdatei halt)

    Wie schon gesagt, hab ich in den Dateien qoffsets.h und aoffsets.h die Offsets der Fragen bzw. Anworten festgehalten:

    /* qoffsets.h */
    #ifndef _QOFFSETS_H
    #define _QOFFSETS_H
    
    #define OFFSETQ1 0
    #define OFFSETQ2 61
    #define OFFSETQ3 81
    #define OFFSETQ4 130
    /* ... */
    
    #endif
    
    /* aoffsets.h */
    #ifndef _AOFFSETS_H
    #define _AOFFSETS_H
    
    #define OFFSETA1 0
    #define OFFSETA2 13
    #define OFFSETA3 22
    #define OFFSETA4 32
    /* ... */
    
    #endif
    

    Nun sieht die Quiz.c so aus, dass ich immer von Hand die entsprechende Frage eingeben muss:

    /* Quiz.c */
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #include "qoffsets.h" /*--- Headerdatei, welche die Offsets zu den Fragen beinhaltet ---*/
    #include "aoffsets.h" /*--- Headerdatei, welche die Offsets zu den Anworten beinhaltet ---*/
    
    const char* QFileName = "questions.dat";
    const char* AFileName = "answers.dat";
    
    int main( int argc, char* argv[] )
    {
       FILE* fp_QFile;
    
       char  QBuffer[1024];
       char* ABuffer;
    
       unsigned int lenAnswer = 0;
    
       if( argc != 1 )
       {
          fprintf( stdout, "Programm bitte ohne Parameter starten!\n" );
       }
    
       /*--- Datei die die Fragen beinhaltet oeffnen ---*/
       if( ( fp_QFile = fopen( QFileName, "rt" ) ) != NULL )
       {
          /*--- Dateiposition festlegen fuer Frage ---*/
          fseek( fp_QFile, OFFSETQ1, SEEK_SET );
    
          /*--- Frage auslesen ---*/
          if( ( fgets( QBuffer, sizeof( QBuffer ), fp_QFile ) ) != NULL )
          {
             fprintf( stdout, "Frage: %s\n\n", QBuffer );
    
             /*--- Speicherplatz fuer Antwort anfordern ---*/
             if( ( ABuffer = ( char* )malloc( 255 * sizeof( char ) ) ) != NULL )
             {
                fprintf( stdout, "Antwort: " );
                  scanf( "%[^\n]s", ABuffer );
    
                lenAnswer = strlen( ABuffer );
    
                /*--- Vergleichen ob Anwort richtig ist ---*/
                if( CompAnswer( ABuffer, lenAnswer ) == 0 )
                {
                   fprintf( stdout, "%s ist richtig!\n\n", ABuffer );
                }
    
                else
                {
                   fprintf( stdout, "\nFalsch!\n\n" );
                   return( -1 );
                }
             }
    
             else
             {
                perror( "(56)QuizGuard" );
                return( -1 );
             }
    
             /*--- Reservierten Speicherbereich wieder freigeben ---*/
             free( ABuffer );
          }
    
          else
          {
             perror( "(63)QuizGuard" );
             return( -1 );
          }
    
       }
    
       else
       {
          perror( "(70)QuizGuard" );
          return( -1 );
       }
    
       /*--- Datei die die Fragen beinhaltet schliessen ---*/
       fclose( fp_QFile );
    
       return( 0 );
    }
    
    int CompAnswer( const char* UAnswer, unsigned int lenAnswer )
    {
       char* ABuffer;
       FILE* fp_AFile;
    
       if( ( fp_AFile = fopen( AFileName, "rt" ) ) != NULL )
       {
          fseek( fp_AFile, OFFSETA1, SEEK_SET );
    
          if( ( ABuffer = ( char* )malloc( ( lenAnswer + 1 ) * sizeof( char ) ) ) != NULL )
          {
             if( ( fgets( ABuffer, sizeof( ABuffer ), fp_AFile ) ) != NULL )
                if( ( memcmp( ABuffer, UAnswer, strlen( ABuffer ) ) ) == 0 )
                   return( 0 );
          }
    
          else
          {
             perror( "(114)QuizGuard" );
             return( -1 );
          }
    
          free( ABuffer );
       }
    
       else
       {
          perror( "(95)QuizGuard" );
          return( -1 );
       }
    
       fclose( fp_AFile );
    
       return( -1 );
    }
    

    Jetzt wollte ich das eigentlich so machen, dass man irgendwie die Fragen zufällig auswählen lässt - über die Konstanten OFFSETQ1 usw.
    Natürlich sollten dann auch dementsprechend die Anworten richtig ausgewählt werden. Mir ist aber bisher keine wirklich gute Lösungsmöglichkeit eingefallen.

    Wüsste vielleicht jemand von euch Rat ?

    THX schon mal im Voraus

    edit: Falls ihr noch eventuell die Frage- bzw. Antwortdatei sehen wollte, poste ich sie gern 😉

    [ Dieser Beitrag wurde am 31.12.2002 um 14:11 Uhr von guard editiert. ]



  • Ich sehe gerade, dass es unter Windows nicht so recht laufen will. Hab es unter Linux MDK programmiert, dort lief es jedoch ohne Probleme 😉



  • Du machst Dir IMO zu viel Arbeit bei dem Problemchen. Von den ganzen Standard-C-Verletzungen mal abgesehen... Warum nicht eine Datei, die Fragen und Antworten beinhaltet und Dein Programm sucht zufällig ein passendes paar aus und präsentiert es dem Anwender?



  • Original erstellt von mady:
    Warum nicht eine Datei, die Fragen und Antworten beinhaltet und Dein Programm sucht zufällig ein passendes paar aus und präsentiert es dem Anwender?

    Ja wäre ja schon alles richtig, aber dann wäre es ja wieder nach ein paar Stunden fertig. Ich wollte mal wieder etwas schwerigeres erarbeiten 😉

    Von den ganzen Standard-C-Verletzungen mal abgesehen...
    Welche Verletzungen wäre denn das so ? Könntest du das bitte noch ein wenig erläutern, wäre dir sehr verbunden 🙂



  • Original erstellt von guard:
    Ja wäre ja schon alles richtig, aber dann wäre es ja wieder nach ein paar Stunden fertig. Ich wollte mal wieder etwas schwerigeres erarbeiten 😉

    Naja ... gib' Dir das doch mal: Einen text (eine einzelne Zeile) aus einer Datei zufällig auswählen, ohne die Datei mehrmals durchzulesen, oder einen Eintrag mit fseek() anzuspringen... 🙂

    Original erstellt von guard:
    Welche Verletzungen wäre denn das so ? Könntest du das bitte noch ein wenig erläutern, wäre dir sehr verbunden 🙂

    Gerne:

    1. Du castest einen void*-Zeiger. Das kann(!) zu Problemen führen.
    2. fopen(..., "rt") ist undefiniertes Verhalten.
    3. sizeof(char) ist IMMER 1.
    4. Dein Programm verursacht IMO 'Memory Leaks'. Als mit malloc() besorgter Speicher wird nicht immer freigegben.
    5. die ganzen Klammern bei return und sizeof sind zu einem großen Teil unnötig und können gefährlich werden.
    6. Bezeichner sollten nicht mit einen _ starten.
    7. fseek() in Textdateien kann in's Auge gehen....
    8. Bufferüberläufe bei Eingaben sind möglich ...

    So - mehr wollte ich jetzt nicht suchen ... :))

    PS: Bitte nicht negativ auffassen...



  • Original erstellt von mady:
    **So - mehr wollte ich jetzt nicht suchen ... :))

    PS: Bitte nicht negativ auffassen...**

    Hey mady ... bessers wärs gewesen, du hättest morgen gepostet 😉
    Jezz hab ich nimmer wirklich Lust zu feiern 😃

    Nee ... Spaß bei Seite. Ich werd das Dingen noch mal überarbeiten, und deine - durchaus konstruktive - Kritik berücksichtigen 😉 🙂

    Ich wünsch dir nen guten Rutsch ...



  • Original erstellt von guard:
    ...
    Ich wünsch dir nen guten Rutsch ...

    Danke - Dir auch. Und wenn noch Fragen sind, frag einfach oder mail. np. 🙂



  • 5. die ganzen Klammern bei return und sizeof sind zu einem großen Teil unnötig und können gefährlich werden.

    Das verstehe ich nicht. Wie kann das zu gefahren führen?



  • Original erstellt von <close>:
    Wie kann das zu gefahren führen?

    Vertippe dich bei einem 'return (12);' und schreibe 'retrun (12);'. Das Programm kompiliert nach C89 fehlerfrei. Beim Binden bekommst Du im günstigsten Fall einen Fehler; es kann allerdings passieren, dass Du eine Funktion hast, die retrun heißt aber in einer anderen Übersetztungseinheit definiert ist. Dein Programm liefert nun absolut falsche Ergebnisse und Du suchst den Fehler tagelang ... Bei 'retrun 12;' wäre das nicht passiert. Bei sizeof das gleiche.

    Außerdem ist es nicht sehr sinnvoll einen Ausdruck zusätzlich zu Klammern. Zum einen der Lesbarkeit wegen (((((1))) + (((2))) + (((3)))) oder 1 + 2 + 3) zum anderen gibt es in C immer noch so etwas wie eine maximale Klammerungstiefe :).



  • Original erstellt von mady:
    *1. Du castest einen void-Zeiger. Das kann(!) zu Problemen führen.
    2. fopen(..., "rt") ist undefiniertes Verhalten.
    3. sizeof(char) ist IMMER 1.
    4. Dein Programm verursacht IMO 'Memory Leaks'. Als mit malloc() besorgter Speicher wird nicht immer freigegben.
    5. die ganzen Klammern bei return und sizeof sind zu einem großen Teil unnötig und können gefährlich werden.
    6. Bezeichner sollten nicht mit einen _ starten.
    7. fseek() in Textdateien kann in's Auge gehen....
    8. Bufferüberläufe bei Eingaben sind möglich ...
    **

    So ... I'm back 😉

    Zu 1.: O.K. hast recht, obwohl manche Compiler eine Warnung auspucken, wenn man nicht castet
    Zu 2.: Geb ich dir auch recht. Wer weiß was da wieder in mir vorging
    Zu 3.: Kannst du mir das beweisen ? 🙄
    Zu 4.: Hab ich behoben
    Zu 5.: Sorry aber so hab ich mir das angeeignet 😉
    Zu 6.: Wieder was dazugelernt
    Zu 7.: Was Besseres fiehl mir da nicht ein ausser fgetpos & fsetpos und die mag ich nicht 😉
    Zu 8.: Bufferüberläufe habe ich jetzt weitestgehend vermieden

    Und genau zu dem 8ten Punkt hab ich eine Funzion readUString, die soweit einließt, bis ein man Enter drückt. Allerdings werden die Eingaben ohne Leerzeichen eingelesen. Ich geb erst mal die Funzion durch:

    int readUString( char** dest )
    {
       int ch = 0, slen = 0;
    
       *dest = malloc( 3 * sizeof( char ) );
       if( *dest == NULL )
       {
          perror( "QG" );
          if( *dest )
             free( *dest );
    
          return( -1 );
       }
    
       while( ( ch = fgetc( stdin ) ) != EOF )
       {
          if( ch == '\n' )
          {
             *dest = realloc( *dest, ( slen + 1 ) * sizeof( char ) );
    
             if( *dest != NULL )
             {
                ( *dest )[slen++] = '\0';
                return( slen );
             }
    
             else
             {
                if( *dest )
                   free( *dest );
    
                perror( "in readString" );
                return( -1 );
             }
          }
    
          if( isalnum( ch ) )
          {
             *dest = realloc( *dest, ( slen + 1 ) * sizeof( char ) );
    
             if( *dest != NULL )
             {
                ( *dest )[slen++] = ( char )ch;
             }
    
             else
             {
                if( *dest )
                   free( *dest );
    
                perror( "in readString" );   
                return( -1 );
             }
          }
       }
    
       return( -1 );
    }
    

    aufgerufen wird sie dann in einer anderen Funzion mit:

    /* ... */
    unsigned int lenUAnswer;
    char* UAnswer;
    /* ... */
    if( ( lenUAnswer = readUString( &( UAnswer ) ) ) == -1 )
    {
       fprintf( stderr, "%s: Fehler beim Einlesen der Antwort.\n", argv[0] );
       perror( "QG" );
       return( EXIT_FAILURE );
    }
    /* ... */
    

    btw: ich hab noch eine Funzion freeUString die den Speicher wieder freigibt 😉

    So ... nun zum Problem: es wird die Eingabe eingelesen -> gut, jedoch gespeichert ohne Leerzeichen -> schlecht. Bin bis jetzt noch auf keinen richtigen Pfad gekommen, wie man des anstellen könnte.

    Kann da jemand helfen ?

    thx mal wieder im voraus 🙂



  • Original erstellt von guard:
    **Zu 3.: Kannst du mir das beweisen ? 🙄
    **

    Koennen schon, wollen nicht.
    Es ist so - bin aber zu faul irgendwo einen Beweis zu suchen. Vertrau uns einfach 😉



  • Original erstellt von Shade Of Mine:
    [...]Vertrau uns einfach 😉

    ähem ... nagut. Schweren Herzens werd ich euch dann mal vertrauen. Gucke selbst aber auch noch mal in ein paar Dokus nach :p



  • Original erstellt von guard:
    [quote]Original erstellt von Shade Of Mine:
    [qb][...]Vertrau uns einfach 😉

    ähem ... nagut. Schweren Herzens werd ich euch dann mal vertrauen. Gucke selbst aber auch noch mal in ein paar Dokus nach :p[/QB][/QUOTE]Also - wenn's soooo schwer ist, dann lass Deinen Compiler den Sachverhalt beweisen:

    printf("-> %d", sizeof(char) * 100);
    


  • Original erstellt von mady:
    **Also - wenn's soooo schwer ist, dann lass Deinen Compiler den Sachverhalt beweisen:

    printf("-> %d", sizeof(char) * 100);
    

    **

    Also ich wollte euch hier echt nicht irgenwie anzweifeln, aber es gibt doch fast immer irgendwelche Ausnahmen. In diesem Fall aber anscheinend doch nicht 😃 ...

    Allerdings hab ich bisher immer noch keine Lösung für mein Problem mit dem Leerzeichen in der obigen Funktion 😞



  • Wieso rufst du sooft realloc auf? das ist doch lahm. arbeite zB immer mit 100er Bloecken oder so...

    isalnum() ist nur bei buchstaben und zahlen true - brauchst du vielleicht noch ein isspace()? oder was vielleicht besser waere -> isprint()?



  • Original erstellt von Shade Of Mine:
    **Wieso rufst du sooft realloc auf? das ist doch lahm. arbeite zB immer mit 100er Bloecken oder so...

    isalnum() ist nur bei buchstaben und zahlen true - brauchst du vielleicht noch ein isspace()? oder was vielleicht besser waere -> isprint()?**

    Also wenn du mir das so warm unter die Nase reibst ... haste ja auch irgendwie recht. Gut gut ... werd denn mal weiter dran herum werkeln 😉

    MfG


Anmelden zum Antworten