Vorlesung 10 Flashcards

1
Q

nenne alle 4 speicherbereiche bei einem C programm

A

programmspeicher
-übersetzter programmcode (maschinensprache)

stack
-lokale variablen, funktionsparameter, rücksrungadressen

globaler speicher
-glabale variablen, statische variablen

heap
-dynamische speicherverwaltung

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

erläutere den speicherort stack

A

stapelspeicher zum speichern von lokalen variablen, funktoinsparametern und rücksprungadressen.

  • Speicher mit fixer Größe
  • Wird beim Start des Prozesses initialisiert
  • Effiziente “Stapel”-Datenstruktur
    4
    int manyNumbers[100000];
    manyNumbers[0] = 1;
    manyNumbers[1] = 2;
    int count = 2; Schlechte Idee!
  • Aber: Der Stack ist begrenzt!
  • Risiko: Stack overflow
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

was passiert beim stack overflow?

A
  • Ein Stack overflow tritt auf, wenn der Stack-Speicher vollständig verbraucht
    wurde und weiterer Speicher reserviert werden soll:
  • Lokale Arrays mit zu vielen Einträgen
  • Rekursive Funktionen, die nicht oder zu spät terminieren
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

erläutere den speicherort halde (Heap)

A
  • Großer, unstrukturierter Arbeitsspeicher
  • Erlaubt die dynamische Reservierung von “beliebig” viel Speicher
    zur Laufzeit.
  • Zugriff nur über Zeiger möglich
  • Nicht automatisch verwaltet
  • Verwaltung liegt in der Verantwortung des/der Programmier:in!
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

was macht der operator sizeof?

A
  • Gibt die Größe eines Ausdrucks oder Datentyps zurück.
  • Rückgabetyp: size_t (vorzeichenlose Ganzzahl)
  • Regeln:
  • sizeof(char) = 1 (auch für signed/unsigned)
  • Ausdrücke werden nicht ausgewertet (z.B. sizeof p++)
    Daher: Keine Seiteneffekte möglich!
  • sizeof berücksichtigt Speicherausrichtung.
  • Rückgabe hängt stark von Plattform und Compiler ab!

bsp.:
size_t s = sizeof <Ausdruck>
size_t s = sizeof(<Typbezeichner>)</Typbezeichner></Ausdruck>

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

was macht die funktion malloc?

A
  • Syntax:
    #include <stdlib.h>
    void *malloc(size_t size)</stdlib.h>
  • malloc reserviert Speicher der Größe size.
  • Parameter size: Größe des zu reservierenden Speichers in Byte.
  • Speicher wird nicht initialisiert.
  • Rückgabewert:
  • Zeiger auf Anfang des Speicherblocks
  • NULL, wenn Fehler bei der Speicherreservierung auftritt
  • Rückgabewert muss geprüft werden!
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

was macht die funktion calloc?

A
  • Syntax:
    #include <stdlib.h>
    void *calloc(size_t count, size_t size)</stdlib.h>
  • calloc reserviert Speicher der Größe size * count.
  • Parameter
  • count: Anzahl der Feldelemente
  • size: Größe eines Feldelements
  • Speicher wird mit 0 initialisiert.
  • Rückgabewert:
  • Zeiger auf Anfang des Speicherblocks
  • NULL, wenn Fehler bei der Speicherreservierung auftritt
  • Rückgabewert muss geprüft werden!
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

wie geht das freigeben von speicher?

A
  • Jeder dynamisch reservierte Speicher muss manuell freigegeben werden!
  • Sonst: Memory Leak
  • Kein automatisches Freigeben, lediglich beim Programmende
  • Funktion:
    #include <stdlib.h>
    void free(void *ptr);</stdlib.h>
  • Gibt einen (z.B. mit malloc) reservierten Speicherbereich bei ptr
    wieder frei.
  • Undefiniertes Verhalten, wenn:
  • ptr wurde nicht zuvor reserviert (durch malloc, calloc, realloc).
  • ptr wurde bereits durch free freigegeben.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

