Beispielprogramme in C/Strukturiertes Programmieren mit C

Aus C64-Wiki
Zur Navigation springenZur Suche springen

Leicht erweiterte C-Version des Beispiels im Artikel Strukturiertes Programmieren mit BASIC

/*

    Program:  struct.c (cough cough)
    URL:      http://www.c64-wiki.de/index.php/Strukturiertes_Programmieren_mit_BASIC
    Compiler: cc65, gcc

100 INPUT "NAME DES 1. KANDIDATEN "; A$
110 INPUT "STIMMENANZAHL "; A
120 INPUT "NAME DES 2. KANDIDATEN "; B$
130 INPUT "STIMMENANZAHL "; B
140 INPUT "NAME DES 3. KANDIDATEN "; C$
150 INPUT "STIMMENANZAHL "; C
160 LET S = A+B+C
170 LET A1 = A*100/S
180 LET B1 = B*100/S
190 LET C1 = C*100/S
200 PRINT "KANDIDAT ";A$; " ERHIELT";A1;"%"
210 PRINT "KANDIDAT ";B$; " ERHIELT";B1;"%"
220 PRINT "KANDIDAT ";C$; " ERHIELT";C1;"%."

*/

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

struct Kandidat_s
{
  uint8_t Name[200];
  uint32_t Stimmen;
};

struct Kandidat_s Kandidat;
struct Kandidat_s *Kandidat_p;
uint8_t String[200];
uint16_t anzahlKandidaten, Zaehler;
uint32_t abgegebeneStimmen = 0;

void p_reset()
{
  for (Zaehler = 0; Zaehler < anzahlKandidaten; ++Zaehler) --Kandidat_p;
}

void aufraeumen()
{
  p_reset();
  free(Kandidat_p);
}

void KandidatenEingabe(uint16_t Zaehler, struct Kandidat_s *Kandidat_p)
{
    printf("\r\nName des %d. Kandidaten? ", Zaehler+1);
    fgets(String, 200, stdin);
    String[strcspn ( String, "\n\r" )] = '\0';
    strcpy(Kandidat_p->Name, String);

    printf("\r\nStimmenanzahl? ");
    fgets(String, 16, stdin);
    Kandidat_p->Stimmen = atol(String);

    abgegebeneStimmen += Kandidat_p->Stimmen;
}

void Stimmerfassung()
{
  printf("\r\nAnzahl der Kandidaten: ");
  fgets( String, 3, stdin );
  anzahlKandidaten = (uint8_t) atoi(String);

  Kandidat_p = malloc(anzahlKandidaten * sizeof(Kandidat));

  for (Zaehler = 0; Zaehler < anzahlKandidaten; ++Zaehler)
  {
    KandidatenEingabe(Zaehler, Kandidat_p);
    ++Kandidat_p;
  }
}

void Stimmauszaehlung()
{

  p_reset();

  printf("\r\nAbgegebene Stimmen %ld: \r\n",abgegebeneStimmen);


  for (Zaehler = 0; Zaehler < anzahlKandidaten; ++Zaehler)
  {
    printf("Kandidat %s erhielt %ld%%\r\n", Kandidat_p->Name,
            Kandidat_p->Stimmen*100/abgegebeneStimmen);

    ++Kandidat_p;
  }
}

void main(void)
{

  Stimmerfassung();
  Stimmauszaehlung();
  aufraeumen();

}

Nochmal etwas erweitertes Beispiel mit Fehlerbehandlung, sortierter Kandidatenausgabe und Prozentausgabe mit einer Nachkommastelle:

/**
 * Beispiel eines Stimmenauszähl-Programms.
 * 
 * Die Anzahl der Kandidaten ist flexibel — der Speicher wird zur
 * Laufzeit verwaltet.
 * 
 * Es wird gezeigt, wie man auch ohne Gleitkommatypen Prozentzahlen mit
 * einer Nachkommastalle realisieren kann.
 * 
 * Ferner werden die Kandidaten vor der Ausgabe absteigend nach Stimmen
 * sortiert.
 * 
 * Ausserdem wurde versucht, auf Fehleingaben vom Benutzer zu reagieren,
 * damit das Programm nicht abstürzt oder unsinnige Werte anzeigt.
 * 
 * \TODO Es wird nicht überprüft, ob ein eingegebener Name leer ist oder
 *      bereits in den Kandidaten enthalten ist.
 */
#include <assert.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_NAME_LENGTH                 100
/*
 * Die Stimmen werden mit 1000 multipliziert, um eine Nachkommastelle
 * zu bekommen, deshalb darf die Anzahl pro Kandidat nicht so gross werden,
 * dass dadurch ein Überlauf entsteht.
 */
#define MAX_STIMMEN_PRO_KANDIDAT        (INT32_MAX / 1000)

