C-Programm & Cflags

Ich habe vor einiger Zeit das Prinzip von Makefiles anhand eines kleines Beispiels gezeigt -> http://suckup.de/howto/c/c-programm-primzahlen-makefiles/ <- den selben Quelltext kompilieren wir heute mit verschiedenen C-Flags und 1000000 Schleifendurchläufen …

 

1.)  ohne C-Flags

gcc -lm primzahlen.c -o primzahlen_slow

 

Output: time ./primzahlen_slow

[...]

999961
999979
999983

real 0m1.760s
user 0m1.420s
sys 0m0.164s

 

2.)  ohne C-Flags & ohne “math.h” (sqrt)

gcc primzahlen.c -o primzahlen_slow

 

Output: time ./primzahlen_slow

[...]

999961
999979
999983

real 0m1.407s
user 0m0.988s
sys 0m0.192s

 

3.)  -O2 & ohne “math.h” (sqrt)

gcc -O2 primzahlen.c -o primzahlen_2

 

Output: time ./primzahlen_slow

[...]

999961
999979
999983

real 0m1.405s
user 0m0.976s
sys 0m0.188s

 

4.) -Ofast (http://gcc.gnu.org/gcc-4.6/changes.html) & ohne “math.h” (sqrt)

gcc -Ofast primzahlen.c -o primzahlen_fast

 

Output: time ./primzahlen_fast

[...]

999961
999979
999983

real 0m1.377s
user 0m0.980s
sys 0m0.180s

 

5.) -Ofast + amdfam10 (http://en.gentoo-wiki.com/wiki/Safe_Cflags/AMD#Athlon_X2_7x50.2C_Phenom_X3.2FX4.2C_Phenom_II.2C_Athlon_II_X2.2FX3.2FX4

Ein paar spezielle CFlags für meine CPU. :) (cat /proc/cpuinfo)

gcc -Ofast -funsafe-math-optimizations -funsafe-loop-optimizations -m64 -mtune=amdfam10 -mabm -msse4a -floop-parallelize-all -ftree-parallelize-loops=4 -floop-strip-mine -floop-block -funroll-all-loops -fbranch-target-load-optimize -lm primzahlen.c -o primzahlen_fast

 

Output: time ./primzahlen_fast

[...]

999961
999979
999983

real 0m1.327s
user 0m0.944s
sys 0m0.172s

 

Fazit: 

Sobald ich -O1, -O2, -O3 oder -Ofast bei diesem kleinen Beispiel nutze ist der Geschwindigkeitsunterschied minimal und es ist egal, ob vorgefertigte mathematische Funktionen genutzt werden oder nicht.

C-Programm – einfacher Taschenrechner

Hier mal wieder ein einfaches Beispiel in C mit “Struktogramm” & “Programmablaufplan” & “Pseudocode” …

 

Pseudocode:

begin
    Eine 'einfache' Rechenaufgabe (z.B. 5+5) eingeben.
    Aufteilung der Eingabe in (drei) Variablen [ein1, ein2, ein3]
    case ein2 is
        +: Addition: "ein1" & "ein3"
        -: Subtraktion: "ein1" & "ein3"
        *: Multiplikation: "ein1" & "ein3"
        /: Division: "ein1" & "ein3"
        %: Modulo: "ein1" & "ein3"
        otherwise: Ausgabe: "Fehler in der Berechnung"
    end case
    Ausgabe: Ergebnis
end

 

Programmiersprache C:

#include <stdio.h> 
#define MAXLENGTHSTR 255

int main(void)
{
  /* Deklaration der Variablen */
  int ein1, ein3, aus;
  char ein2;
  char s1[MAXLENGTHSTR];

  printf("z.B.: \"1 + 2\" oder \"5 + 5\" eingeben!!!"); 
  /* Usereingabe */
  printf("Eingabe: ");
  /* flushall(); gets(s1); */
  gets(s1);

  /* Interne Verarbeitung des Input */
  sscanf(s1, "%d %c %d", &ein1, &ein2, &ein3);
  aus = 0;

  /* Berechnung */
  switch(ein2)
  {
    case '+': aus = ein1 + ein3; break; /* Addition */
    case '-': aus = ein1 - ein3; break; /* Subtraktion */
    case '*': aus = ein1 * ein3; break; /* Multiplikation */
    case '/': aus = ein1 / ein3; break; /* Division */
    case '%': aus = ein1 % ein3; break; /* Modulo */
    default: printf("   Input error!\n"); break;
  }
 
  /* Ausgabe */
  printf("Ergebnis: %d\n", aus);

  /* Ende */
  return 0;
}

Optimierungen von Android unter Linux nutzen

Vor einiger Zeit habe ich ein kleines Shell-Script (SSSwitch – auto-switch settings) geschrieben, welches mein Android Handy beim Start optimiert und die Kernel-Einstellungen anpasst, wenn der Bildschirm an bzw. aus ist. Einige der Einstellungen kann man auch unter Linux verwenden. Als Beispiel beschreibe ich hier kurz, wie man die I/O Leistung verbessern kann und wer allgemein etwas zum optimieren von Linux / Ubuntu lesen möchte, dem hilft ggf. folgender Blog-Post weiter -> SpeedUp-Ubuntu ;)

 

Ein Ausschnitt aus dem besagtem Skript …

# =========
# One-time tweaks to apply on every boot;
# =========
STL=`ls -d /sys/block/stl*`;
BML=`ls -d /sys/block/bml*`;
MMC=`ls -d /sys/block/mmc*`;

… hier wurde der externe / interne Speicher von Android angegeben unter meinem Linux-System würde ich hier also z.B. folgendes angeben.

SDA=`ls -d /sys/block/sda/*`;

# =========
# Remount all partitions
# =========
for k in $(busybox mount | cut -d " " -f3);
do
	sync;
	busybox mount -o remount,noatime,nodiratime $k;
done;

“atime – Update inode access time for each access. See also the strictatime mount option.” – man mount Hier schalten wir die Funktion aus, welche aufzeichnet wann ein Datei oder Verzeichnis zuletzt angesehen wurde, da wir diese Funktionalität unter Android selten benötigen werden. ;) Ggf. kann man diesen Abschnitt komplett so unter Linux / Ubuntu verwenden z.B.:

mount
/dev/sda5 on / type ext4 (rw,errors=remount-ro,commit=0)
[...]
/dev/sda3 on /boot type ext2 (rw)
/dev/sda6 on /home type ext4 (rw,commit=0)
[...]
for k in $(busybox mount | cut -d " " -f3); do sync; mount -o remount,noatime,nodiratime $k; done;
mount
/dev/sda5 on / type ext4 (rw,noatime,nodiratime,errors=remount-ro)
[...]
/dev/sda3 on /boot type ext2 (rw,noatime,nodiratime)
/dev/sda6 on /home type ext4 (rw,noatime,nodiratime)
[...]

… wie man sieht sind die neuen Mount-Optionen nun aktiv. Wer mehr dazu erfahren möchte findet in dem bereits erwähnten “SpeedUp Ubuntu“-Beitrag unter dem Punkt “3.1) Filesystem” mehr Infos.

# =========
# check enabled/disabled status for IO settings
# =========
if [ "$IO_SETTINGS_ENABLED" -eq "1" ];
then
	# =========
	# Optimize non-rotating storage
	# =========
	for i in $STL $BML $MMC;
	do
		/system/xbin/echo "1" > $i/queue/iosched/rq_affinity;
		/system/xbin/echo "1" > $i/queue/iosched/low_latency;
		/system/xbin/echo "64" > $i/queue/max_sectors_kb;
		/system/xbin/echo "$READ_AHEAD_ALL" > $i/queue/read_ahead_kb;
	done;

Hier legen wir unter anderem die Puffergröße von unseren Speichermedien ein. Als Beispiel zeige ich kurz wie sich der Buffer auf die Lesegeschwindigkeit auswirkt, wenn eine Datei z.B. erneut geöffnet wird. ;) Dazu benötigen wir zuerst einen Compiler (gcc)

sudo apt-get install gcc

Nun den folgenden Quelltext kopieren …

#include 
#include <stdio.h>
#include <unistd.h>
#include <sys/times.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

#define MAX_PUFFER_GROESSE 1<<14
// Ausgabe
static void zeit_ausgabe(long int puff_groesse, clock_t realzeit, struct tms *start_zeit, struct tms *ende_zeit, long int schleiflaeufe);

int main(void) {
    char puffer[MAX_PUFFER_GROESSE];
    ssize_t n;
    long int i, j=0, puffer_groesse, opt_puffer;
    struct tms start_zeit, ende_zeit;
    static long ticks=0;
    clock_t uhr_start, uhr_ende, system_cpu=0.0;

    // Ausgabe
    fprintf(stderr, "+--------------+-------------+--------------+--------------+--------------+\n");
    fprintf(stderr, "| %-10s | %-10s | %-10s | %-10s | %-10s |\n",
                    "Puffer-", "UserCPU", "SystemCPU", "Gebrauchte", "Schleifen-");
    fprintf(stderr, "| %10s | %10s | %10s | %10s | %10s |\n",
                    " groesse", " (Sek)", " (Sek)", " Uhrzeit", " laeufe");
    fprintf(stderr, "+--------------+-------------+--------------+--------------+--------------+\n");

    while (j <= 14) {
        i=0;
        puffer_groesse=1<<j;
        if (lseek(STDIN_FILENO, 0L, SEEK_SET) == -1) {
            fprintf(stderr, "Error: lseek");
            exit(1);
        }
        if (lseek(STDOUT_FILENO, 0L, SEEK_SET) == -1) {
            fprintf(stderr, "Errir: lseek");
            exit(1);
        }
        if ( (uhr_start = times(&start_zeit)) == -1) {
            fprintf(stderr, "Error: times");
            exit(2);
        }
        while ( (n=read(STDIN_FILENO, puffer, puffer_groesse)) > 0) {
            if (write(STDOUT_FILENO, puffer, n) != n) {
                fprintf(stderr, "Error: write");
                exit(3);
            }
            i++;
        }
        if (n < 0) {
            fprintf(stderr, "Error: read");
            exit(4);
        }
        if ( (uhr_ende = times(&ende_zeit)) == -1) {
            fprintf(stderr, "Error: times");
            exit(5);
        }

        if (ticks == 0) {
            if ( (ticks = sysconf(_SC_CLK_TCK)) < 0) {
                fprintf(stderr, "Error: sysconf");
                exit(6);
            }
        }
        // Ausgabe
        zeit_ausgabe(puffer_groesse, uhr_ende-uhr_start, &start_zeit, &ende_zeit, i);
        j++;
    }
    exit(0);
}

