gcc programm1.c -o meinprog
gcc -Wall -ggdb programm1.c -o meinprog
.c
erhalten.
dateiname.txt
ist kein gültiger Name für eine Quelltextdatei in C.
Debug-Informationen. Durch den Zusatz von
-ggdb
im Aufruf vongcc
teilen Sie dem Compiler mit, diese vom Debugger benötigten Debug-Informationen mit aufzunehmen.
test.c:4: parse error before '{'
test.c:6: parse error before string constant
test.c:6: warning: data definition has no type or storage class
/tmp/ccyNzE2u.o: In function 'main':
/tmp/ccyNzE2u.o(.text+0x1f): undefined reference to 'tue_es'
collect2: ld returned 1 exit status
tue_es()
finden. Ändern Sie tue_es()
in printf()
.
main()
.
/*
und */
steht, ist ein Programmkommentar und wird
vom Compiler ignoriert. Kommentare werden verwendet, um Anmerkungen zu
Struktur und Funktionsweise des Programms in den Quelltext aufzunehmen.
#include
-Direktive teilt dem Compiler mit, bei der Kompilierung den Code
einer anderen Datei in Ihren Quellcode einzubinden.
/*
und endet erst, wenn ein */
auftaucht.
main()
obligatorisch ist. Das folgende Codefragment ist das denkbar kürzeste Programm.
Leider kann man damit jedoch nichts machen:
int main(void)
{
return 0;
}
int main(void) { return 0; }
1 : /* Ueb02_02.c */
2 : #include <stdio.h>
3 :
4 : void anzeigen_zeile(void);
5 :
6 : int main(void)
7 : {
8 : anzeigen_zeile();
9 : printf("\n C in 21 Tagen!\n");
10: anzeigen_zeile();
11: printf("\n\n");
12: return 0;
13: }
14:
15: /* Zeile mit Sternchen ausgeben */
16: void anzeigen_zeile(void)
17: {
18: int zaehler;
19:
20: for( zaehler = 0; zaehler < 34; zaehler++ )
21: printf("*" );
22: }
23: /* Ende des Programms */
/*
und */
steht. Sehen Sie im
Folgenden einige Beispiele:
/* Dies ist ein Kommentar. */
/* ??? */
/*
Dies ist ein
dritter Kommentar */
ABCDEFGHIJKLMNOPQRSTUVWXYZ
.
5
und 8
zu addieren und das Ergebnis der Variablen x
zuzuweisen.
a
gleich 10
und der Wert von x
11
.
Nach der zweiten Anweisung haben a
und x
beide den Wert 11
. (Die Anweisungen
müssen getrennt ausgeführt werden.)
1
, denn dies ist der Rest von 10
geteilt durch 3
.
19
(5 + 3) * 8 / (2 + 2)
0
<
hat eine höhere Priorität als ==
.
*
hat eine höhere Priorität als +
.
!=
und ==
haben die gleiche Priorität, deshalb werden sie von links nach rechts
ausgewertet.
>=
und >
haben die gleiche Priorität. Verwenden Sie Klammern, wenn Sie
mehr als einen Vergleichsoperator in einer Anweisung oder einem Ausdruck
verwenden müssen.
+=
, -=
, *=
, /=
und %=
.
#include <stdio.h>
int x,y;
int main(void)
{
printf("\nGeben Sie zwei Zahlen ein: ");
scanf("%d %d",&x,&y);
printf("\n\n%d ist größer\n",(x>y)?x:y);
return 0;
}
17: printf("\n%d %d", a++, ++b);
18: printf("\n%d %d", a++, ++b);
19: printf("\n%d %d", a++, ++b);
20: printf("\n%d %d", a++, ++b);
21: printf("\n%d %d\n", a++, ++b);
x
größer gleich 1
und kleiner gleich 20
ist. Wenn diese beiden Bedingungen erfüllt
sind, wird x
der Variablen y
zugewiesen. Andernfalls wird x
nicht y
zugewiesen,
und y behält seinen Wert.
if ((x >= 1) && (x <= 20))
y = x;
y = (x >= 1) && (x <= 20)) ? x : y;
if
-Anweisung WAHR
ist, wird x
der Variablen y
zugewiesen, Andernfalls wird y
sich selbst zugewiesen - d.h. der Wert ändert sich
nicht.
if (x < 1 && x > 10 )
anweisung;
7
0
9
1
5
WAHR
FALSCH
WAHR
. Beachten Sie, dass hier nur ein einfaches Gleichheitszeichen steht,
wodurch die if
-Anweisung praktisch zu einer Zuweisung wird.
WAHR
if
-Anweisung, die festlegt, ob eine Person rechtlich erwachsen
ist (Alter 21) und noch nicht das Rentenalter (Alter 65) erreicht hat.
if (alter < 18)
printf("Sie sind noch nicht erwachsen");
else if (alter >= 65)
printf("Sie haben bereits das Rentenalter erreicht");
else
printf("Sie sind ein Erwachsener");
if
-Anweisung in Zeile 6. Der dritte Fehler
wird sehr häufig gemacht: In der if
-Anweisung wird der Zuweisungsoperator (=
)
statt des Vergleichsoperators (==
) verwendet. Der letzte Fehler ist das Wort
andernfalls
in Zeile 8. Es sollte eigentlich else
heißen. Der Code lautet korrekt:
#include <stdio.h>
int x= 1;
int main(void)
{
if( x == 1)
printf(" x ist gleich 1" );
else
printf(" x ist ungleich 1");
return 0;
}
void
deklariert
werden.
main()
sollte die erste Funktion in Ihrem Listing sein.
float tue_es(char a, char b, char c)
void eine_zahl_ausgeben(int zahl)
void
-Funktion. Wie in Übung 1 können Sie daraus einen
Funktionsprototyp machen, indem Sie an das Ende der Zeile ein Semikolon
setzen. Als Funktions-Header sollte diese Zeile von den in geschweiften Klammern
stehenden Funktionsanweisungen gefolgt werden.
int
long
print_msg()
als void
deklariert, liefert aber einen Wert zurück. Sie sollten die return
-
Anweisung entfernen. Das zweite Problem befindet sich in Zeile 5. Bei dem
Aufruf von print_msg()
wird ein Parameter (ein String) übergeben. In dem
Funktionsprototyp wurde aber angegeben, dass die Parameterliste der Funktion
leer ist - weswegen ihr nichts übergeben werden sollte. Sehen Sie nachstehend
das korrigierte Listing:
#include <stdio.h>
void print_msg( void );
int main(void)
{
print_msg();
return 0;
}
void print_msg( void )
{
puts( "Diese Nachricht soll ausgegeben werden." );
}
groesser_von()
geändert werden.
int groesser_von( int a, int b)
{
int tmp;
if (a > b)
tmp = a;
else
tmp = b;
return tmp;
}
int groesser_von( int a, int b)
{
return (a > b) ? a : b ;
}
int produkt(int x, int y)
{
return (x * y);
}
int teile(int a, int b)
{
if (b == 0)
return 0;
return (a / b);
}
main()
wie im folgenden Beispiel könnte auch jede andere Funktion die
Funktionen produkt()
und teile()
aufrufen.
#include <stdio.h>
int produkt(int x, int y);
int teile(int a, int b);
int main (void)
{
int zahl1 = 10,
zahl2 = 5;
int x, y, z;
x = produkt(zahl1, zahl2);
y = teile(zahl1, zahl2);
z = teile(zahl1, 0);
printf("zahl1 ist %d und zahl2 ist %d\n", zahl1, zahl2);
printf("zahl1 * zahl2 gleich %d\n", x);
printf("zahl1 / zahl2 gleich %d\n", y);
printf("zahl1 / 0 gleich %d\n", z);
return 0;
}
int produkt(int x, int y)
{
return (x * y);
}
int teile(int a, int b)
{
if (b == 0)
return 0;
return (a / b);
}
#include <stdio.h>
float mittelwert (float a, float b, float c, float d, float e);
int main (void)
{
float v, w, x, y, z, antwort;
puts("Geben Sie 5 Zahlen ein:");
scanf("%f%f%f%f%f", &v, &w, &x, &y, &z);
antwort = mittelwert(v, w, x, y, z);
printf("Der Mittelwert beträgt %f\n", antwort);
return 0;
}
float mittelwert (float a, float b, float c, float d, float e)
{
return ((a+b+c+d+e)/5);
}
int
. Sie funktioniert nur,
wenn Werte kleiner oder gleich 19
eingegeben werden.
#include <stdio.h>
int drei_hoch(int exponent);
int main (void)
{
int a = 4, b = 19;
printf("3 hoch %d gleich %d\n", a, drei_hoch(a));
printf("3 hoch %d gleich %d\n", b, drei_hoch(b));
return 0;
}
int drei_hoch (int exponent)
{
if (exponent < 1)
return 1;
else
return 3 * drei_hoch(exponent -1);
}
0
.
for
-Anweisung enthält als Teil des Befehls Ausdrücke für die Initialisierung,
Bedingung und Inkrementierung/Dekrementierung, während die while
-
Anweisung nur einen Bedingungsteil enthält.
Bei einer
do...while
-Anweisung steht diewhile
-Bedingung nach dem Anweisungsblock, weshalb die Schleife mindestens einmal ausgeführt wird.
while
-Anweisung kann die gleichen Aufgaben erledigen wie eine for
-
Anweisung. Allerdings werden dann noch zwei weitere Schritte erforderlich. Sie
müssen alle Variablen vor dem Start der Schleife initialisieren und das
Inkrementieren beziehungsweise Dekrementieren innerhalb der while
-Schleife
vornehmen.
while
-Anweisung kann in einer do...while
-Anweisung untergebracht
werden. Sie können jeden Befehl innerhalb eines Schleifenblocks verschachteln.
for
-Anweisung lauten: Initialisierung, Bedingung,
Inkrementierung und Anweisung(en).
while
-Anweisung lauten: Bedingung und Anweisung(en).
do...while
-Anweisung lauten: Bedingung und
Anweisung(en).
long array[50];
49
erhält. Dies liegt
daran, dass Array-Indizes mit 0
beginnen.
array[49] = 123,456;
x
den Wert 100
.
ctr
den Wert 11
. (cptr
beginnt bei 2
und
wird um 3
inkrementiert, solange sie kleiner als 10
ist.)
X
aus. Die äußere Schleife führt die innere Schleife
10-mal aus. Das bedeutet, dass insgesamt 50 X
ausgegeben werden.
int x;
for(x = 1; x <= 100; x +=3);
int x = 1;
while(x <= 100)
x += 3;
int x = 1;
do
{
x += 3;
}
while(x <= 100)
datensatz
wird mit 0
initialisiert. Die
while
-Schleife überprüft dann, ob datensatz
kleiner als 100
ist. 0
ist kleiner als
100,
und deshalb wird die Schleife ausgeführt und gibt die zwei Meldungen aus.
Anschließend wird die Bedingung erneut geprüft. 0
ist immer noch kleiner als 100
,
so dass die Schleife erneut ausgeführt wird. Damit dieser Code korrekt ausgeführt
wird, muss datensatz
innerhalb der Schleife wie folgt inkrementiert werden:
datensatz = 0;
while (datensatz < 100)
{
printf( "\nDatensatz %d ", datensatz );
printf( "\nNächste Zahl..." );
datensatz++;
}
for
-Anweisung
sollte kein Semikolon stehen. Dieser Fehler kommt sehr häufig vor.
puts()
und printf()
.
printf()
kann Variablenparameter ausgeben.
puts()
gibt immer ein Neue-Zeile-Zeichen nach dem String aus.
printf()
die Header-Datei stdio.h
einbinden.
\\
gibt einen Backslash aus
\b
gibt einen Backspace aus
\n
gibt einen Zeilenumbruch aus
\t
gibt einen Tabulator aus
\a
(für Alarm) gibt ein akustisches Signal aus
%s
für einen Zeichenstring
%d
für eine vorzeichenbehaftete Dezimalzahl
%f
für eine Fließkommazahl
b
gibt das Zeichen b aus
\b
gibt einen Backspace aus
\
betrachtet das nächste Zeichen als Escape-Sequenz (siehe Tabelle 6.1)
\\
gibt einen Backslash aus
puts()
-Anweisung gibt automatisch eine neue Zeile aus, printf()
hingegen
nicht.
puts("");
printf("\n");
char c1, c2;
unsigned int d1;
scanf("%c %ud %c", c1, d1, c2);
#include <stdio.h>
int main(void)
{
int x;
puts("Geben Sie einen Integer ein:");
scanf("%d", &x);
printf("Der eingegebene Wert lautete %d.\n", x);
return 0;
}
#include <stdio.h>
int main(void)
{
int x;
puts("Geben Sie eine gerade Zahl ein:");
scanf("%d", &x);
while (x % 2 != 0)
{
printf("%d ist keine gerade Zahl.\nVersuchen Sie es erneut\n",x);
scanf("%d", &x);
}
printf("Der eingegebene Wert lautete %d.\n", x);
return 0;
}
#include <stdio.h>
int main(void)
{
int array[6], x, zahl;
/* Durchlaufen Sie die Schleife 6-mal oder
bis der letzte Wert 99 beträgt. */
for(x = 0; x < 6 && zahl != 99; x++)
{
puts("Geben Sie eine gerade Zahl ein oder 99 zum Verlassen:");
scanf("%d", &zahl);
while (zahl % 2 == 1 && zahl != 99)
{
printf("%d ist keine gerade Zahl.\nVersuchen Sie es erneut\n",x);
scanf("%d", &zahl);
}
array[x] = zahl;
}
/* Geben Sie sie jetzt aus. */
for(x = 0; x < 6 && zahl != 99; x++)
printf("Der eingegebene Wert lautete %d.\n", array [x]);
return 0;
}
printf()
. Um jeden Wert durch einen Tabulator
getrennt auszugeben, muss die endgültige printf()
-Anweisung wie folgt lauten:
printf ("%d\t", array [x]);
printf( "Jack sagte, \"Fischers Fritze fischt frische Fische.\"");
printf()
-Anweisung, der zweite Fehler in dem
fehlenden Adressoperator in dem Aufruf von scanf()
. Der letzte Fehler liegt
ebenfalls in der scanf()
-Anweisung. Die Variable antwort
ist vom Typ int
, und
der korrekte Konversionsspezifizierer für Integer-Werte lautet %d
und nicht %f
.
Folgendes wäre korrekt:
int hole_1_oder_2( void )
{
int antwort = 0;
while (antwort < 1 || antwort > 2)
{
printf("1 für Ja, 2 für Nein eingeben");
scanf( "%d", &antwort );
}
return antwort;
}
bericht_anzeigen()
-Funktion.
void bericht_anzeigen( void )
{
printf( "\nMUSTERBERICHT" );
printf( "\n\nSequenz\Bedeutung" );
printf( "\n=========\t=======" );
printf( "\n\\a\t\tGlocke (Akustisches Signal)" );
printf( "\n\\b\t\tBackspace" );
printf( "\n\\n\t\tNeue Zeile" );
printf( "\n\\t\t\tHorizontaler Tabulator" );
printf( "\n\\\\\t\tBackslash" );
printf( "\n\\\?\t\tFragezeichen" );
printf( "\n\\\'\t\tEinfache Anführungszeichen" );
printf( "\n\\\"\t\tDoppelte Anführungszeichen" );
printf( "\n...\t\t...");
}
/* Liest zwei Fliesskommazahlen ein und */
/* gibt ihr Produkt aus. */
#include <stdio.h>
int main(void)
{
float x, y;
puts("Geben Sie zwei Werte ein: ");
scanf("%f %f", &x, &y);
printf("Das Produkt von %f und %f ist %f.\n", x, y, x*y);
return 0;
}
#include <stdio.h>
int main(void)
{
int count, temp, gesamt = 0;
for(count = 1; count <= 10; count++)
{
printf("Geben Sie den %d-ten Integer-Wert ein: ", count);
scanf("%d", &temp);
gesamt += temp;
}
printf("Die Gesamtsumme beträgt %d.\n", gesamt);
return 0;
}
#include <stdio.h>
#define MAX 100
int main(void)
{
int array [MAX];
int count = -1, maximum, minimum, eingegeben, temp;
puts("Geben Sie einen Integer pro Zeile ein.");
puts("Geben Sie 0 ein, wenn Sie fertig sind.");
do
{
scanf("%d", &temp);
array[++count] = temp;
} while (count < (MAX-1) && temp != 0);
eingegeben = count;
/* Suchen Sie den größten und kleinsten Wert. */
/* Am Anfang ist der erste Wert sowohl */
/* Maximum als auch Minimum . */
maximum = minimum = array [0];
for(count = 1; count < eingegeben; count++)
{
if (array[count] > maximum)
maximum = array[count];
if (array[count] < minimum)
minimum = array[count];
}
printf("Der größte Wert ist %d.\n", maximum);
printf("Der kleinste Wert ist %d.\n", minimum);
return 0;
}
0
.
n-1
.
240
. Diesen Wert erhalten Sie durch die Multiplikation von 2*3*5*8.
array [0][0][1][1]
int eins[1000], zwei[1000], drei[1000];
int array [10] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
int achtundachtzig[88] = { 88, 88, 88, 88, 88, 88, 88,
88, 88, ...... , 88 };
int achtundachtzig[88];
int x;
for(x = 0; x < 88 x++)
achtundachtzig[x] = 88;
int stuff [12][10];
int sub1, sub2;
for(sub1 = 0; sub1 < 12; sub1++)
for(sub2 = 0; sub2 < 10 ; sub2++)
stuff [sub1][sub2] = 0;
Seien Sie vorsichtig mit diesem Codefragment, denn dieser Fehler passiert sehr leicht: Das Array ist als
10*3
-Array deklariert, wird aber als3*10
-Array initialisiert. Nähern wir uns dem Problem von einer anderen Seite. Der linke Index wurde als10
deklariert, aber diefor
-Schleife verwendetx
als linken Index und inkrementiertx
nur dreimal. Der rechte Index ist als3
deklariert, aber die zweite Schleife verwendety
als Index und inkrementierty
zehnmal. Dies wird zu unerwarteten Ergebnissen führen, schlimmstenfalls stürzt Ihr Programm ab. Der Fehler im Programm lässt sich auf zwei Arten beheben. Zum einen können Siex
undy
in der Zuweisung vertauschen:
int x, y;
int array[10][3];
int main(void)
{
for ( x = 0; x < 3; x++ )
for ( y = 0; y < 10; y++ )
array[y][x] = 0; /* geändert! */
return 0;
}
for
-
Schleifen zu tauschen:
int x, y;
int array[10][3];
int main(void)
{
for ( x = 0; x < 10; x++ ) /* geändert! */
for ( y = 0; y < 3; y++ ) /* geändert! */
array[x][y] = 0;
return 0;
}
array[10]
nicht initialisieren, da es nicht existiert. Die for
-Anweisung
sollte wie folgt geändert werden (zwei Möglichkeiten):
for ( x = 1; x <= 9; x++ ) /* initialisiert 9 der 10 Elemente */
for ( x = 0; x < 10; x++ )
x <= 9
gleichbedeutend ist mit x < 10
. Beides ist möglich,
obwohl meist x < 10
verwendet wird.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int array[5][4];
int a, b;
for(a = 0 ; a < 5; a++)
for(b = 0; b < 4; b++)
array[a][b] = rand();
/* Gibt die Array-Elemente aus. */
for(a = 0 ; a < 5; a++)
{
for(b = 0; b < 4; b++)
printf("%12d\t", array [a][b]);
printf("\n"); /* Springt in eine neue Zeile */
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
short zufall[1000];
int a;
int total = 0;
for(a = 0 ; a < 1000; a++)
{
zufall[a] = rand();
total += zufall[a];
}
printf("Durchschnitt ist %d\n", total / 1000);
/* Elemente in !0-Einheiten anzeigen. */
for(a = 0 ; a < 1000; a++)
{
printf("Zufallszahl [%4d] = %d\n", a, zufall[a]);
if (a % 10 == 0 && a > 0)
{
printf("Weiter mit Eingabetaste, Verlassen mit STRG-C.\n");
getchar();
}
}
return 0;
}
#include <stdio.h>
int main(void)
{
int elemente[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int idx;
for(idx = 0 ; idx < 10; idx++)
printf("elemente[%d] = %d\n", idx, elemente[idx]);
return 0;
}
#include <stdio.h>
int main(void)
{
int elemente[10];
int idx;
for(idx = 0 ; idx < 10; idx++)
elemente[idx] = idx;
for(idx = 0 ; idx < 10; idx++)
printf("elemente[%d] = %d\n", idx, elemente[idx]);
return 0;
}
#include <stdio.h>
int main(void)
{
int elemente[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int neues_array [10];
int idx;
for(idx = 0 ; idx < 10; idx++)
neues_array[idx] = elemente[idx] + 10;
for(idx = 0 ; idx < 10; idx++)
printf("elemente[%d] = %d\nneues_array[%d] = %d\n",
idx, elemente[idx], idx, neues_array [idx]);
return 0;
}
&
).
*
verwendet. Wenn Sie dem Namen des Zeiger
ein *
voranstellen, beziehen Sie sich auf den Wert, auf den gezeigt wird.
&daten[0]
und daten
.
1
. Die Größe der Elemente im Array hat
keine Bedeutung.
1
.
void
kann auf C-Datenobjekte beliebiger Typen zeigen. Mit
anderen Worten, es handelt sich um einen allgemeinen, einen generischen Zeiger.
void
-Zeigers können Sie einen generischen Zeiger
erzeugen, der auf ein beliebiges Datenobjekt zeigt. Am häufigsten werden void
-
Zeiger eingesetzt, um Funktionsparameter zu deklarieren, die Argumente
verschiedener Typen akzeptieren.
void
-Zeiger zur Zeit zeigt. Sie müssen einen void
-Zeiger umwandeln,
bevor Sie ihn dereferenzieren können.
char *char_zgr;
int
und weist ihm dann die
Adresse von kosten
(&kosten
) zu:
int *z_kosten;
p_cost = &cost;
kosten = 100;
*z_kosten = 100;
printf("Zeigerwert : %p, zeigt auf Wert : %d\n",
z_kosten, *z_kosten);
float *variable = &radius
;
daten[2] = 100;
*(daten+2) = 100;
#include <stdio.h>
#define MAX1 5
#define MAX2 8
int array1[MAX1] = { 1, 2, 3, 4, 5 };
int array2[MAX2] = { 1, 2, 3, 4, 5, 6, 7, 8 };
int total;
int sumarrays(int x1[], int laen_x1, int x2[], int laen_x2);
int main(void)
{
total = sumarrays(array1, MAX1, array2, MAX2);
printf("Die Gesamtsumme beträgt %d\n", total);
return 0;
}
int sumarrays(int x1[], int laen_x1, int x2[], int laen_x2)
{
int total = 0, count = 0;
for (count = 0; count < laen_x1; count++)
total += x1[count];
for (count = 0; count < laen_x2; count++)
total += x2[count];
return total;
}
/* Übung 8.9 */
#include <stdio.h>
#define GROESSE 10
/* Funktionsprototypen */
void addarrays( int [], int []);
int main(void)
{
int a[GROESSE] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
int b[GROESSE] = {9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
addarrays(a, b);
return 0;
}
void addarrays( int erstes[], int zweites[])
{
int total[GROESSE];
int ctr = 0;
for (ctr = 0; ctr < GROESSE; ctr ++ )
{
total[ctr] = erstes[ctr] + zweites[ctr];
printf("%d + %d = %d\n", erstes[ctr], zweites[ctr], total[ctr]);
}
}
char buchstabe = '$';
char array[21] = "Zeiger machen Spass!";
char *array = "Zeiger machen Spass!";
char *zgr;
zgr = malloc(81);
fgets(zgr,81,stdin);
/* Übung 9.5 */
#include <stdio.h>
#define GROESSE 10
/* Funktionsprototypen */
void kopiere_arrays( char [], char []);
int main(void)
{
int ctr=0;
char a[GROESSE] = {'1', '2', '3', '4', '5', '6',
'7', '8', '9', '0'};
char b[GROESSE];
/* Werte vor dem Kopieren */
for (ctr = 0; ctr < GROESSE; ctr ++ )
{
printf( "a[%d] = %c, b[%d] = %c\n",
ctr, a[ctr], ctr, b[ctr]);
}
kopiere_arrays(a, b);
/* Werte nach dem Kopieren */
for (ctr = 0; ctr < GROESSE; ctr ++ )
{
printf( "a[%d] = %c, b[%d] = %c\n",
ctr, a[ctr], ctr, b[ctr]);
}
return 0;
}
void kopiere_arrays( char quelle[], char ziel[])
{
int ctr = 0;
for (ctr = 0; ctr < GROESSE; ctr ++ )
{
ziel[ctr] = quelle[ctr];
}
}
/* Übung 9.6 */
#include <stdio.h>
#include <string.h>
/* Funktionsprototypen */
char * vergleiche_strings( char *, char *);
int main(void)
{
char *a = "Hallo";
char *b = "Programmierer!";
char *laenger;
laenger = vergleiche_strings(a, b);
printf( "Der längere String ist: %s\n", laenger );
return 0;
}
char * vergleiche_strings( char * erster, char * zweiter)
{
int x, y;
x = strlen(erster);
y = strlen(zweiter);
if( x > y)
return(erster);
else
return(zweiter);
}
ein_string
ist als ein Array von zehn Zeichen deklariert, wird aber mit einem
String initialisiert, der länger als zehn Zeichen ist. ein_string
muss größer sein.
*zitat
oder zitat[100]
verwenden.
strcpy()
, umwandeln.
struct
meineadresse
. Das Strukturelement meineadresse.name
wird mit Bradley
Jones
initialisiert, meineadresse.adr1
mit RTSoftware
, meineadresse.adr2
mit P.O. Box
1213
, meineadresse.stadt
mit Carmel
, meineadresse.staat
mit IN
und
meineadresse.plz
mit 46032-1213
.
zgr
so, dass der Zeiger auf das zweite Array-
Element zeigt:
zgr++;
struct zeit
{ int stunden;
int minuten;
int sekunden ;
} ;
struct daten
{ int wert1;
float wert2, wert3;
} info;
info.wert1 = 100;
struct daten *ptr;
ptr = &info;
ptr->wert2 = 5.5;
(*ptr).wert2 = 5.5;
struct daten
{ char name [21]
};
typedef struct
{ char adresse1[31];
char adresse2[31];
char stadt[11];
char staat[3];
char plz[11];
} DATENSATZ;
DATENSATZ meineadresse = { "RTSoftware",
"P.O. Box 1213",
"Carmel", "IN", "46082-1213"};
zeichen
falsch. Die
Initialisierungswerte sollten in geschweiften Klammern stehen. Und so sieht der
Code korrekt aus:
struct tierkreis
{ char tierkreiszeichen [21];
int monat ;
} zeichen = { "Löwe", 8 } ;
union
ist nur in einer Hinsicht falsch. Es kann immer nur eine
Variable der Union zur Zeit verwendet werden. Das gilt auch für die Initialisierung
der Union. So sähe die korrekte Initialisierung aus:
/* eine Union einrichten */
union daten{
char ein_wort[4];
long eine_zahl;
} generische_variable = { "WOW" } ;
0
initialisiert. Es ist
jedoch immer besser, Variablen explizit zu initialisieren.
count
lokal zu dem Block ist, hat die Funktion
printf()
nicht länger Zugriff auf eine Variable namens count
. Der Compiler wird
eine Fehlermeldung ausgeben.
int
-Variable namens vari
lautete die Deklaration
beispielsweise:
static int vari;
extern
wird als Speicherklassen-Modifizierer verwendet. Es
weist darauf hin, dass die Variable irgendwo sonst in dem Programm deklariert
worden ist.
static
wird als Speicherklassen-Modifizierer verwendet. Es teilt
dem Compiler mit, den Wert einer Variablen oder Funktion für die Dauer des
Programms zu behalten. Innerhalb einer Funktion behält die Variable ihren Wert
zwischen den Funktionsaufrufen.
register int x = 0;
/* Übung 11.2 */
#include <stdio.h>
void wert_ausgeben (int x);
int main(void)
{
int x = 999;
printf("%d\n", x);
wert_ausgeben(x);
return 0;
}
void wert_ausgeben (int x)
{
printf("%d\n", x);
}
var
als global deklarieren, müssen Sie sie nicht als Parameter
übergeben.
/* Übung 11.3 */
#include <stdio.h>
void wert_ausgeben(void);
int var = 99;
int main(void)
{
wert_ausgeben();
return 0;
}
void wert_ausgeben (void)
{
printf("Der Wert ist %d.\n", var);
}
var
übergeben, um sie in einer anderen Funktion
auszugeben.
/* Übung 11.4 */
#include <stdio.h>
void wert_ausgeben (int x);
int main(void)
{
int var = 99;
wert_ausgeben(var);
return 0;
}
void wert_ausgeben (int x)
{
printf("Der Wert ist %d.\n", x);
}
/* Übung 11.5 */
#include <stdio.h>
void wert_ausgeben(void);
int var = 99;
int main(void)
{
int var = 77;
printf ("Ausgabe in Funktion mit lokaler u. globaler Variablen.\n");
printf("Der Wert von var ist %d.\n", var);
wert_ausgeben();
return 0;
}
void wert_ausgeben (void)
{
printf("Der Wert ist %d.\n", var);
}
eine_beispiel_funktion()
weist nur ein Problem auf. Variablen
müssen zu Beginn eines Blocks deklariert werden, so dass die Deklarationen von
ctr1
und sternchen
korrekt sind. Die andere Variable, ctr2
, wird jedoch nicht zu
Beginn des Blocks deklariert. Diese Art der Deklaration ist in C++ zulässig, aber
nicht in C. Sehen Sie im Folgenden ein vollständiges Programm mit der
korrigierten Funktion.
/* Übung 11.6 */
#include <stdio.h>
void eine_beispiel_funktion( void );
int main(void)
{
eine_beispiel_funktion();
puts("");
return 0;
}
void eine_beispiel_funktion( void )
{
int ctr1;
for ( ctr1 = 0; ctr1 < 25; ctr1++ )
printf( "*" );
puts( "\nDies ist eine Beispielfunktion" );
{
char sternchen = '*';
int ctr2; /* Damit wird der Fehler behoben. */
puts( "\nEs gibt kein Problem\n" );
for ( ctr2 = 0; ctr2 < 25; ctr2++ )
{
printf( "%c", sternchen);
}
}
}
x
mit 1
zu initialisieren, da sie
bereits in der for
-Anweisung mit 0
initialisiert wird. Außerdem ist es nicht nötig,
die Variable anzahl
als statisch zu deklarieren, denn das Schlüsselwort static
hat
in der main()
-Funktion keine Auswirkung.
sternchen
und strich
? Diese zwei Variablen werden nicht
initialisiert. Da beide lokale Variablen sind, könnten sie jeden Wert enthalten.
Denken Sie daran, dass dieses Programm, auch wenn es sich ohne
Fehlermeldungen oder Warnungen kompilieren lässt, trotzdem noch zu einem
Problem werden kann.
ctr
wird als global deklariert, aber nur in funktion_ausgeben()
verwendet. Diese
Zuweisung ist nicht besonders glücklich. Das Programm wäre besser, wenn ctr
eine lokale Variable zu der Funktion funktion_ausgeben()
wäre.
X==X==X==X==X==X==X==X==X==X==X==X==X==X==X==X==...
ctr
, denn main()
und buchstabe2_ausgeben()
verwenden beide die
Variable ctr
in ihren verschachtelten Schleifen. Da buchstabe2_ausgeben()
den
Wert ändert, wird die for
-Schleife in main()
nie abgeschlossen. Den Fehler
können Sie auf verschiedene Arten beheben, aber am besten wäre es, wenn Sie
sowohl in main()
als auch in buchstabe2_ausgeben()
eine lokale Variable ctr
deklarierten.
buchstabe1
und
buchstabe2
in die Funktionen zu verschieben, in denen sie benötigt werden.
#include <stdio.h>
void buchstabe2_ausgeben(void);
int main(void)
{
char buchstabe1 = 'X';
int ctr;
for( ctr = 0; ctr < 10 ; ctr++ )
{
printf("%c", buchstabe1);
buchstabe2_ausgeben();
}
puts ("");
return 0;
}
void buchstabe2_ausgeben(void)
{
char buchstabe2 = '=';
int ctr; /* Diese Variable ist lokal */
/* sie unterscheidet sich von ctr in main() */
for( ctr = 0; ctr < 2 ; ctr++ )
printf("%c", buchstabe2);
}
goto
-Anweisung macht den Code wesentlich verständlicher.)
break
-Anweisung trifft, verlässt die Ausführung
sofort die for
-, while
- oder do...while
-Schleife, welche die break
-Anweisung
enthält. Wenn das Programm auf eine continue
-Anweisung trifft, beginnt sofort
der nächste Durchlauf der Schleife.
for
-, while-
oder do...while
-Schleife mit einer Bedingung verknüpft, die immer
wahr
ist.
main()
erreicht oder die Funktion exit()
aufgerufen wird.
switch
-Anweisung kann zu einem Wert von Typ long
, int
oder char
ausgewertet werden.
default
-Anweisung ist ein spezieller Fall in der switch
-Anweisung. Wenn der
Ausdruck in der switch
-Anweisung in einen Wert resultiert, zu dem es keine
übereinstimmende case
-Konstante gibt, springt die Programmausführung zu
default
.
exit()
beendet das Programm. Dieser Funktion kann ein Wert
übergeben werden, der an das Betriebssystem zurückgegeben wird.
system()
führt einen Befehl des Betriebssystems aus.
continue;
break;
system ("/bin/ls");
break
-Anweisung nach dem 'N'-Fall,
da die switch
-Anweisung hier sowieso endet.
default
) am Ende der switch
-
Anweisung stehen muss, aber dem ist nicht so. Der default
-Fall kann irgendwo in
der switch
-Anweisung stehen. Der Fehler in diesem Code liegt darin, dass am
Ende der default
-Anweisung keine break
-Anweisung steht.
if (option == 1)
printf("Ihre Antwort lautete 1");
else if (option == 2)
printf("Ihre Antwort lautete 2");
else
printf("Sie haben nicht 1 oder 2 gewählt");
do {
/* beliebige C-Anweisungen. */
} while (1);
stdin
(die Tastatur), stdout
(der Bildschirm) und stderr
(der Bildschirm).
stdout
.
stdout
.
stdin
.
stdin
.
fprintf()
kann einen beliebigen Ausgabestream verwenden - beispielsweise
stdout
oder stderr
.
EOF
-Zeichen kann nicht mit ungetc()
in den Eingabestream
zurückgestellt werden.
q
ist kein gültiger Formatspezifizierer.
stderr
gepuffert ist und stdout
nicht.
printf("Hallo Welt");
fprintf(stdout, "Hallo Welt");
puts("Hallo Welt");
fprintf(stderr, "Hallo Standardfehlerausgabe");
char puffer[31];
scanf("%30[^*]s"", puffer);
printf("Hans fragte, \"Was ist ein Backslash\?\"\nGrete sagte, \"Es ist ein \'\\\'\");
float x;
float *px = &x;
float **px = &px;
100
px
und nicht x
zugewiesen wird. Die Anweisung sollte mit
einem doppelten Indirektionsoperator geschrieben werden:
**ppx = 100;
array
ist ein Array mit zwei Elementen. Jedes dieser Elemente ist selbst ein Array,
das drei Elemente enthält. Jedes dieser drei Elemente ist ein Array, das vier int
-
Variablen enthält.
array[0][0]
ist ein Zeiger auf das erste vierelementige Array vom Typ int[]
.
void funk(char *zgr[]);
NULL
-Zeiger.
char (*zgr)(char *x[]);
*zgr
vergessen, ist die Zeile ein Prototyp einer
Funktion, die einen Zeiger vom Typ char
zurückliefert.
void
-Zeiger kann nicht inkrementiert werden, da der Compiler die
Größe des Objekts, auf den der Zeiger zeigt, nicht kennt.
NULL
ist, heißt das, dass die Liste leer ist.
var1
ist ein Zeiger auf einen Integer.
var2
ist ein Integer.
var3
ist ein Zeiger auf einen Zeiger auf Integer.
a
ist ein Array von 36 (3 * 12) Integer-Elementen.
b
ist ein Zeiger auf ein Array von zwölf Integer-Elementen.
c
ist ein Array von zwölf Zeigern auf Integer-Elemente.
z
ist ein Array von zehn Zeigern auf Zeichen.
y
ist eine Funktion, die ein Integer-Argument übernimmt und einen Zeiger auf
ein Zeichen zurückliefert.
x
ist ein Zeiger auf eine Funktion, die ein Integer-Argument übernimmt und
ein Zeichen zurückliefert.
float (*funk)(int field);
int (*menue-optionen[10])(char *titel);
char *zgr[10];
zgr
wird als ein Array von zwölf Zeigern auf Integer-Werte deklariert und nicht
als Zeiger auf ein Array von zwölf Integer-Werten. Der korrekte Code lautet:
int x[3][12];
int (*zgr)[12];
zgr = x;
struct freund
{
char name[32];
char adresse[64];
struct freund *next;
};
int funktion(char *zgr[]);
void
ist, lautet der Prototyp der
Funktion zahlen()
wie folgt:
void zahlen(int *a, int *b, int *c);
zahlen()
in Übung 9 aufzurufen, müssen Sie den
Adressoperator verwenden:
zahlen (&int1, &int2, &int3);
nbr
zeigt, und multipliziert ihn mit sich selbst.
'\n'
), das C zur Markierung des Zeilenendes verwendet, in die
Zeilenumbruch/Wagenrücklauf-Kombination ("\n\r"
) um, die Windows zur
Markierung des Zeilenendes verwendet.
fopen()
das Zeichen b
als Teil des
Modus-Strings angeben.
fopen()
öffnen.
fopen()
verwenden, müssen Sie den Namen der zu öffnenden Datei
angeben und den Modus, in dem geöffnet werden soll. Die Funktion fopen()
liefert einen Zeiger auf den Typ FILE
zurück. Dieser Zeiger wird in nachfolgenden
Dateizugriffsfunktionen verwendet, um auf die spezielle Datei Bezug zu nehmen.
EOF
ist eine symbolische Konstante, die -1
entspricht und das Ende
einer Datei markiert.
feof()
. In Textdateien können Sie sowohl nach dem EOF
-Zeichen Ausschau halten
als auch feof()
verwenden.
rewind()
oder fseek()
verschieben.
0
. Die einzige Ausnahme hierzu sind
Dateien, die im Anhängen-Modus geöffnet wurden, da der Dateipositionszeiger in
diesem Fall auf das Ende der Datei gesetzt wird.
fcloseall();
rewind(fp);
fseek(fp, 0, SEEK_SET);
EOF
-Zeichen enthalten können. Es wäre besser, die feof()
-Funktion zu
verwenden.
strlen()
ermitteln.
strcmp()
vergleicht zwei komplette Strings, während strncmp()
nur
eine bestimmte Anzahl von Zeichen innerhalb der Strings vergleicht.
strcmp()
vergleicht zwei Strings unter Berücksichtigung der Groß-
und Kleinschreibung (das heißt, 'a'
und 'A'
werden als unterschiedliche
Buchstaben betrachtet). Mit der Funktion strcasecmp()
können die Vergleiche
ohne Rücksicht auf die Groß- und Kleinschreibung durchgeführt werden. ('a'
und
'A'
werden als gleich betrachtet.)
isascii()
-Funktion prüft, ob ein Zeichen innerhalb des Wertebereichs 0 bis
127 liegt.
isascii()
und iscntrl()
würden beide wahr
zurückliefern. Alle
andern liefern falsch zurück.
65
entspricht dem Zeichen 'A'
. Die folgenden Makros liefern wahr
zurück: isalnum()
, isalpha()
, isascii()
, isgraph()
, isprint()
und isupper()
.
1
) oder Falsch (0
).
65
81
-34
0
12
0
65.000000
81.230000
-34.200000
0.000000
12.00000
1000.0000
string2
wird verwendet, ohne dass zuvor Speicher für den String reserviert
wurde. Es ist daher unmöglich, vorherzusagen, wohin strcpy()
den Wert von
string1
kopiert.
double
.
time_t
dem Typ
long
.
time()
liefert die Anzahl der Sekunden, die seit dem 1. Januar 1970
um Mitternacht verstrichen sind, zurück, die Funktion clock()
liefert die Anzahl
Millionstelsekunden seit Programmbeginn zurück.
perror()
gibt lediglich eine Meldung aus, die den Fehler
beschreibt.
va_start()
sollte verwendet werden, um die Argumentenliste zu initialisieren.
va_arg()
sollte verwendet werden, um auf die Argumente zuzugreifen, und
va_end()
sollte verwendet werden, um nach der Verarbeitung der Argumente
aufzuräumen
bsearch()
durchsuchen, müssen Sie es in aufsteigender
Reihenfolge sortieren.
0,
wenn die Werte gleich sind, >0,
wenn der Wert von Element 1 größer ist als
Element 2, und <0,
wenn Element 1 kleiner ist als Element 2.
NULL
bsearch(meinname, namen, (sizeof(namen)/sizeof(namen[0])),
sizeof(namen[0]), vergl_namen);
qsort()
keine Feldlänge
angegeben. Zweitens sollten hinter dem Funktionsnamen qsort()
keine
Klammern stehen und drittens fehlt dem Programm die Vergleichsfunktion.
qsort()
verwendet vergleich_funktion()
, die im Programm nicht definiert ist.
element1 > element2
, und einen negativen Wert, wenn
element1 < element2
.
va_list
, va_start()
, va_arg()
und va_end()
.
Siehe Listing 17.5 für die korrekte Anwendung von beliebig langen
Parameterlisten.
malloc(
) reserviert eine bestimmte Anzahl an Byte, während
calloc()
ausreichend Speicher für eine vorgegebene Anzahl an Elementen einer
bestimmten Größe reserviert. Mit calloc()
werden außerdem die Bytes im
Speicher auf 0
gesetzt, wohingegen malloc()
keine Initialisierung vornimmt.
long
int
char
float
float
memmove()
arbeitet auch dann korrekt, wenn sich die
Speicherbereiche von Quelle und Ziel überlappen (im Gegensatz zu der Funktion
memcpy()
). Wenn sich Quell- und Zielbereiche nicht überlappen, sind die beiden
Funktionen identisch.
struct datum
{
unsigned monat : 4;
unsigned tag : 5;
unsigned jahr : 7;
};
monat
kann
Werte von 0
bis 15
enthalten, was für die Aufnahme der zwölf Monate ausreicht.
Entsprechend kann das 5-Bit-Feld tag
Werte von 0
bis 31
und das 7-Bit-Feld jahr
Werte von 0
bis 127
aufnehmen Wir setzen dabei voraus, dass sich das Jahr aus
der Addition von 1900 plus dem abgespeicherten Wert errechnet, so dass
Jahreswerte von 1900 bis 2027 möglich sind.
16000
500
OR
mit dem binären Wert 11111111
führt zum gleichen Ergebnis wie die
Verwendung des Komplement-Operators. Jedes Bit in den ursprünglichen Werten
wird umgekehrt.
long *zgr;
zgr = malloc (1000 * sizeof(long));
long *zgr;
zgr = calloc (1000, sizeof(long));
int count;
for(count = 0 ; count < 1000; count++)
daten[count] = 0;
memset()
-Funktion:
memset(daten, 0, 1000 * sizeof(float));
zahl1
als auch zahl2
Integer-Variablen sind, ist das Ergebnis ihrer Division ein Integer-Wert. Dabei geht
ein möglicher Nachkommateil der Antwort verloren. Um eine korrekte Antwort
zu erhalten, müssen Sie den Typ des Ausdrucks in float
umwandeln:
antwort = (float) zahl1 / zahl2;
p
ein void
-Zeiger ist, muss er zuerst vom Typ her umgewandelt werden, bevor
er in einer Zuweisung verwendet werden kann. Die dritte Zeile sollte wie folgt
lauten
*(float*)p = 1.23;
struct quiz_antworten {
unsigned antwort1 : 1;
unsigned antwort2 : 1;
unsigned antwort3 : 1;
unsigned antwort4 : 1;
unsigned antwort5 : 1;
char student_name[15];
};
1
bis einschließlich 32767
.
getpid()
liefert die Prozess-ID des Prozesses zurück, der die
Funktion aufruft, während getppid()
die Prozess-ID des Elternprozesses
zurückliefert.
wait()
wird immer warten, bis ein Kindprozess beendet ist, während
die Funktion waitpid()
angewiesen werden kann, direkt zurückzukehren, wenn
keine Zombie-Kindprozesse existieren.
execl()
wird der aktuelle Prozess durch das
neue Programm ersetzt, so dass kein Code mehr in dem Programm, das ihn
aufgerufen hat, ausgeführt wird.
1523
SIGSTOP
und SIGKILL
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
int mein_system(char *befehl);
int main (void)
{
mein_system ("/bin/ls");
printf ("Fertig\n");
return 0;
}
int mein_system(char *befehl)
{
pid_t pid;
int status;
pid = fork();
if (pid == -1)
return -1;
if (pid == 0)
{
execl(befehl, befehl, NULL);
}
wait (&status);
return status;
}
main
-Modul ist das Modul mit der main()
-Funktion.
defined()
prüft, ob ein bestimmter Name definiert ist. Wenn ja,
wird wahr
zurückgeliefert, im anderen Fall falsch
.
#if
muss ein korrespondierendes #endif
folgen.
#include
kopiert den Inhalt der angegebenen Datei in die aktuelle Datei.
#include
in doppelten Anführungszeichen weist den Compiler an, die
include
-Datei in dem aktuellen Verzeichnis zu suchen. Ein #include
-Anweisung,
bei der der Dateiname in spitzen Klammern steht (<>
), weist den Compiler an, in
den Standardverzeichnissen zu suchen.
__DATE__
wird verwendet, um das Kompilierungsdatum des Programms in das
Programm aufzunehmen.
argv[0]
zeigt auf einen String, der den Namen des aktuellen Programms enthält
Aufgrund der vielen möglichen Lösungen gibt es zu den Übungen von Tag 20 keine Antworten.
gtk-config --cflags
in den Compiler-Aufruf mit
aufzunehmen.
gtk-config --libs
in den Compiler-Aufruf mit
aufzunehmen.
Aufgrund der vielen möglichen Lösungen gibt es zu den Übungen von Tag 21 keine Antworten.
1Wobei die ASCII-Werte nur für die ersten Zeichen verglichen werden - und zwar so lange, bis ein Unterschied zwischen den Strings festgestellt wird.