wie vergrößert man ein feld?

A
  • Vorgehensweise bei der Feldvergrößerung
  • Gegeben: Feld a mit m Elementen
  • Ziel: Feld a mit n Elementen, n > m
  • Erzeuge mit calloc Feld b mit n Elementen
  • Kopiere die Elemente des Feldes a an die ersten m Positionen des Feldes b
    (Schrittweise mit einer for-Schleife oder per memcpy)
  • Speicher für Feld a freigeben (Befehl free)
  • Setze Zeiger a auf Beginn des Feldes b
    (Anweisung: a = b;)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

wie geht das Einfügen in Feldern?

A
  • Gegeben: Feld a mit n Elementen
  • Ziel: Einfügen von Element e an Index i
  • Vorgehen:
    1. Erzeuge mit calloc Feld b mit n+1 Elementen
    2. Kopiere die Elemente a[0, …, i-1] nach b[0, …, i-1]
    3. Kopiere die Elemente a[i, …, n-1] nach b[i+1, …, n]
    4. Setze b[i] = e
    5. Speicher für Feld a freigeben (Befehl free)
    6. Setze Zeiger a auf Beginn des Feldes b
    (Anweisung: a = b;)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

was bedeutet realloc? was ist die funktion?

A
  • „Re-allokierung“
  • realloc erlaubt, die Größe von reserviertem Speicher zu ändern:
    void* realloc (void* ptr, size_t size);
  • Verändert die Größe des Speicherbereichs, auf den ptr zeigt,
    auf die neue Größe size.
  • Rückgabe:
  • Anfang des vergrößerten/verkleinerten Blocks
    (kann identisch sein zu ptr, muss es aber nicht)
  • NULL im Fehlerfall
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

was ist der hintergrund von speicherarten?

A
  • Programmspeicher
  • Globaler Speicher
  • Speicher wird beim Programmstart angelegt und erst am Programmende wieder freigegeben
  • Speicherung von globalen Variablen und statischen lokalen Variablen
  • Stack (Automatischer Speicher)
  • Wird „bei Bedarf“ automatisch erzeugt und freigegeben
  • Speicherung von Funktionsargumenten und nichtstatischen lokalen Variablen
  • Interne Realisierung als Stack (Stapel)
  • Gesamtspeicherbereich für Stack wird bei Programmstart reserviert
  • Wenn Stack bei Funktionsaufruf voll (stack overflow): Programmabbruch
  • Heap (dynamischer Speicher, freier Speicher)
  • Volle Kontrolle durch Programmierer
  • Explizite Anforderung des Speicherbereichs mit malloc/calloc/realloc
  • Explizite Freigabe des Speicherbereichs mit free
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

lokale vs. dynamische arrays

A
  • Deklaration
  • Nach der Deklaration int a[100] zeigt a auf den Anfang eines
    Speicherbereichs für Integer-Zahlen.
  • Nach der Deklaration int *z = calloc(100, sizeof(int)) zeigt z ebenfalls
    auf den Anfang eines Speicherbereichs für Integer-Zahlen.
  • Speicher
  • Für a wird der Speicher auf dem Stack oder im globalen Speicher automatisch
    reserviert.
  • Für z muss der Speicher manuell auf dem Heap reserviert (und später
    freigegeben) werden, z.B. mit calloc bzw. free
  • Zugriff
  • für beide Arten von Arrays gilt:
  • mit *a bzw. *z wird auf das erste Element zugegriffen
  • mit a[i] bzw. z[i] wird auf das Element mit Index i zugegriffen
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

zeigerarithmetik