// Ausgabe
static void zeit_ausgabe(long int puff_groesse, clock_t realzeit, struct tms *start_zeit, struct tms *ende_zeit, long int schleiflaeufe) {
    static long ticks=0;
    if (ticks == 0) {
        if ( (ticks = sysconf(_SC_CLK_TCK)) < 0) {
            fprintf(stderr, "Error: sysconf");
            exit(6);
        }
    }
    fprintf(stderr, "| %10ld | %10.2f | %10.2f | %10.2f | %10ld |\n", puff_groesse, (ende_zeit->tms_utime - start_zeit->tms_utime) / (double)ticks, (ende_zeit->tms_stime - start_zeit->tms_stime) / (double)ticks, realzeit / (double)ticks, schleiflaeufe);
    return;
}

… und in eine leere Datei (io_speed_buffer.c) einfügen, nun compilieren wir noch schnell das Programm mit folgendem Befehl …

gcc io_speed_buffer.c -o io_speed_buffer

… als nächsten benötigen wir eine etwa 10 MB große Datei als Eingabe, diese erzeugen wir mittels “dd” im aktuellen Verzeichnis.

dd if=/dev/zero of=./test count=20000

Und schon können wir mittels folgenden Befehl die optimale Buffer-Größe herausfinden. Wobei man bei minimaler Verbesserung nicht den höheren Wert nutzen sollte.

z.B.:

./io_speed_buffer <test >test2
+--------------+-------------+--------------+--------------+--------------+
| Puffer-    | UserCPU    | SystemCPU  | Gebrauchte | Schleifen- |
|    groesse |      (Sek) |      (Sek) |    Uhrzeit |     laeufe |
+--------------+-------------+--------------+--------------+--------------+
|          1 |       0.48 |      10.41 |      10.90 |   10240000 |
|          2 |       0.26 |       3.40 |       3.66 |    5120000 |
|          4 |       0.19 |       1.64 |       1.83 |    2560000 |
|          8 |       0.12 |       0.80 |       0.92 |    1280000 |
|         16 |       0.01 |       0.46 |       0.47 |     640000 |
|         32 |       0.03 |       0.20 |       0.23 |     320000 |
|         64 |       0.00 |       0.12 |       0.12 |     160000 |
|        128 |       0.00 |       0.07 |       0.07 |      80000 |
|        256 |       0.00 |       0.04 |       0.04 |      40000 |
|        512 |       0.00 |       0.02 |       0.02 |      20000 |
|       1024 |       0.00 |       0.02 |       0.02 |      10000 |
|       2048 |       0.00 |       0.01 |       0.01 |       5000 |
|       4096 |       0.00 |       0.00 |       0.00 |       2500 |
|       8192 |       0.00 |       0.01 |       0.01 |       1250 |
|      16384 |       0.00 |       0.01 |       0.01 |        625 |

Standardmäßig ist der Wert “128” gesetzt …

cat /sys/block/sda/queue/read_ahead_kb
128

… welchen wir jedoch leicht ändern können! ;)

sudo echo "256" > /sys/block/sda/queue/read_ahead_kb
cat /sys/block/sda/queue/read_ahead_kb
256

Ggf. kann man diese Einstellungen auch unter Linux direkt beim start ausführen lassen z.B. könnte man den zuvor gezeigten “echo”-Befehl in der “rc.local”-Datei einfügen. (/etc/rc.local)

	# =========
	# Optimize io scheduler
	# =========
	for i in $STL $BML $MMC;
	do
		/system/xbin/echo "$IO_SCHEDULER" > $i/queue/scheduler;

Welcher I/O Scheduler der beste für das Speichermedium ist kann man am betesten selber testen, indem man z.B. wieder den “dd”-Befehl verwendet. -> [Discussion] SSSwitch – auto-switch settings PS: Für mein Android-System nutze ich momentan “bfq” wobei “noop” gerade für SSD-Speichermedien schneller sein soll …

		case $IO_SCHEDULER in
		"cfq")
    		        /system/xbin/echo "0" > $i/queue/rotational;
      		        /system/xbin/echo "1" > $i/queue/iosched/back_seek_penalty;
      		        /system/xbin/echo "1" > $i/queue/iosched/low_latency;
     		        /system/xbin/echo "3" > $i/queue/iosched/slice_idle;
      		        /system/xbin/echo "16" > $i/queue/iosched/quantum;
      		        /system/xbin/echo "2048" > $i/queue/nr_requests;
			/system/xbin/echo "1000000000" > $i/queue/iosched/back_seek_max;;
		"bfq")
			/system/xbin/echo "0" > $i/queue/rotational;
			/system/xbin/echo "1" > $i/queue/iosched/back_seek_penalty;
			/system/xbin/echo "1" > $i/queue/iosched/low_latency;
			/system/xbin/echo "3" > $i/queue/iosched/slice_idle;
			/system/xbin/echo "16" > $i/queue/iosched/quantum;
			/system/xbin/echo "2048" > $i/queue/nr_requests;
			/system/xbin/echo "1000000000" > $i/queue/iosched/back_seek_max;;
		"noop")
			/system/xbin/echo "4" > $i/queue/iosched/quantum;
			/system/xbin/echo "16" > $i/queue/iosched/fifo_batch;
			/system/xbin/echo "248" > $i/queue/nr_requests;;
		"deadline")
			/system/xbin/echo "1" > $i/queue/iosched/front_merges;
      		        /system/xbin/echo "16" > $i/queue/iosched/fifo_batch;;
		"sio")
      		        /system/xbin/echo "1" > $i/queue/iosched/front_merges;
			/system/xbin/echo "4" > $i/queue/iosched/quantum;
			/system/xbin/echo "16" > $i/queue/iosched/fifo_batch;
			/system/xbin/echo "256" > $i/queue/nr_requests;;
		esac;
[...]
	done;
[...]
fi;

Hier noch ein-wenig Feintuning für die entsprechenden I/O Scheduler ;) ggf. müssen diese Werte auf anderen Systemen (Hardware) angepasst werden, dies habe ich bisher nur auf meinem Android System getestet. Falls euch / jemanden dieser Blog-Beitrag gefallen hat, werde ich weitere Einstellungen von dem Skript erklären … :)

C-Programm – String (char) kopieren

Hier einige Möglichkeiten, einen String zu kopieren … :-)

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

/* --- 1. strcpy mit Arrays --- */
char *strcpy1(char ziel[], const char quelle[]) {
    int zahl = 0;
    // solange Zeichen von der Quelle vorhanden sind,
    // also quelle[zahl] ungleich 0 ist ...
    // (letztes Zeichen eines Strings ist immer \0 -> =0 -> false)
    while(quelle[zahl]) {
    // der Buchstabe aus dem Quell-Array wird
    // an die selbe Stelle ([zahl]) im Ziel-Array geschrieben
        ziel[zahl] = quelle[zahl];
    // zahl wird um 1 erhöht (zahl=zahl+1)-> nächster Buchstabe
        zahl++;
    }
    // der neue Sting wird abgeschlossen
    ziel[zahl] = '\0';
    return(ziel);
}

/* --- 2. strcpy mit Arrays --- */
char *strcpy2(char ziel[], const char quelle[]) {
    int zahl = 0;
    // solange der Buchstabe aus dem Quell-Array an die selbe Stelle ([zahl])
    // im Ziel-Array geschrieben werden kann, also quelle[zahl] ungleich 0 ist ...
    // (letztes Zeichen eines Strings ist immer \0 -> =0 -> false)
    while((ziel[zahl] = quelle[zahl]))
    // zahl wird um 1 erhöht (zahl=zahl+1) -> nächster Buchstabe
        zahl++;
    return(ziel);
}

/* --- 3. strcpy mit Zeigern --- */
char *strcpy3(char *ziel, const char *quelle) {
    // solange der Buchstabe vom Quell-Zeiger auf die selbe Stelle
    // vom Ziel-Zeiger zeigt ...
    // (letztes Zeichen eines Strings ist immer \0 -> =0 -> false)
    while((*ziel = *quelle)) {
    // Zeiger um einen erhöhen -> nächste Speicherstelle -> nächster Buchstabe 
        ziel++;
        quelle++;
    }
    return(ziel);
}

/* --- 4. strcpy mit Zeigern --- */
char *strcpy4(char *ziel, const char *quelle) {
    // solange der Buchstabe vom Quell-Zeiger auf die selbe Stelle
    // vom Ziel-Zeiger zeigt, so werden diese jedesmal um 1 erhöht ...
    // (letztes Zeichen eines Strings ist immer \0 -> =0 -> false)
    while((*ziel++ = *quelle++));
    return(ziel);
}


int main(void) {
    char *gruss = "Hallo Welt";
    char gruss1[100];
    char gruss2[100];
    char gruss3[100];
    char gruss4[100];
    char gruss5[100];

/* --- 1. strcpy mit Arrays --- */
    strcpy1(gruss1, gruss);
    printf("%s\n", gruss1);
/* --- 2. strcpy mit Arrays --- */
    strcpy2(gruss2, gruss);
    printf("%s\n", gruss2);
/* --- 3. strcpy mit Zeigern --- */
    strcpy3(gruss3, gruss);
    printf("%s\n", gruss3);
/* --- 4. strcpy mit Zeigern --- */
    strcpy4(gruss4, gruss);
    printf("%s\n", gruss4);
/* --- 5. strcpy -> <string.h> --- */
    strcpy(gruss5, gruss);
    printf("%s\n", gruss5);

    return(0);
}