#if ((INT32_MAX / MAX_STIMMEN_PRO_KANDIDAT) < 256)
    #error "Aufsummieren koennte zu Ueberlauf von Gesamtstimmen fuehren"
#endif

typedef int (*compare_func_t)(const void*, const void*);

/**
 * \invariant stimmen <= MAX_STIMMEN_PRO_KANDIDAT
 */
typedef struct {
    char name[MAX_NAME_LENGTH];
    int32_t stimmen;
} Kandidat;

typedef struct {
    uint8_t anzahl;
    Kandidat *data;
} Kandidaten;


void remove_trailing_newline(char *s)
{
    char *ptr = s + strlen(s);
    if (ptr != s && ptr[-1] == '\n') ptr[-1] = '\0';
}

int Kandidat_compare(const Kandidat *a, const Kandidat *b)
{
    int32_t result = b->stimmen - a->stimmen;
    if (!result) return strcmp(a->name, b->name);
    return result < 0 ? -1 : 1;
}

Kandidaten* Kandidaten_init(Kandidaten *kandidaten, uint8_t anzahl)
{
    if ((kandidaten->data = calloc(anzahl, sizeof(*kandidaten->data)))) {
        kandidaten->anzahl = anzahl;
        return kandidaten;
    } else {
        kandidaten->anzahl = 0;
        return NULL;
    }
}

void Kandidaten_free(Kandidaten *kandidaten)
{
    assert(kandidaten);
    kandidaten->anzahl = 0;
    free(kandidaten->data);
}

_Bool Kandidaten_eingabe(Kandidaten *kandidaten)
{
    uint8_t i;
    int16_t anzahl;
    int32_t stimmen;
    Kandidat *kandidat;
    char buffer[20];
    
    assert(kandidaten);
    
    printf("Anzahl der Kandidaten: ");
    fgets(buffer, sizeof(buffer), stdin);
    anzahl = atoi(buffer);
    putchar('\n');
    
    if (anzahl < 1) {
        puts("Weniger als 1 Kandidat ist sinnlos.");
        return false;
    }
    
    if (!Kandidaten_init(kandidaten, anzahl)) {
        puts("Konnte Kandidaten nicht initialisieren.");
        return false;
    }
    
    for (i = 0; i < kandidaten->anzahl; ++i) {
        kandidat = &kandidaten->data[i];
        printf("\nName des %d. Kandidaten: ", i + 1);
        fgets(kandidat->name, sizeof(kandidat->name), stdin);
        remove_trailing_newline(kandidat->name);
        
        while (true) {
            printf("\nStimmenanzahl: ");
            fgets(buffer, sizeof(buffer), stdin);
            stimmen = atol(buffer);
            if (stimmen < 0) {
                puts("\nStimmanzahl muss >=0 sein!");
                continue;
            }
            if (stimmen > MAX_STIMMEN_PRO_KANDIDAT) {
                printf(
                    "\nPro Kandidat max %"PRIu32" Stimmen!",
                    MAX_STIMMEN_PRO_KANDIDAT
                );
                continue;
            }
            kandidat->stimmen = stimmen;
            break;
        }
        putchar('\n');
    }
    return true;
}

void Kandidaten_sort(Kandidaten *kandidaten)
{
    assert(kandidaten);
    qsort(
        kandidaten->data,
        kandidaten->anzahl,
        sizeof(*kandidaten->data),
        (compare_func_t) Kandidat_compare
    );
}

void Kandidaten_auswerten(Kandidaten *kandidaten)
{
    uint8_t i;
    int32_t stimmen, gesamt_stimmen;
    div_t percent;
    Kandidat *kandidat;

    assert(kandidaten);
    
    for (i = 0; i < kandidaten->anzahl; ++i) {
        stimmen = kandidaten->data[i].stimmen;
        assert(stimmen <= MAX_STIMMEN_PRO_KANDIDAT);
        gesamt_stimmen += stimmen;
    }
    assert(gesamt_stimmen >= 0);
    printf("\nAbgegebene Stimmen: %"PRIu32"\n", gesamt_stimmen);
    
    if (gesamt_stimmen) {
        Kandidaten_sort(kandidaten);
        for (i = 0; i < kandidaten->anzahl; ++i) {
            kandidat = &kandidaten->data[i];
            percent = div(kandidat->stimmen * 1000 / gesamt_stimmen, 10);
            assert(
                percent.quot >= 0 && percent.quot <= 100
                && percent.rem >= 0 && percent.rem <= 9
            );
            printf(
                " %2d.%01d%% fuer %s\n",
                percent.quot,
                percent.rem,
                kandidat->name
            );
        }
    }
}

int main(void)
{
    Kandidaten kandidaten;
    
    if (Kandidaten_eingabe(&kandidaten)) {
        Kandidaten_auswerten(&kandidaten);
        Kandidaten_free(&kandidaten);
    }
    return 0;
}