A
  • Ein Zeiger speichert eine Adresse im Arbeitsspeicher.
  • Zeiger sind typisiert
    (außer void*, dort auch keine Adressarithmetik möglich)
  • Addition / Subtraktion von Zeiger mit int-Zahl i
  • Adresse wird um i Elemente (nicht Byte!) verändert
  • Die Adresse wird also um i * sizeof(datentyp) verändert
  • Was ist die Ausgabe von folgendem Programm?
    int a[5] = {11, 23, 34, 48, 59};
    int z;
    z = a;
    printf(“
    z = %d *a = %d\n”, *z, a);
    printf(“
    (z+2) = %d *(a+2) = %d\n”, *(z+2), (a+2));
    printf(“
    z+2 = %d *a+2 = %d\n”, *z+2, *a+2);
  • Fazit der vorherigen Folie: z[n] entspricht *(z + n)
  • Inkrement und Dekrement: z++, z–, ++z, –z
  • analog zu Operatoren auf Integer, es wird aber elementweise
    (sizeof(datentyp)) addiert/subtrahiert.
  • Was gibt folgendes Programm aus?
    int array[5] = {1, 3, 4, 8, 9};
    int *ptr = array, result = 0;
    for(int i = 0; i < 5; i++)
    {
    result += *ptr;
    ptr++;
    }
  • Subtraktion von Zeigern z1 – z2
  • nur sinnvoll, wenn beide zu gleichem Speicherbereich gehören
  • Ergebnis: Anzahl von Elementen zwischen den Zeigern (Typ int)
  • Was macht das folgende Programm?

int wasMacheIch(char *z)
{
char z2 = z;
while(
z2) {
z2++;
}
return z2 - z;
}
int main()
{
char str[101];
printf(“Eingabe: “);
scanf(“%100s”, str);
printf(“Ergebnis: %d\n”, wasMacheIch(str));
return 0;
}

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Mehrdimensionale felder und zeiger

A

● Felder können mehrdimensional sein, z.B. int a[5][5]
● Auch mehrdimensionale Arrays können auf Zeiger (int *z) gelegt werden,
Speicherberechnung muss dann manuell angepasst werden.

Anwendungsbeispiel: beliebig große Matrizen ausgeben