C-Programm – check_mem für Nagios

Habe gerade ein kleines C-Programm geschrieben, welches mithilfe von Nagios / Icinga die Speicherauslastung (Arbeitsspeicher + Swap) eines Linux-Servers überprüfen kann. Wenn ein Server seine aktuell laufenden Programm auf der Festplatte auslagern muss, da zu wenig Arbeitsspeicher zur Verfügung steht, sollte man darüber ggf. informiert werden… :-)

/*****************************************************************************
* 
* Nagios check_mem plugin
* 
* License: GPL
* Copyright (c) 2000 Karl DeBisschop (kdebisschop@users.sourceforge.net)
* Copyright (c) 2000-2007 Nagios Plugins Development Team
* Copyright (c) 2011 Lars Moelleken (voku@voku-online.de)
* 
* Description:
* 
* This file contains the check_mem plugin
* 
* 
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
* 
* 
*****************************************************************************/

const char *progname = "check_mem";
const char *NP_VERSION = "0.1";
const char *copyright = "2011";
const char *email = "voku@voku-online.de";

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/sysinfo.h>

void print_usage (void);
void print_help (void);


int main (int argc, char *argv[]) {
    long total = 0, free_total = 0, used_total = 0;
    long total_mem = 0, free_mem = 0, used_mem = 0;
    long total_swap = 0, free_swap = 0, used_swap = 0;
    struct sysinfo meminfo;

    char *warn_percent = NULL;
    char *crit_percent = NULL;

    int STATE_OK = 0;
    int STATE_WARNING = 1;
    int STATE_CRITICAL = 2;
    int STATE_UNKNOWN = 3;
    int result = 0;

     if (argc < 2) {
        print_help();
        printf("Hilfe anzeigen lassen: %s -h\n", argv[0]);
        exit(STATE_UNKNOWN);
    }

    char option;
    while((option = getopt(argc, argv, "hwc:")) != EOF) {
        switch(option) {
            case 'h':
                print_help();
                break;
            case 'w':
                warn_percent = argv[2];
                break;
            case 'c':
                crit_percent = argv[4];
                break;
            case ':':
                printf("option needs a value\n");
                break;
            case '?':
                printf("unknown option: %c\n", optopt);
                break;
        }
    }

    if(sysinfo(&meminfo) !=0) {
        perror("Fehler ...");
    }

    total_mem = meminfo.totalram;
    free_mem = meminfo.freeram;
    used_mem = meminfo.totalram - meminfo.freeram;

    total_swap = meminfo.totalswap;
    free_swap = meminfo.freeswap;
    used_swap = meminfo.totalswap - meminfo.freeswap;

    total = total_mem + total_swap;
    free_total = free_mem + free_swap;
    used_total = used_mem + used_swap;

    if (free_swap < total_swap/2 || free_total < total / 100 * atoi(crit_percent)) {
        printf("CRITICAL > ");
        result = STATE_CRITICAL;
    } else if (free_total < total / 100 * atoi(warn_percent)) {
        printf("WARNING > ");
        result = STATE_WARNING;
    } else {
        result = STATE_OK;
        printf("OK > ");
    }
    printf("Free Mem+Swap: %ld - Free Mem: %ld - Free Swap: %ld", free_total/1024/1024, free_mem/1024/1024, free_swap/1024/1024); // test-Ausgabe
    return result;
}


void print_help (void) {
    printf ("%s\n", "Check memory on local machine.");

  printf ("\n");

    print_usage ();

  printf (" %s\n", "-w PERCENT%%");
  printf ("    %s\n", "Exit with WARNING status if less than PERCENT of mem/swap space is free");
  printf (" %s\n", "-c PERCENT%%");
  printf ("    %s\n", "Exit with CRITCAL status if less than PERCENT of mem/swap space is free");
    printf ("\n");
}


void print_usage (void) {
  printf ("%s -w <percent_free>%% -c <percent_free>%%\n",progname);
}

C-Programm – neueste Datei eines Verzeichnisses (Linux)

Unter Linux kann man mit dem folgendem Befehl anzeigen lassen, welche die neuste Datei ist…

ls -1tr --group-directories-first /path/to/dir/ | tail -n 1

… habe gerade versucht dies mit C zu Programmieren, ggf. findest man noch Fehler im Skript!!! :-)

PS: weitere Infos zum arbeiten mit Dateien und Verzeichnissen findest du hier -> openbook.galileocomputing.de/c_von_a_bis_z/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>

time_t st_mTime(char *dir_name) {
    struct stat attribut;

    // printf("%s\n", dir_name); /* Test Ausgabe */
    if (stat(dir_name, &attribut) == -1) {
        fprintf(stderr, "... stat-Fehler\n");
        exit(1);
    }
    if (attribut.st_mode & S_IFREG) {
        return attribut.st_mtime;
    } else {
        return 0;
    }
}

int main(int argc, char *argv[]) {
    int length;
    char dir_name[1000];
    char dir_name_1[1000];
    char dir_name_2[1000];
    DIR *dir;
    time_t t1, t2;
    struct dirent *dir_info;

    if (argc>2) {
        fprintf(stderr, "Es ist nur ein Argument (Verzeichnis) erlaubt!!!\n");
        exit(1);
    }
    if (argc==2) {
        strcpy(dir_name, argv[1]);
    } else {
        strcpy(dir_name, ".");
    }

    if ((dir = opendir(dir_name)) == NULL) {
        fprintf(stderr, "kann %s nicht öffnen", dir_name);
        exit(2);
    }

    length=strlen(dir_name);
    if ((dir_name[length]) != "/") {
        strcat(dir_name, "/");
    }

    while ((dir_info = readdir(dir)) != NULL) {
        strcpy(dir_name_1, dir_name);
        strcat(dir_name_1, (char*)dir_info->d_name );

        while ((dir_info = readdir(dir)) != NULL) {
            strcpy(dir_name_2, dir_name);
            strcat(dir_name_2, (char*)dir_info->d_name );

            t1=st_mTime(dir_name_1);
            t2=st_mTime(dir_name_2);
             if(t1!=t2) {
                if(t1>t2) {
                    strcpy(dir_name_1, dir_name_1);
                } else if (t1

C-Programm – Dateien kopieren unter Linux

In dem Buch “Linux-Programmierung” habe ich einige interessante Beispiele zum kopieren von Dateien unter Linux gefunden.

#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

int main() {
	char c;
	int in, out;

	// open - mit dem Systemaufruf open kann ein neuer Dateideskriptor erstellt werden
	// ---------------------
	// Modus -> Beschreibung
	// ---------------------
	// O_RDONLY -> nur zum lesen oeffnen
	// O_WONLY	-> nur zum schreiben oeffnen
	// O_RDWR	-> zum lesen und schreiben oeffnen
	// ---------------------
	// optionaler Modus -> Beschreibung
	// ---------------------
	// O_APPEND	-> am Ende der Datei schreiben
	// O_TRUNC	-> Inhalt der vorhandenen Datei wird geloescht
	// O_CREAT	-> erstellt die Datei mit Berechtigungen 
	// O_EXCL	-> stellt sicher, dass nicht zwei Programme
	//				die selbe Datei, zur gleichen Zeit erstellen 
	// ---------------------
	// Berechtigung -> Beschreibung
	// ---------------------
	// S_IRUSR 	-> Lesen, Eigentuemer (owner)
	// S_IWUSR	-> Schreiben, Eigentuemer (owner)
	// S_IXUSR	-> Ausfuehren, Eigentuemer (owner)
	// S_IRGRP	-> Lesen, Gruppe (group)
	// S_IWGRP	-> Schreiben, Gruppe (group)
	// S_IXGRP	-> Ausfuehren, Gruppe (group)
	// S_IROTH	-> Lesen, Andere (others)
	// S_IWOTH	-> Schreiben, Andere (others)
	// S_IXOTH	-> Ausfuehren, Andere (others)
	//
	// weitere Infos unter: man 2 open 
	//
	// 1 MB Datei erstellen -> dd if=/dev/zero of=file.in bs=1024 count=10240
	// 
	// Datei "file.in" zum lesen oeffnen
	in = open("file.in", O_RDONLY);
	// Datei "file.out" erstellen (Eigentuemer -> Lesen + Schreiben) 
	out = open("file.out", O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
	// Zeichen fuer Zeichen einlesen ...
	while(read(in,&c,1) == 1) {
		// ... und jedes Zeichen in die neue Datei schreiben
		write(out,&c,1);
	}
	exit(0);
}

Wir gehen in diesem Beispiel davon aus, dass die Datei “file.in” (10 MB) bereits vorhanden ist.

Test:

dd if=/dev/zero of=file.in bs=1024 count=10240
time ./copy_system

Ausgabe:

./copy_system  7,54s user 88,56s system 99% cpu 1:36,23 total

Wie wir sehen, dauerte der Kopiervorgang insgesamt ~ 1 1/2 Minuten, da wir die Datei Zeichen für Zeichen kopiert haben, im nächsten Beispiel werden jeweills 1024 Byte eingelesen und in die neue Datei geschrieben.

#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>

int main() {
	char block[1024];
	int in, out, nread;

	// open - mit dem Systemaufruf open kann ein neuer Dateideskriptor erstellt werden
	// ---------------------
	// Modus -> Beschreibung
	// ---------------------
	// O_RDONLY -> nur zum lesen oeffnen
	// O_WONLY	-> nur zum schreiben oeffnen
	// O_RDWR	-> zum lesen und schreiben oeffnen
	// ---------------------
	// optionaler Modus -> Beschreibung
	// ---------------------
	// O_APPEND	-> am Ende der Datei schreiben
	// O_TRUNC	-> Inhalt der vorhandenen Datei wird geloescht
	// O_CREAT	-> erstellt die Datei mit Berechtigungen 
	// O_EXCL	-> stellt sicher, dass nicht zwei Programme
	//				die selbe Datei, zur gleichen Zeit erstellen 
	// ---------------------
	// Berechtigung -> Beschreibung
	// ---------------------
	// S_IRUSR 	-> Lesen, Eigentuemer (owner)
	// S_IWUSR	-> Schreiben, Eigentuemer (owner)
	// S_IXUSR	-> Ausfuehren, Eigentuemer (owner)
	// S_IRGRP	-> Lesen, Gruppe (group)
	// S_IWGRP	-> Schreiben, Gruppe (group)
	// S_IXGRP	-> Ausfuehren, Gruppe (group)
	// S_IROTH	-> Lesen, Andere (others)
	// S_IWOTH	-> Schreiben, Andere (others)
	// S_IXOTH	-> Ausfuehren, Andere (others)
	//
	// weitere Infos unter: man 2 open 
	//
	// 1 MB Datei erstellen -> dd if=/dev/zero of=file.in bs=1024 count=10240
	// 
	// Datei "file.in" zum lesen oeffnen
	in = open("file.in", O_RDONLY);
	// Datei "file.out" erstellen (Eigentuemer -> Lesen + Schreiben) 
	out = open("file.out", O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);
	// 1024 Byte werden eingelesen ...
	while((nread = read(in,block,sizeof(block))) > 0) {
		// ... und in die neue Datei geschrieben
		write(out,block,nread);
	}
	exit(0);
}

Test:

rm file.out
time ./copy_block 

Ausgabe:

./copy_block  0,01s user 0,15s system 98% cpu 0,158 total

Hier dauerte der gleiche Vorgang nur noch ~ 0,16 Sekunden. Daher nutzt man zum kopieren von ganzen Festplatten auch gerne “dd”! :-) Zum Schluss noch ein Beispiel, wo die Bibliothek (stdio.h) von C genutzt wurden.

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

int main() {
	char c;
	FILE *in, *out;

	// fopen - oeffnet eine Datei 
	// ---------------------
	// Modus -> Beschreibung
	// ---------------------
	// r	-> nur zum lesen oeffnen
	// w	-> nur zum schreiben oeffnen
	// a	-> am Ende der Datei anhaengen
	// r+	-> zum Aktualisieren oeffnen (schreiben + lesen)
	// w+	-> zum Aktualisieren oeffnen, auf Null-Laenge abschneiden
	// a+	-> zum Aktualisieren oeffnen, am Ende der Datei anhaengen
	//
	// weitere Infos unter: man fopen 
	//
	// fgetc - liefert das naechste Byte als Zeichen aus einem Datei-Stream zurueck,
	// 			die Funktion liefert EOF (End of File) beim Ende der Datei bzw.
	//			bei einem Fehler zurück
	//
	// weitere Infos unter: man fgetc
	//
	// fputc - schreibt ein Zeichen in einen Ausgabe-Datei-Stream
	//
	// weitere Infos unter: man fputc
	//
	// 1 MB Datei erstellen -> dd if=/dev/zero of=file.in bs=1024 count=10240
	// 
	// Datei "file.in" zum lesen oeffnen
	in = fopen("file.in", "r");
	// Datei "file.out" erstellen (Eigentuemer -> Lesen + Schreiben) 
	out = fopen("file.out", "w");
	// Zeichen fuer Zeichen einlesen (+ interner Puffer in der Struktur FILE) ...
	while((c = fgetc(in)) != EOF) {
		// ... und jedes Zeichen in die neue Datei schreiben
		fputc(c,out);
	}
	exit(0);
}

Test:

rm file.out
time ./copy_system_2

Ausgabe:

./copy_system_2  1,10s user 0,09s system 99% cpu 1,196 total

Hier brauchen wir für 10 MB zirka 1,2 Sekunden, was um einiges schneller ist als das erste Beispiel, wo die Zeichen einzeln kopiert wurden.

C-Programm – Umgebungsvariablen unter Linux

In dem Buch “Linux Programmierung” habe ich ein schönes Beispiel für Umgebungsvariablen unter Linux gefunden, welches ich gerade ein wenig Kommentiert habe… :-)

“Beachten Sie, dass sich die Umgebung nur lokal zum Programm verhält. Änderungen, die innerhalb des Programmes durchgeführt werden, werden nicht nach außen reflektiert, da Variablenwerte nicht vom untergeordneten Prozess (unser Programm) an den übergeordneten Prozess (die Shell) propagiert werden.” – Seite 166

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

/* argc -> Anzahl Kommandozeilenparameter + Programmnamen (1), somit ist der Wert min. 1 */
 
/* argv -> ist ein Zeiger auf das Feld (Array) mit der in argc angegebene Anzahl von Elementen...
	... und die Elemente (z.B.: argc[0] sind Zeiger auf eine Zeichenkette...
 
	arg[0] -> Programmname
	arg[1] -> 1. Parameter 
	arg[2] -> 2. Parameter
	[...]
	arg[n] -> letzter Parameter
	0L    -> das letzte Element von argv[] einthaelt eine Null
*/
int main(int argc, char *argv[]) {
	char *var, *value;

	// wenn kein oder mehr als 3 Parameter uebergeben wurden, dann ...
	if (argc == 1 || argc > 3) {
			// Fehlermeldung ausgeben und Programm beenden
			fprintf(stderr,"usage: environ var [value]\n");
			exit(1);
	}

	// 1. Parameter in die Variable "var" schreiben
	var = argv[1];
	// mit getenv den Wert der Umgebungsvariablen abrufen 
	// und in die Variable "value" schreiben
	value = getenv(var);
	// wenn value wahr bzw. vorhanden ist, dann ...
	if (value) {
			printf("Variable %s has value %s\n", var, value);
	// ... ansonsten ...
	} else {
			printf("Variable %s has no value\n", var);
	}

	// wenn 2. Parameter uebergeben wurden, dann ...
	if (argc == 3) {
		char *string;
		// 2. Parameter in die Variable "value" schreiben
		value = argv[2];
		// Speicherbereich fuer die Umgebungsvariablen + Wert anlegen
		string = malloc(strlen(var)+strlen(value)+2);
		// wenn string nicht wahr bzw. nicht vorhanden ist, dann ...
		if(!string) {
				// Fehlermeldung ausgeben und Programm beenden
				fprintf(stderr,"out of memory\n");
				exit(1);
		}
		// strcpy - Stringfunktion zum kopieren einer Zeichenkette (string <- var)
		strcpy(string,var);
		// strcat - Stringfunktion zum verketten von Strings (string=) 
		strcat(string,"=");
		// strcat - Stringfunktion zum verketten von Strings (string=value)
		strcat(string,value);
		printf("Calling putenv with: %s\n", string);
		//
		// putenv - Aendert oder setzt eine Umgebungsvariable, gibt -1 bei einem Fehler 
		// und 0 bei keinem Fehler aus 
		//
		// wenn nicht gleich 0 -> wenn ein Fehler aufgetreten ist , dann ...
		if (putenv(string) != 0) {
				// Fehlermeldung ausgeben, Speicher wieder freigeben und Programm beenden
				fprintf(stderr,"putenv failed\n");
				free(string);
				exit(1);
		}

		// den Wert der Umgebungsvariablen in der Variablen "var"
		// in die Variable "value" schreiben
		value = getenv(var);
		// wenn value gleich wahr bzw. gesetzt, dann ...
		if (value) {
				// Umgebungsvariablen + neuen Wert ausgeben
				printf("New value of %s is %s\n", var, value);
		// ... ansonsten ...
		} else {
				// Umgebungsvariablen + ? ausgeben
				printf("New value of %s is null??\n", var);
		}
	}
exit(0);
}

C-Programm – Dynamische Speicherverwaltung

In diesem Beispiel zeigt ich, wie man Speicher dynamisch anlegen bzw. verwalten kann …

/*
============================================================================
Autor          : Lars Moelleken
Datum          : 10.02.2011
Beschreibung   : Preiskalkulation
Version        : 1.0
Compiler       : gcc 4.6.2-12
Programmschnittstelle: int main(void)
Das Programm gibt den Wert 0 oder 1 zurück.
Es werden keine Argumente erwartet.
============================================================================
*/

/*
============================================================================
Praeprozessoranweisungen
============================================================================
*/
#include 
#include 
#include 
#include 
#if defined __linux__
#include 
#elif defined _WIN32 || defined _WIN64
#define false 0
#define true 1
#endif

#define FUNSTAR_PREIS 1243.43
#define FUNSTAR_NAME "Fun Star"
#define HIGHEND_PREIS 1658.50
#define HIGHEND_NAME "High End"
#define MULTIMEDIASTAR_PREIS 698.20
#define MULTIMEDIASTAR_NAME "Multimedia Star"
#define OFFICESTAR_PREIS 1015.39
#define OFFICESTAR_NAME "Office Star"
#define GEHAEUSE_NAME "Gehaeuse"
#define LX100_PREIS 97.05
#define LX100_NAME "Compucase LX100 weiss"
#define LX120_PREIS 68.89
#define LX120_NAME "Compucase LX120 schwarz"
#define LX34A_PREIS 103.60
#define LX34A_NAME "Compucase LX34A weiss"
#define MAINBOARD_PREIS 193.03
#define MAINBOARD_NAME "Mainboard"
#define CPU_PREIS 334.65
#define CPU_NAME "CPU"
#define FESTPLATTEN_PREIS 130.95
#define FESTPLATTEN_NAME "Festplatte"
#define GRAFIKKARTEN_PREIS 319.13
#define GRAFIKKARTEN_NAME "Grafikkarte"

// die Struktur existiert nach der Deklaration als neuer Datentyp
// per typedef kann ein Synonym fuer die Strucktur erstellt werden 
typedef struct 
{
   char *pcKundenname, *pcProduktname;
   int iKundenNr, iProduktanzahl, iLieferung, iMontage;
   double dPreis;
} kunden;

/*
============================================================================
Funktionsprototypen
============================================================================
*/
// neuer Datentyp "kunden" wird hier direkt verwendent
kunden* datenEinlesen(kunden *s,int *iAnzahl, char *pcKundenname, 
   char *pcProduktname, int iKundenNr, int iProduktanzahl,
   int iLieferung,int iMontage,double dPreis);
int cls(void);
int new_fflush(void);
int InArray(int x, int iArray[], int iSize);
int loeschen(kunden *s, int *iAnzahl, int i);
double berechnungPreis(double dInputPreis, int iLieferung,
   int iMontage, int iAusgabe);
int ausgabeWarenkorb(kunden *s, int iAnzahl);
int ausgabeGesamtpreis(kunden *s, int iAnzahl);
int sucheNachKundenNr(kunden *s, int iAnzahl, int iKundenNr);
int sucheNachName(kunden *s, int iAnzahl, char *pcKundenname);
char *readKundenName(kunden *s, int iAnzahl, int iKundenNr);
int readProduktanzahl(void);
int readMontage(void);
int readLieferung(void);
int readKundenNr(void);
int printMenu(void);
int printMenuStandard(void);
int printMenuEinzel(void);
int printMenuGehaeuse(void);

/*
============================================================================
Funktion main() - Hauptfunktion
============================================================================
*/
int main(void)
/*
Rückgabewert:    0 ==> alles OK
                 1 ==> es ist ein Fehler aufgetreten
Es werden keine Argumente übergeben!
*/
{
   char cNamePuffer[100], cProduktPuffer[100], cInput;
   int iAnzahl=0, i, iKundenNr, inputStandard, auswahl, iProduktanzahl, 
      iShowMenu=true, iLieferung=false, iMontage=false;
   double dPreis;
 
   // Zeiger auf einen Eintrag definieren 
   kunden *s;
   // neuen Speicherbereich fuer die Struktur "kunden" anlegen
   s = (kunden*) malloc(sizeof(iAnzahl));
   // falls kein Speicherplatz zur Verfuegung steht ...
   if (s == NULL)
   {
      printf("Fehler: .......Speicherplatzmangel\n");
      exit(1);
   }
 
   // solange bis '0' eingegeben wird ...
   do 
   {
      if (iShowMenu == 1) 
      {
         cls();
         // Ausgabe vom Warenkorb
         ausgabeGesamtpreis(s,iAnzahl);
         // Ausgabe vom Menue
         printMenu();
      }  
      // Eingabe
      scanf("%c", &cInput);
      new_fflush();
      // Auswahl zur Eingabe 
      switch (cInput) 
      {
         // Einlesen
         case 'a': case 'A':
            iShowMenu=false;
            // i = 1 => true
            i = 1;
            // solange i = true ...
            while (i == true)
            {
               do
               {
                  cls();
                  // Ausgabe vom Warenkorb
                  ausgabeGesamtpreis(s,iAnzahl);
                  // Ausgabe vom MenueStadard
                  printMenuStandard();
                  scanf("%d", &inputStandard);
                  new_fflush();
               } 
               while (inputStandard != 0 && 
               		 inputStandard != 1 && 
               		 inputStandard != 2 && 
               		 inputStandard != 3 && 
               		 inputStandard != 4);
               // Auswahl zur Eingabe 
               switch (inputStandard) 
               {
                  case 1:
                     dPreis=FUNSTAR_PREIS;
                     strncpy(cProduktPuffer,FUNSTAR_NAME,
                     		 strlen(FUNSTAR_NAME) +1);
                     break;
                  case 2:
                     dPreis=HIGHEND_PREIS;
                     strncpy(cProduktPuffer,HIGHEND_NAME,
                     		 strlen(HIGHEND_NAME) +1);
                     break;
                  case 3:
                     dPreis=MULTIMEDIASTAR_PREIS;
                     strncpy(cProduktPuffer,MULTIMEDIASTAR_NAME,
                     		 strlen(MULTIMEDIASTAR_NAME) +1);
                     break;
                  case 4:
                     dPreis=OFFICESTAR_PREIS;
                     strncpy(cProduktPuffer,OFFICESTAR_NAME,
                     		 strlen(OFFICESTAR_NAME) +1);
                     break;
                  default:
                     dPreis=0;
                     // i = 0 => false => while-Schleife wird verlassen
                     i=false;
                     cls();
                     iShowMenu=true;
                     break;
               }
               if (dPreis != 0)
               {
                  iKundenNr=readKundenNr();
                  strcpy(cNamePuffer,readKundenName(s, iAnzahl, iKundenNr));
                  iProduktanzahl=readProduktanzahl();
                  iLieferung=readLieferung();

                  cls();
                  berechnungPreis(dPreis, iLieferung, iMontage, 1);

                  printf("\n\nIn den Warenkorb? ('j' fuer ja) ");
                  // Einlesen von cInput
                  scanf("%c", &cInput);
                  new_fflush();
                  printf("\n\n");
                  // wenn Eingabe ungleich j ist, dann ...
                  if (cInput == 'j') 
                  {
                     // Speicher wird per Funktion (datenEinlesen) erstellt
                     s = datenEinlesen(s,&iAnzahl,cNamePuffer,cProduktPuffer,
                     		 iKundenNr,iProduktanzahl,iLieferung,iMontage,dPreis);

                     printf("\n**Eintrag gespeichert**\n");
                     printf("\n\tweiteren Eintrag anlegen? ('j' fuer ja) ");
                  }
                  else
                  {
                     printf("\n\tanderen Eintrag anlegen? ('j' fuer ja) ");
                  }

                  // Einlesen von cInput
                  scanf("%c", &cInput);
                  new_fflush();
                  printf("\n\n");
                  // wenn Eingabe ungleich j ist, dann ...
                  if (cInput != 'j') 
                  {
                     // i = 0 => false => while-Schleife wird verlassen
                     i=false;
                     cls();
                     iShowMenu=true;
                  }
                  else
                  {
                     cls();
                     iShowMenu=false;
                  }
               }
            }
            // beendet eine Schleife bzw. eine case-Anweisung 
            break;
         // Einlesen
         case 'b': case 'B':
            cls();
            iShowMenu=false;
            // i = 1 => true
            i = true;
            // solange i==true ...
            while (i == true)
            {
               do
               {
                  cls();
                  // Ausgabe vom Warenkorb
                  ausgabeGesamtpreis(s,iAnzahl);
                  // Ausgabe vom MenueStadard
                  printMenuEinzel();
                  scanf("%d", &inputStandard);
                  new_fflush();
               } 
               while (inputStandard != 0 && 
               		 inputStandard != 1 && 
               		 inputStandard != 2 && 
               		 inputStandard != 3 && 
               		 inputStandard != 4 && 
               		 inputStandard != 5);
               // Auswahl zur Eingabe 
               switch (inputStandard) 
               {
                  case 1:
                     // i = 0 => false => while-Schleife wird verlassen
                     i=false;
                     do
                     {
                        cls();
                        // Ausgabe vom Warenkorb
                        ausgabeGesamtpreis(s,iAnzahl);
                        // Ausgabe vom MenueStadard
                        printMenuGehaeuse();
                        scanf("%d", &inputStandard);
                        new_fflush();
                     } 
                     while (inputStandard != 0 && 
                     		 inputStandard != 1 && 
                     		 inputStandard != 2 && 
                     		 inputStandard != 3);
                     // Auswahl zur Eingabe 
                     switch (inputStandard)
                     {
                        case 1:
                           dPreis=LX100_PREIS;
                           strncpy(cProduktPuffer,LX100_NAME,
                           		 strlen(LX100_NAME) +1);
                           break;
                        case 2:
                           dPreis=LX120_PREIS;
                           strncpy(cProduktPuffer,LX120_NAME,
                           		 strlen(LX120_NAME) +1);
                           break;
                        case 3:
                           dPreis=LX34A_PREIS;
                           strncpy(cProduktPuffer,LX34A_NAME,
                           		 strlen(LX34A_NAME) +1);
                           break;
                        default:
                           dPreis=0;
                           // i = 0 => false => while-Schleife wird verlassen
                           i=false;
                           cls();
                           iShowMenu=true;
                           break;
                     }
                     break;
                  case 2:
                     dPreis=MAINBOARD_PREIS;
                     strncpy(cProduktPuffer,MAINBOARD_NAME,
                     		 strlen(MAINBOARD_NAME) +1);
                     break;
                  case 3:
                     dPreis=CPU_PREIS;
                     strncpy(cProduktPuffer,CPU_NAME,
                     		 strlen(CPU_NAME) +1);
                     break;
                  case 4:
                     dPreis=FESTPLATTEN_PREIS;
                     strncpy(cProduktPuffer,FESTPLATTEN_NAME,
                     		 strlen(FESTPLATTEN_NAME) +1);
                     break;
                  case 5:
                     dPreis=GRAFIKKARTEN_PREIS;
                     strncpy(cProduktPuffer,GRAFIKKARTEN_NAME,
                     		 strlen(GRAFIKKARTEN_NAME) +1);
                     break;
                  default:
                     dPreis=0;
                     // i = 0 => false => while-Schleife wird verlassen
                     i=false;
                     cls();
                     iShowMenu=true;
                     break;
               }
               if (dPreis != 0)
               {
                  iKundenNr=readKundenNr();
                  strcpy(cNamePuffer,readKundenName(s, iAnzahl, iKundenNr));
                  iProduktanzahl=readProduktanzahl();
                  iLieferung=readLieferung();
                  iMontage=readMontage();
 
                  cls();
                  berechnungPreis(dPreis, iLieferung, iMontage, 1);

                  printf("\n\nIn den Warenkorb? ('j' fuer ja) ");
                  // Einlesen von cInput
                  scanf("%c", &cInput);
                  new_fflush();
                  printf("\n\n");
                  // wenn Eingabe ungleich j ist, dann ...
                  if (cInput == 'j') 
                  {
                     // Speicher wird per Funktion (datenEinlesen) erstellt
                     s = datenEinlesen(s,&iAnzahl,cNamePuffer,cProduktPuffer,
                     		 iKundenNr,iProduktanzahl,iLieferung,iMontage,dPreis);

                     printf("\n**Eintrag gespeichert**\n");
                     printf("\n\tweiteren Eintrag anlegen? ('j' fuer ja) ");
                  }
                  else
                  {
                     printf("\n\tanderen Eintrag anlegen? ('j' fuer ja) ");
                  }

                  // Einlesen von cInput
                  scanf("%c", &cInput);
                  new_fflush();
                  printf("\n\n");

                  // wenn Eingabe ungleich j ist, dann ...
                  if (cInput != 'j') 
                  {
                     // i = 0 => false => while-Schleife wird verlassen
                     i=false;
                     cls();
                     iShowMenu=true;
                  }
                  else
                  {
                     cls();
                     iShowMenu=false;
                  }
               }
            }
            // beendet eine Schleife bzw. eine case-Anweisung 
            break;
         // Ausgabe
          case 'c': case 'C':
            cls();
            iShowMenu=false;
            // wenn Anzahl gleich 0, dann ...
            if (iAnzahl==0) 
            {
               printf("\n\n**Kein Eintrag gefunden**\n\n");
            } 
            else 
            {
               ausgabeWarenkorb(s,iAnzahl);
            }
            printf("\ndrueke 'Enter' um fortzufahren: ...\n");
            if (getchar() == '\n')
            {
               cls();
               iShowMenu=true;
            }
            // beendet eine Schleife bzw. eine case-Anweisung 
            break;
         // Nach Kunden-Namen suchen
         case 'd': case 'D':
            cls();
            iShowMenu=false;
            printf("Suchen (Kunden-Name): ");
            // Einlesen von cNamePuffer (pcKundenname)
            scanf("%99s", cNamePuffer);
            new_fflush();
            // Funktion wird aufgerufen 
            sucheNachName(s,iAnzahl,cNamePuffer);
            printf("\ndrueke 'Enter' um fortzufahren: ...\n");
            if (getchar() == '\n')
            {
               cls();
               iShowMenu=true;
            }
            // beendet eine Schleife bzw. eine case-Anweisung 
            break;
         // Nach Kunden-Nr. suchen
         case 'e': case 'E':
            cls();
            iShowMenu=false;
            printf("Suchen (Kunden-Nr.): ");
            // Einlesen von iKundenNr
            scanf("%d",&iKundenNr);
            new_fflush();
            // Funktion wird aufgerufen 
            sucheNachKundenNr(s,iAnzahl,iKundenNr);
            printf("\ndrueke 'Enter' um fortzufahren: ... \n");
            if (getchar() == '\n')
            {
               cls();
               iShowMenu=true;
            }
            // beendet eine Schleife bzw. eine case-Anweisung 
            break;
         // Einen Eintrag löschen
         case 'f': case 'F':
            cls();
            iShowMenu=false;
            printf("Loeschen: ");
            i=true;
            while (i == true) 
            {
               if (iAnzahl != 0) 
               {
                  for (i=0; i != iAnzahl; i++) 
                  {
                     printf("\n\t---------------------------------------");
                     printf("\n\tIndex: %d -> Kunde: %s (%d)", i, 
                     		 s[i].pcKundenname, s[i].iKundenNr);
                     printf("\n\t---------------------------------------");
                  }
                  printf("\n\nIndex angeben: ");
                  scanf("%d",&auswahl);
                  new_fflush();
                  if (auswahl < 0 || auswahl >= iAnzahl) 
                  {
                     cls();
                     printf("\nungueltige Eingabe\n\n");
                  } 
                  else 
                  {
                     printf("\n\tEintrag wirklich loeschen? ('j' fuer ja) ");
                     // Einlesen von cInput
                     scanf("%c", &cInput);
                     new_fflush();
                     printf("\n\n");

                     // wenn Eingabe gleich j ist, dann ...
                     if (cInput == 'j') 
                     {
                        loeschen(s,&iAnzahl,auswahl);
                        i=false;
                           printf("\n\n**Eintrag geloescht !**\n\n");
                     }
                     else
                     {
                        // i = 0 => false => while-Schleife wird verlassen
                        i=false;
                        iShowMenu=true;
                     }

                  }
               } 
               else 
               {
                  i=false;
                  printf("\n\n**Kein Eintrag gefunden**\n\n");
               }
               printf("\ndrueke 'Enter' um fortzufahren: ... \n");
               if (getchar() == '\n')
               {
                  cls();
                  iShowMenu=true;
               }
            }
            // beendet eine Schleife bzw. eine case-Anweisung 
            break;
         // Speicher wieder freigeben (free)
         case 'x': case 'X':
            for (i=0; i != iAnzahl; i++) 
            {
               // "free" gibt den Speicher wieder frei
               free(s[i].pcKundenname);
            }
            // testing
            //free(s);
            // Alternative schreibweise:
            // realloc(s,0);
            // beendet eine Schleife bzw. eine case-Anweisung
            break;
         // Standard 
         default:
            iShowMenu=true;
            break;
      }
   // solange in der Schleife bleiben, bis 0 eingegeben wird 
   } 
   while (cInput != 'x' && cInput != 'X');
 
   return 0;
}

/*
============================================================================
Funktion datenEinlesen() - der Speicher wird bereitgestellt und die Eingaben 
               an die Strucktur uebergeben
============================================================================
*/
kunden* datenEinlesen(kunden *s, int *iAnzahl, char *pcKundenname,
   char *pcProduktname, int iKundenNr, int iProduktanzahl,
   int iLieferung, int iMontage, double dPreis)
/*
Rückgabewert:    s ==> neuen Speicherbereich
Argumente:    *s ==> Zeiger auf den neuen Speicherbereich
      *iAnzahl ==> Zeiger auf die Anzahl an Eintraegen
      *pcKundenname ==> Zeiger auf den Kunden-Namen
      *pcProduktname ==> Zeiger auf den Produkt-Namen 
      iKundenNr ==> Kunden-Nr.
      iProduktanzahl ==> Anzahl vom bestellten Produkten
      iLieferung ==> Lieferung (1=ja || 0=nein)
      iMontage ==> Montage (1=ja || 0=nein)
      dPreis ==> Preis pro Produkt
*/
{
   //
   // realloc() -    kann Speicherplatz von einem bereits zugeteilten 
   //      Blocks vergroeßern oder verkleinern, dazu wird ein 
   //      Zeiger auf die Anfangsadresse des neu reservierten 
   //      Speicherblocks gesetzt, dabei bleibt der Inhalt des 
   //      urspruenglichen Speicherblocks erhalten und der neue 
   //      Speicherblock wird hinten angefuegt
   //
   // Speicherbereich wird vergroeßert
   s=(kunden*)realloc(s,sizeof(kunden)*(*iAnzahl +1));
   //
   // strlen -    gibt die Anzahl der Zeichen eines Strings 
   //      ohne das Null-Zeichen zurueck
   // strcpy -    Stringfunktion zum kopieren einer Zeichenkette       
   //
   // malloc() -    reserviert genau so viel zusammenhaengenden Speicher, 
   //      wie angegeben wird, zurueckgegeben wird ein typenloser 
   //      Zeiger auf void mit der Anfangsadresse des 
   //      Speicherbereichs
   //
   // z.B.: 
   // Speicher fuer 100 int-Elemente reservieren 
   // ptr = malloc(100 * sizeof(int));
   // ...
   // Speicher auf 50 int-Elemente verkleinern 
   // ptr = realloc(ptr, 50 * sizeof(int));
   // ...
   // Speicher von 256 auf 512 int-Elemente vergroeßern 
   // int block = 256;
   // ptr = malloc(block * sizeof(int));
   // block += block;
   // ptr = reallloc(ptr, block * sizeof(int));
   //
   // neuen Speicherbereich fuer einen neuen Namen anlegen
   // +1 wegen \0 -> am Ende vom String
   s[*iAnzahl].pcKundenname=(char*) malloc(strlen(pcKundenname) +1); 
   // falls kein Speicherplatz zur Verfuegung steht ...
   if (s[*iAnzahl].pcKundenname == NULL) 
   {
      printf("Fehler: .......Speicherplatzmangel\n");
      exit(1);
   }
   // der Strucktur (kunden) wird die Variable "pcKundenname" hinzugefuegt 
   strncpy(s[*iAnzahl].pcKundenname,pcKundenname,strlen(pcKundenname) +1);
   // der Strucktur (kunden) wird die Variable "iKundenNr" hinzugefuegt
   s[*iAnzahl].iKundenNr=iKundenNr;
   // neuen Speicherbereich fuer einen neuen Produktnamen anlegen
   // +1 wegen \0 -> am Ende vom String
   s[*iAnzahl].pcProduktname=(char*) malloc(strlen(pcProduktname) +1);
   // falls kein Speicherplatz zur Verfuegung steht ...
   if (s[*iAnzahl].pcProduktname == NULL) 
   {
      printf("Fehler: .......Speicherplatzmangel\n");
      exit(1);
   }
   // der Strucktur (kunden) wird die Variable "pcProduktname" hinzugefuegt 
   strncpy(s[*iAnzahl].pcProduktname,pcProduktname,strlen(pcProduktname) +1);
   // der Strucktur (kunden) wird die Variable "iProduktanzahl" hinzugefuegt   
   s[*iAnzahl].iProduktanzahl=iProduktanzahl; 
   // der Strucktur (kunden) wird die Variable "iLieferung" hinzugefuegt   
   s[*iAnzahl].iLieferung=iLieferung;
   // der Strucktur (kunden) wird die Variable "iMontage" hinzugefuegt   
   s[*iAnzahl].iMontage=iMontage;
   // der Strucktur (kunden) wird die Variable "dPreis" hinzugefuegt 
   s[*iAnzahl].dPreis=dPreis;
   // die Anzahl der Kunden um 1 erhoehen
   ++*iAnzahl;
   return s;
}

/*
============================================================================
Funktion cls() - clear
============================================================================
*/
int cls(void)
/*
Rückgabewert:    0 ==> alles OK
Es werden keine Argumente übergeben!
*/
{
#if defined __linux__
   printf("\033[2J");
#elif defined _WIN32 || defined _WIN64
   system("cls");
#endif
   return 0;
}

/*
============================================================================
Funktion new_fflush() - fflush(stdin) for Linux and Windows
============================================================================
*/
int new_fflush(void)
/*
Rückgabewert:    0 ==> alles OK
Es werden keine Argumente übergeben!
*/
{
#if defined __linux__
   int ch;
   while ((ch = getchar()) != '\n' && ch != EOF);                  
#elif defined _WIN32 || defined _WIN64
   fflush(stdin);
#endif
   return 0; 
}

/*
============================================================================
Funktion InArray() - check if 'x' in the 'iArray'
============================================================================
*/
int InArray(int x, int iArray[], int iSize)
/*
Rückgabewert:    inArray ==> is in Array or not ;)
Argumente:   x ==> checking 'x'
      iArray[] ==> in this iArray
      iSize ==> iSize of the iArray
*/
{
   // default is "false"
   int inArray=false;
   int i;
   for (i=0; i alles OK
Argumente:   *s ==> Zeiger auf den neuen Speicherbereich
      *iAnzahl ==> Zeiger auf die Anzahl an Eintraegen
      i ==> Auswahl des Indexes 
*/
{
   // solange Index nicht Anzahl ist ...
   for (i; i != *iAnzahl; i++) 
   {
      // Strucktur-Eintraege um 1 erhoehen
      s[i].pcKundenname=s[i+1].pcKundenname;
      s[i].iKundenNr=s[i+1].iKundenNr;
      s[i].pcProduktname=s[i+1].pcProduktname;
      s[i].iProduktanzahl=s[i+1].iProduktanzahl;
      s[i].iLieferung=s[i+1].iLieferung;
      s[i].iMontage=s[i+1].iMontage;
      s[i].dPreis=s[i+1].dPreis;
   }
   // Anzahl -1 
   --*iAnzahl;
   // Speicherbereich wird verkleinert
   s=(kunden*) realloc(s,sizeof(kunden) * (*iAnzahl));
   return 0;
}

// Funktion: berechnungPreis
double berechnungPreis(double dInputPreis, int iLieferung,
		int iMontage, int iAusgabe)
{
   // Ausgabe ...
   if (iAusgabe == 1) 
   {
      printf("\n\n\tListenpreis pro Artikel:\t%7.2lf", dInputPreis);
      printf("\n\t\t+ Lagerkosten:\t\t%7.2lf", dInputPreis * 0.1);
   }
   dInputPreis = dInputPreis + (dInputPreis  * 0.1);
   if (iAusgabe == 1) 
   {
      printf("\n\t---------------------------------------");
      printf("\n\tMaterialkosten:\t\t\t%7.2lf", dInputPreis);
      printf("\n\t\t+ Verwaltungskosten:\t%7.2lf", dInputPreis * 0.1);
   }
   dInputPreis = dInputPreis + (dInputPreis * 0.1);
   if (iAusgabe == 1) 
   {
      printf("\n\t---------------------------------------");
      printf("\n\tSelbstkosten:\t\t\t%7.2lf", dInputPreis);
      printf("\n\t\t+ Gewinn:\t\t%7.2lf", dInputPreis * 0.1);
   }
   dInputPreis = dInputPreis + (dInputPreis * 0.1);
   if (iAusgabe == 1) 
   {
      printf("\n\t---------------------------------------");
      printf("\n\tBarverkaufspreis:\t\t%7.2lf", dInputPreis);
   }
   if (iLieferung == 1)
   {
      if (iAusgabe == 1) 
      {
         printf("\n\t\t+ Versand:\t\t%7.2lf", dInputPreis * 0.05);
      }
      dInputPreis = dInputPreis + (dInputPreis * 0.05);
      if (iAusgabe == 1) 
      {
         printf("\n\t---------------------------------------");
         printf("\n\tVersandpreis:\t\t\t%7.2lf", dInputPreis);
      }
   }
   if (iMontage == 1)
   {
      if (iAusgabe == 1) 
      {
         printf("\n\t\t+ Montage:\t\t%.2lf", dInputPreis * 0.15);
      }
      dInputPreis = dInputPreis + (dInputPreis * 0.15);
      if (iAusgabe == 1) 
      {
         printf("\n\t---------------------------------------");
         printf("\n\tHerstellungskosten:\t\t%7.2lf", dInputPreis);
      }
   }
   return dInputPreis;
}

/*
============================================================================
Funktion ausgabeWarenkorb() - Warenkorb ausgeben
============================================================================
*/
int ausgabeWarenkorb(kunden *s, int iAnzahl) 
/*
Rückgabewert:    0 ==> alles OK
Argumente:   *s ==> Zeiger auf den neuen Speicherbereich
      iAnzahl ==> Anzahl an Eintraegen
*/
{
   int i, iArray[100];
   double gesamtpreis[100], dPreis[100];
   printf("\nWarenkorb (Einzelpreise):\n");
   // von 0 bis Anzahl ...
   for (i=0; i alles OK
Argumente:   *s ==> Zeiger auf den neuen Speicherbereich
      iAnzahl ==> Anzahl an Eintraegen
*/
{
   int i;
   double gesamtpreis=0, dPreis[32];
   // von 0 bis Anzahl ...
   for (i=0; i alles OK
      1 ==> es ist ein Fehler aufgetreten
Argumente:   *s ==> Zeiger auf den neuen Speicherbereich
      iAnzahl ==> Anzahl an Eintraegen
      iKundenNr ==> Kunden-Nr.
*/
{
   int i,x=false;
   double dPreis[100];
   // von 0 bis Anzahl ...
   for (i=0;i != iAnzahl; i++) 
   {
      // wenn der Eintrag gleich dem Suchbegriff ist ...
      if (s[i].iKundenNr==iKundenNr) 
      {
         dPreis[i] = berechnungPreis(s[i].dPreis, s[i].iLieferung,
         		 s[i].iMontage, 0);
         dPreis[i] = dPreis[i] * s[i].iProduktanzahl;
         printf("\n(Index: %3d)\nKunde: %s\nKunden-Nr: %d\nProdukt: %s\n"
         		 "Preis: %.2lf\n\n",i,s[i].pcKundenname,s[i].iKundenNr,
         		 s[i].pcProduktname,dPreis[i]);
         // x=1 -> Eintrag gefunden
         x=true;
      }
   }
   // wenn Eintrag nicht gefunden wurde, dann ...
   if (x==false) 
   {
      printf("\n\n**Kein Eintrag gefunden**\n\n");
      return 1;
   }
   else
   {
      return 0;
   }
}

/*
============================================================================
Funktion sucheNachName() - Infos ueber eine bestimmten Kunden-Namen
============================================================================
*/
int sucheNachName(kunden *s, int iAnzahl, char *pcKundenname)
/*
Rückgabewert:    0 ==> alles OK
      1 ==> es ist ein Fehler aufgetreten
Argumente:   *s ==> Zeiger auf den neuen Speicherbereich
      iAnzahl ==> Anzahl an Eintraegen
      *pcKundenname ==> Kunden-Name
*/
{
   int i,x=false;
   double dPreis[100];
   // von 0 bis Anzahl ...
   for (i=0;i != iAnzahl;i++) 
   {
      // Vergleich (strcmp) von char-Arrays bzw. String
      if ( !strcmp(pcKundenname,s[i].pcKundenname) ) 
      {
         dPreis[i] = berechnungPreis(s[i].dPreis, s[i].iLieferung,
         		 s[i].iMontage, 0);
         printf("\n(Index: %3d)\nKunde: %s\nKunden-Nr: %d\nProdukt: %s\n"
         		 "Preis: %.2lf\n\n",i,s[i].pcKundenname,s[i].iKundenNr,
         		 s[i].pcProduktname,dPreis[i]);
         // x=1 -> Eintrag gefunden
         x=true;
      }
   }
   // wenn Eintrag nicht gefunden wurde, dann ...
   if (x==false) 
   {
      printf("\n\n**Kein Eintrag gefunden**\n\n");
      return 1;
   }
   else
   {
      return 0;
   }
}

/*
============================================================================
Funktion readKundenName() - scanf with check
============================================================================
*/
char *readKundenName(kunden *s, int iAnzahl, int iKundenNr)
/*
Rückgabewert:    cNamePuffer ==> Kunden-Name
Argumente:   *s ==> Zeiger auf den neuen Speicherbereich
      iAnzahl ==> Anzahl an Eintraegen
      iKundenNr ==> Kunden-Nr.
*/
{
   int check=true, i;
   static char cNamePuffer[100];
   if (iAnzahl != 0) 
   {
      for (i=0; i != iAnzahl; i++) 
      {
         if (s[i].iKundenNr == iKundenNr)
         {
            strncpy(cNamePuffer,s[i].pcKundenname,
            		strlen(s[i].pcKundenname) +1);
            check=false;
         }
      }
   }
   if (check==true)
   {
      do 
      {
         printf("\tKunde (Name): ");
         // Einlesen von cNamePuffer (pcKundenname)
         scanf("%99s", cNamePuffer);
         new_fflush();
         if (!isalpha(cNamePuffer[0]))
         {
            printf("\n\n**Bitte einen korrekten Namen eingeben!!!**\n\n");
         }
      } 
      while (!isalpha(cNamePuffer[0]));
   }
   return cNamePuffer;
}

/*
============================================================================
Funktion readProduktanzahl() - scanf with check
============================================================================
*/
int readProduktanzahl(void)
/*
Rückgabewert:    iProduktanzahl ==> Produktanzahl
Es werden keine Argumente übergeben!
*/
{
   int check=true, iProduktanzahl;
   check=true;
   do 
   {
      printf("\tAnzahl: ");
      // Einlesen der Produktanzahl
      check = !scanf("%d", &iProduktanzahl);
      new_fflush();
      if (check)
      {
         printf("\n\n**Bitte eine korrekte Produktanzahl eingeben!!!**\n\n");
      }
   } 
   while (check);
   return iProduktanzahl;
}

/*
============================================================================
Funktion readLieferung() - scanf with check
============================================================================
*/
int readMontage(void)
/*
Rückgabewert:    iMontage ==> Montage (1 | 0)
Es werden keine Argumente übergeben!
*/
{
   int iMontage=0;
   char cInput;
   do 
   {
      printf("\tMontage: ('j' fuer ja) ");
      // Einlesen der Montage
      scanf("%c", &cInput);
      new_fflush();
      if (!isalpha(cInput))
      {
         printf("\n**Bitte eine korrekte Eingabe taetigen!!!**\n");
      }
   } 
   while (!isalpha(cInput));
   if (cInput == 'j') 
   {
      iMontage=true;
   }
   return iMontage;
}

/*
============================================================================
Funktion readLieferung() - scanf with check
============================================================================
*/
int readLieferung(void)
/*
Rückgabewert:    iLieferung ==> Lieferung (1 | 0)
Es werden keine Argumente übergeben!
*/
{
   int iLieferung=0;
   char cInput;   
   do 
   {
      printf("\tLieferung: ('j' fuer ja) ");
      // Einlesen der Lieferung
      scanf("%c", &cInput);
      new_fflush();
      if (!isalpha(cInput))
      {
         printf("\n\n**Bitte eine korrekte Eingabe taetigen!!!**\n\n");
      }
   } 
   while (!isalpha(cInput));
   if (cInput == 'j') 
   {
      iLieferung=true;
   }
   return iLieferung;
}

/*
============================================================================
Funktion readKundenNr() - scanf with check
============================================================================
*/
int readKundenNr(void)
/*
Rückgabewert:    iKundenNr ==> Kunden-Nr.
Es werden keine Argumente übergeben!
*/
{
   int check=true, iKundenNr;
   do 
   {
      printf("\n\tKunden-Nr.: ");
      // Einlesen der iKundenNr
      check = !scanf("%d", &iKundenNr);
      new_fflush();
      if (check)
      {
         printf("\n\n**Bitte eine korrekte Kunden-Nr. eingeben!!!**\n\n");
      }
   } 
   while (check);
   return iKundenNr;
}

/*
============================================================================
Funktion printMenu() - Ausgabe vom Menue
============================================================================
*/
int printMenu(void) 
/*
Rückgabewert:    0 ==> alles OK
Es werden keine Argumente übergeben!
*/
{
   printf("\n\tP R E I S K A L K U L A T I O N");
   printf("\n\t===============================");
   printf("\n\n\ta: Standardkonfiguration");
   printf("\n\n\tb: Einzelkomponenten");
   printf("\n\n\tc: Warenkorb anzeigen"); 
   printf("\n\n\td: Suchen (Kunden-Name)");
   printf("\n\n\te: Suchen (Kunden-Nr.)");
   printf("\n\n\tf: Loeschen");
   printf("\n\n\tx: Ende");
   printf("\n\n\n\tAuswahl: ");
   return 0;
}

/*
============================================================================
Funktion printMenuStandard() - Ausgabe vom Standard-Menue
============================================================================
*/
int printMenuStandard(void) 
/*
Rückgabewert:    0 ==> alles OK
Es werden keine Argumente übergeben!
*/
{
   printf("\n\tS T A N D A R D K O N F I G U R A T I O N");
   printf("\n\t=========================================");
   printf("\n\n\t1: %s\t\t%5.2f", FUNSTAR_NAME, FUNSTAR_PREIS);
   printf("\n\t2: %s\t\t%5.2f", HIGHEND_NAME, HIGHEND_PREIS);
   printf("\n\t3: %s\t% 5.2f", MULTIMEDIASTAR_NAME, MULTIMEDIASTAR_PREIS);
   printf("\n\t4: %s\t\t%5.2f", OFFICESTAR_NAME, OFFICESTAR_PREIS);
   printf("\n\t0: Abbruch");
   printf("\n\n\n\tAuswahl: ");
   return 0;
}

/*
============================================================================
Funktion printMenuEinzel() - Ausgabe vom Einzel-Menue
============================================================================
*/
int printMenuEinzel(void) 
/*
Rückgabewert:    0 ==> alles OK
Es werden keine Argumente übergeben!
*/
{
   printf("\n\tE I N Z E L K O M P O N E N T E N");
   printf("\n\t=================================");
   printf("\n\n\t1: %s", GEHAEUSE_NAME);
   printf("\n\t2: %s\t\t%5.2f", MAINBOARD_NAME, MAINBOARD_PREIS);
   printf("\n\t3: %s\t\t\t%5.2f", CPU_NAME, CPU_PREIS);
   printf("\n\t4: %s\t\t%5.2f", FESTPLATTEN_NAME, FESTPLATTEN_PREIS);
   printf("\n\t5: %s\t\t%5.2f", GRAFIKKARTEN_NAME, GRAFIKKARTEN_PREIS);
   printf("\n\t0: Abbruch");
   printf("\n\n\n\tAuswahl: ");
   return 0;
}

/*
============================================================================
Funktion printMenuEinzel() - Ausgabe vom Einzel-Menue
============================================================================
*/
int printMenuGehaeuse(void) 
/*
Rückgabewert:    0 ==> alles OK
Es werden keine Argumente übergeben!
*/
{
   printf("\n\tG E H A E U S E K O M P O N E N T E N");
   printf("\n\t=====================================");
   printf("\n\n\t1: %s\t %5.2f", LX100_NAME, LX100_PREIS);
   printf("\n\t2: %s\t %5.2f", LX120_NAME, LX120_PREIS);
   printf("\n\t3: %s\t%5.2f", LX34A_NAME, LX34A_PREIS);
   printf("\n\t0: Abbruch");
   printf("\n\n\n\tAuswahl: ");
   return 0;
}

C-Programm – Palindrom

Dieses Programm teilt einen String in Wörter auf (strtok), anschließend wird jeweils geprüft ob diese von vorn und von hinten gelesen gleich bleiben und somit Palindrome sind.

#include <stdio.h>
#include <string.h>
#define LENGTH 150

// Testdatensatz:  "Ha/n/nah", "La-ger-regal", "O%t/to", "(Reit-)tier", "Reliefpfeiler", "Ren--tner", "R!o!t)or", "st--ets", "nein", "Hall67o" und "Lastwa$gen"

// Funktion: lengthOfString - die laenge von dem gegebenen String herausfinden
int lengthOfString(char wort[]) {
	int i = 0;
// solang das Ende (\0) nicht erreicht ist, wird der Wert i um 1 erhöht 
	while (wort[i] != '\0') {
        i++;
    }
    return i;
}

// Funktion: isPalindrom - prueft, ob der angegebe String ein Palindrom (lal, otto, lagerregal ...) ist
int isPalindrom(char wort[]) {
    int i;
    int length = lengthOfString(wort);

	for (i=0; wort[i] != '\0'; i++) {
	// for (i = 0; i <= (length-1); i++) { // Alternativ, solange keine Zeichen aus der Zeichenkette entfernt werden :-)
// vergleiche ersten und letzten, zweiten und vorletzten ... 
        if (wort[i] != wort[((length-1)-i)]) {
			return 0;
        }
    }
    return 1;
}

// Funktion: toLower - aus GROß wird klein -> ASCII-Tabelle anschauen ;-)
// Alternative-Funktion: tolower + ctype.h
int toLower(char wort[]) {
	int i;

	for (i=0; wort[i] != '\0'; i++) {
		if (wort[i] <= 90 && wort[i] >= 65) {
			wort[i] = wort[i]+32;
		}
	}
}

// Funktion: cleanString - entfernt '"' und ',' 
int cleanString(char wort[]) {
	int i,j;

	for (i=0, j=0; wort[i] != '\0'; i++) {
			if (wort[i] != 34 && wort[i] != 44) {
				wort[j++] = wort[i];
			}
		}
	wort[j]='\0';
}

// Funktion: removeNonLetters - entfernt Sonderzeichen aus einem String
int removeNonLetters(char wort[]) {
	int i,j;
	int alphabet_small_num = 97;
	int alphabet_big_num = 65;

	for (i=0, j=0; wort[i] != '\0'; i++) {
		while (alphabet_small_num <= 122) {
			if (wort[i] == alphabet_small_num) {
				wort[j++] = wort[i];
			}
			alphabet_small_num++;
		}
		while (alphabet_big_num <= 90) {
			if (wort[i] == alphabet_big_num) {
				wort[j++] = wort[i];
			}
			alphabet_big_num++;
		}
		alphabet_small_num = 97;
		alphabet_big_num = 65;
	}
	wort[j]='\0';
}

/*
// Alternative-Funktion: removeNonLetters + ctype.h - entfernt Sonderzeichen aus einem String
int removeNonLetters(char wort[]) {
	int i,j;

	for (i=0, j=0; wort[i] != '\0'; i++) {
		if (isalpha(wort[i])) {
			wort[j++] = wort[i];
		}
	}
	wort[j]='\0';
}
*/

// main - Hauptprogramm
int main(void) {
    char zeichenkette[LENGTH];
	char trennzeichen[] = " ";
	char *wort;

    printf("Bitte eine Zeichenkette eingeben: \n");
    fgets(zeichenkette, sizeof(zeichenkette), stdin);

	wort = strtok(zeichenkette, trennzeichen);
	while(wort != NULL) {

		cleanString(wort);

		printf("\n\nOriginal: %s\n", wort);
		if (isPalindrom(wort)) {
        	printf("Palindrom: %s\n", wort);
    	}
    	else {
        	 printf("kein Palindrom: %s\n", wort);
		}

		removeNonLetters(wort);
		printf("nach removeNonLetters: %s\n", wort);
    	if (isPalindrom(wort)) {
        	printf("Palindrom: %s\n", wort);
    	}
    	else {
        	 printf("kein Palindrom: %s \n", wort);
		}

		toLower(wort);
		printf("nach toLower: %s\n", wort);
    	if (isPalindrom(wort)) {
        	printf("Palindrom: %s \n", wort);
    	}
    	else {
    		printf("kein Palindrom: %s \n", wort);
		}
		printf("***********************************\n");

   		wort = strtok(NULL, trennzeichen); 
    }

    return 0;
}

weitere hilfreiche Tipps findest du unter: de.wikibooks.org