void printMatrix(int *matrix, int m, int n)
{
int i, j;
for(i = 0; i < m; i++) {
for(j = 0; j < n; j++) {
printf(“%4d “, (matrix + in + j));
}
printf(“\n”);
}
}
int main()
{
int matrix[3][4] = { { 1, 2, 3, 4},
{ 5, 6, 7, 8},
{ 9, 10, 11, 12} };
printMatrix(matrix, 3, 4);

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

zeiger auf zeiger: anwendungsbeispiele

A
  • Call by reference für Zeiger:
  • Ziel: eine Funktion soll den
    veränderten Wert eines Zeigers
    zurückgeben
  • Damit: Zeiger auf Zeiger als
    Funktionsparameter notwendig

void liesKunde(kunde k)
{
*k = malloc(sizeof(kunde));
if(
k == NULL) {
return;
}
printf(“Vorname: “);
scanf(“%s”, (
k)->vorname);

}
int main()
{
kunde *k;
liesKunde(&k);
free(k);
}

17
Q

Dateioperationen: Konzept

A

● Ziel: Speichern von Daten in Dateien und Einlesen von Daten aus Dateien
auf Datenträgern.
● Gebräuchlichste Funktionen analog zur Bildschirm-Ein-/Ausgabe
● Zusätzliche Funktionen für Binärdateien sowie systemnahe
(low-level) Funktionen
● Dateikonzept: Jede Datei ist eine Folge von Zeichen
● Phasen des Dateizugriffs:
* Öffnen bzw. Erzeugen der Datei
* Lese- bzw. Schreibzugriffe
* Schließen der Datei

18
Q

Öffnen von Dateien

A

● FILE *fopen(const char *fname,
const char mode)
* fname: Dateiname (inklusive Pfad)
* mode: Zeichenkette für Bearbeitungsmodus
* “r”: Öffnen zum Lesen
* “w”: Öffnen zum Schreiben (löscht bestehende Datei mit gleichem Namen)
* “a”: Öffnen zum Schreiben (anhängen, wenn Datei bereits vorhanden)
* “r+”: Öffnen bestehender Datei zum Verändern (lesen und schreiben)
* “w+”: Erzeugen neuer Datei zum Verändern (lesen und schreiben,
löscht vorhandene gleichnamige Datei)
* “a+”: Öffnen einer Datei zum Ändern am Ende
Binärdateien
* Anhängen von b an mode-String
* Daten werden unverändert geschrieben
* Textdateien
* Anhängen von t an mode-String
* es werden systemabhängige Konvertierungen vorgenommen, um
(Menschen-)Lesbarkeit und Portabilität zu erhöhen
* Rückgabewert: Zeiger FILE

* Identifikator für die geöffnete Datei, NULL bei Fehler
* Wird für Schreib-/Lesebefehle benötigt

19
Q

Dateizugriffe und Schließen einer Datei

A

● Befehle analog zu Bildschirm-Ein-/Ausgabe
* int putc(int c, FILE *f)
* int getc(FILE *f):
* int fprintf(FILE *f, const char *format, …)
* int fscanf(FILE *f, const char *format, …)
● Eingabefunktionen liefern bei Dateiende EOF.
● Schließen einer Datei
* int fclose(FILE *f)
* Noch nicht geschriebene Daten aus dem Puffer werden gespeichert
(zur Steigerung der Performance werden nicht alle Daten sofort geschrieben)
* Danach kein Zugriff mehr möglich

20
Q

Standarddateien

A

Kein prinzipieller Unterschied zwischen Bildschirm- und Datei-Ein-/Ausgabe
* stdin: Standardeingabekanal
* stdout: Standardausgabekanal
* stderr: Standardfehlerkanal
● Fehler sollten daher möglichst nicht per printf sondern mit
fprintf(stderr, Fehlermeldung) ausgegeben werden.

21
Q

beispiel: Speichern

A

include<stdio.h></stdio.h>

#include<stdlib.h>
int main()
{
FILE *f = fopen("test.txt", "wt");
if(f == NULL)
{
fprintf(stderr, "Fehler beim Oeffnen der Datei!\n");
exit(EXIT_FAILURE);
}
fprintf(f, "Speichere vier: %d\n", 4);
fclose(f);</stdlib.h>

return 0;
}

22
Q

Beispiel: Lesen

A

include<stdio.h></stdio.h>

#include<stdlib.h>
int main()
{
FILE *f = fopen("test.txt", "rt");
if(f == NULL) {
fprintf(stderr, "Fehler beim Oeffnen der Datei!\n");
exit(EXIT_FAILURE);
}
int c;
while(EOF != (c = getc(f))) {
printf("Gelesenes Zeichen: %c\n", c);
}
fclose(f);
return 0;
}</stdlib.h>

23
Q

puts und fputs

A

● int puts(char *s);
* schreibt die Zeichenkette s und einen nachfolgenden Zeilenumbruch auf den
Bildschirm
* Rückgabewert: EOF bei Fehler, nichtnegativ sonst
● int fputs(const char *s, FILE *stream);
* schreibt die Zeichenkette s ohne das Abschlusszeichen ‘\0’ in eine Datei
* Rückgabewert: EOF bei Fehler, nichtnegativ sonst

24
Q

fgets

A

● char *fgets(char *s, int size, FILE *stream);
* fgets liest bis zum nächsten Zeilenwechsel oder EOF, maximal aber size-1
Zeichen, aus einer Datei, speichert sie in einer Zeichenkette und hängt \0 an
(\n wird nicht durch \0 ersetzt).

char s[10];
int i;
printf(“Text eingeben: “);
fgets(s, 10, stdin);

/* Zeilenumbruch entfernen /
char
p = strchr(s, ‘\n’);
if(p) {
*p = 0;
}
printf(“Eingegeben wurde "%s"\n”, s);

25
Q

Funktionen zur Steuerung des Dateizugriffs

A

● int fflush(FILE *f): Leeren des Dateipuffers
● void rewind(FILE *f): Setzen der aktuellen Position an den Dateianfang
● long ftell(FILE *f): liefert aktuelle Position des Satzzeigers
● int fseek(FILE *f, long offset, int origin)
* Setzen der Position an beliebige Stelle
* evtl. Probleme bei Textdateien
* offset: Entfernung bzgl. origin, kann auch negativ sein
* origin:
* SEEK_SET: Anfang der Datei
* SEEK_CUR: aktuelle Position
* SEEK_END: Ende der Datei

26
Q

Steuerung des Dateizugriffs: Beispiel

A

● Auslesen der Dateilänge, danach am Anfang weiterarbeiten

FILE f;
long int dateigroesse;
f = fopen(“test.txt”, “rt”);
if(f == NULL)
{
fprintf(stderr, “Fehler beim Oeffnen der Datei!\n”);
exit(EXIT_FAILURE);
}
/
Springe an Dateiende /
fseek(f, 0, SEEK_END);
/
Lese aktuelle Position /
dateigroesse = ftell(f);
/
Springe an Anfang */
rewind(f);

27
Q

Binärdateien

A

● Bisher: Schreiben/Lesen von Texten in/aus Dateien
● Vorteil: Auch mit einem Texteditor editierbar
● Nachteil: große Dateien, Daten können unerwünscht geändert werden
● Jetzt: Binärdateien
● C erlaubt es, Daten byteweise in eine Datei zu schreiben

28
Q

Funktionen für Binärdateien

A
  • Öffnen der Datei im Binärmodus („b“). Schließen wie bisher.
  • Schreiben und Lesen:
    size_t fwrite(void *buf, size_t size, size_t cnt, FILE *f)
    size_t fread(void *buf, size_t size, size_t cnt, FILE *f)
    ● Parameter und Rückgabewert:
  • buf: Zeiger auf den Datenpuffer (void * ist ein untypisierter Zeiger, d.h. es darf
    ein beliebiger Zeiger übergeben werden)
  • size: Größe eines Elements
  • cnt: Anzahl der Elemente
  • Rückgabewert: Anzahl der verarbeiteten Datensätze
29
Q

Binärdateien: Beispiel

A

define DB_SIZE 50


typedef struct s_Customer
{ …
} Customer;

FILE file;
Customer myCustomers[DB_SIZE];
/
Daten lesen */
file = fopen(“kundendatei.dat”, “rb”);
if(file == NULL) {
fprintf(stderr, “Fehler beim Oeffnen der Datei!\n”);
exit(EXIT_FAILURE);
}
if(DBGROESSE != fread(myCustomers, sizeof(Customer), DB_SIZE, file)) {
fprintf(stderr, “Warnung: zu wenig Daten in Datei!\n”);
}
fclose(file);

weiteres beispiel:

/* Daten bearbeiten /

/
Daten speichern */
file = fopen(“kundendatei.dat”, “wb”);
if(file == NULL)
{
fprintf(stderr, “Fehler beim Oeffnen der Datei!\n”);
exit(EXIT_FAILURE);
}

if(DB_SIZE != fwrite(myCustomers, sizeof(Customer), DB_SIZE, file)) {
fprintf(stderr, “Fehler beim Speichern!\n“);
}
fclose(file);

30
Q

Weitere Funktionen der stdio.h

A
  • freopen: Umleiten eines Datei-Streams (meist stdin, stdout oder stderr) in
    eine Datei
  • remove/rename: Löschen bzw. Umbenennen einer Datei
  • tmpfile/tmpname: Erzeugen von temporären Dateien
  • setvbuf/setbuf: Beeinflussung des Datenpuffers
  • ungetc: Zurückstellen eines Zeichens in den Puffer
  • fgetpos/fsetpos: Speichern/Setzen der Position im Datei-Stream
  • feof: Abfragen, ob Dateiende erreicht
  • clearerror/ferror/perror: Funktionen zur Fehlerbehandlung