Vorlesung 9 Flashcards
(38 cards)
Arrays
- Arrays (Felder, Vektoren) dienen zum Speichern einer festen Anzahl von
Werten gleichen Typs. - Anwendungsbeispiele:
- Vektoren, Matrizen
- Liste von Namen
- Syntax (Definition eines Arrays):
Datentyp Bezeichner[Elementanzahl]; - Beispiel:
float vektor[3];
short int a, b[10], c; - Die Elementanzahl muss positiv sein.
- Ungeeignet, wenn die Anzahl der Daten unbekannt ist, dann muss
dynamische Speicherverwaltung verwendet werden. - Durch die Definition eines Arrays werden so viele Variablen erzeugt, wie das
Array Elemente hat. - int b[10] erzeugt:
- Variablenname b für Zugriff auf das gesamte Array
- Variablennamen für Zugriff auf die einzelnen Elemente:
b[0], b[1], …, b[9] - Die Indizierung beginnt immer bei 0.
Arrays im Speicher
Elemente werden geordnet, direkt hintereinander im Speicher abgelegt.
Speicherbedarf von Arrays
- Speicherbedarf: Elementanzahl · Größe des Datentyps
- Beispiele:
- int wert[250]; braucht z.B. 4 · 250 = 1000 Byte
- double wert[1000]; braucht z.B. 8 · 1000 = 8000 Byte
- Vorsicht:
- Der gesamte Speicher für die Arrays wird erst zur Laufzeit angefordert.
- Bei zu großen Arrays oder lokal definierte Arrays kann es
Probleme geben (siehe Stack, später).
Zeichenketten als char-Arrays
- Eine der wichtigsten Anwendungen von Arrays ist die Darstellung und
Verarbeitung von Zeichenfolgen (Strings / Text). - Zeichenfolgen treten meist auf bei
- Ein- und Ausgabe (Benutzerschnittstellen)
- Verarbeitung von Text-Dateien
- In C gibt es keinen Datentyp String, stattdessen werden
char-Arrays verwendet. - Die Standardbibliotheken von C enthalten eine Menge Funktionen für
Zeichenketten (später mehr dazu).
Darstellung von Zeichenfolgen
Eine String-Literal wird intern als char-Array dargestellt.
● Die Länge ist um 1 größer als die Anzahl der Zeichen in der
Stringkonstanten.
● Zusatzfeld für die Speicherung von des Null-Zeichens ‘\0’, welches das
Ende des Strings anzeigt
- Wenn man eine Zeichenfolge bearbeitet, muss man immer prüfen, ob das
aktuelle Zeichen das ‘\0’-Zeichen ist. - Vorsicht: Fehler, wenn das Null-Zeichen mitten in einem String vorkommt
(z.B. bei der Konkatenation zweier Strings).
Initialisierung von Arrays
- Automatische Initialisierung wie bei Variablen:
- globale Arrays werden mit 0 initialisiert
- lokale Arrays werden nicht automatisch initialisiert
- Manuelle Initialisierung erfolgt durch Anhängen einer Liste
von Werten
int vector1[5] = {6, -4, 6, 2, -1};
int vector2[5] = {6, -6, 2};
int vector3[] = {3, -5, 7, 2, -1};
char hello[6] = {‘h’, ‘e’, ‘l’, ‘l’, ‘o’, ‘\0’};
char str[] = “hello world\n”;
- Listenwerte dürfen Literale und Variablen sein.
int vector1[5] = {6, -4, 6, 2, -1}; - Es dürfen auch weniger Elemente in der Liste stehen als die angegebene
Elementenanzahl, die übrigen Elemente bleiben uninitialisiert, bzw. werden
bei globalen Variablen mit 0 initialisiert.
int vector2[5] = {6, -6, 2}; - Implizite Längenbestimmung:
- Die Größe des Feldes wird der Anzahl der Initialisierungswerte gleichgesetzt.
- Häufigste Verwendung ist das Initialisieren von Stringkonstanten
wie im Beispiel str.
int vector3[] = {3, -5, 7, 2, -1};
Zugriff auf Array-Elemente
- Syntax: name [arrayindex];
- arrayindex kann ein beliebiger nichtnegativer Ausdruck sein, der zur Laufzeit
ausgewertet wird, z.B. Laufvariablen einer Schleife - Die Indizierung beginnt immer bei 0.
- Beispiel:
int a, v[] = {1,2,3};
a = v[1]; «_space;a wird zu 2
Prüfung von Bereichsgrenzen
- Keine Prüfung, ob arrayindex in den zugelassenen Grenzen liegt! Zugriffe auf
beliebige Speicherinhalte möglich (Speicherorganisation) - Zugriff auf Werte außerhalb der Grenzen:
- lesend: Programm arbeitet mit falschen Werten. Die Fehlerquelle schwer
lokalisierbar, evtl. Programmabsturz durch Speicherschutz des Betriebssystems. - schreibend: Wenn die Abweichung groß ist, wird ggfs. Programmcode
überschrieben. Bei Betriebssystemen ohne Speicherschutz führt dies zum
Crash, bei UNIX-Rechnern wird der Absturz verhindert (Segmentation fault,
eigenes Programm wird beendet, andere laufen weiter), ebenso auf
Windows-Systemen
Arrays backstage
- Die Variable für den gesamten Array ist intern nichts anderes als ein Zeiger.
- Der Zugriff auf ein Element des Arrays wird über die
Adressarithmetik gesteuert. - folgende Ausdrücke sind gleichbedeutend:
s = vektor[3];
s = *(vektor+3);
Arrays als Funktionsparameter
● Bei der Parameterübergabe eines Arrays wird lediglich die Startadresse des
Feldes übergeben (Zeigerübergabe).
● Änderungen der Elemente des Arrays sind daher auch in der aufrufenden
Umgebung sichtbar.
● Beispiel: Bei scanf wird nicht die Adresse des char-Arrays übergeben,
sondern die Array-Variable selbst:
char str[100];
scanf(“%s”, str);
int i;
scanf(“%d”, &i);
● Häufig soll eine Funktion mit Feldern unterschiedlicher Größe
korrekt arbeiten.
● Daher: Bei Funktionsdefinition braucht die Größe nicht angegeben werden
(für mehrdimensionale Felder stimmt dies nicht, folgt später):
● Vorsicht: Gefahr ungültiger Speicherzugriffe!
* Größe des Feldes unter Umständen in der Funktion nicht bekannt, muss dann
als separater Parameter übergeben werden
Funktion zum Vergleich von Arrays
include <string.h></string.h>
- Vergleich mittels der Funktion memcmp aus string.h
(schneller als manuell) - Parameter: die zu vergleichenden Arrays, sowie die Anzahl von Bytes, die
verglichen werden sollen - Ergebnis: 0, wenn Arrays gleich sind
…
int v1[3] = {1,2,3}, v2[3] = {4,5,6};
if(0 == memcmp(v1, v2, 3 * sizeof(int)))
printf(“v1 gleich v2\n”);
else
printf(“v1 nicht gleich v2\n”);
Funktion zum Kopieren von Arrays
- Zuweisung mittels der Funktion memcpy aus string.h
(schneller als manuell) - Parameter: Ziel-Array, Quell-Array, sowie die Anzahl von Bytes,
die zugewiesen werden sollen
beispiel:
#include <string.h>
...
int v1[3] = {1,2,3}, v2[3];
memcpy(v2, v1, 3 * sizeof(int));</string.h>
Mehrdimensionale Arrays
- Mehrdimensionale Arrays dienen zum Aufbau von Tabellen, Matrizen und
ähnlichen Strukturen. - Syntax der Definition:
- Datentyp Bezeichner[Anzahl 1][Anzahl 2]…;
- Beispiel (Matrix mit 2 Zeilen und 3 Spalten):
short int matrix[2][3]; - Syntax des Zugriffs:
Name[Array-Index 1][Array-Index 2]…; - Beispiel (Zugriff):
x = matrix[1][2];
Initialisierung von mehrdimensionalen Arrays
- Initialisierung analog zu eindimensionalen Arrays.
- Sowohl Zeilen als auch Spalten dürfen unvollständig sein.
- Arraygröße muss nicht angegeben werden.
int matrix[3][5] = { { 6,-4, 6, 2,-1},
{ 2, 3,-1, 9,-3},
{-1, 4,-8, 0, 3} };
Mehrdimensionale Arrays als Funktionsparameter
● Bei Funktionsdefinition braucht die erste Dimension nicht angegeben werden,
die anderen müssen angegeben werden.
void drucke_namen(char namen[][256], int count)
● Mit Zeigern kann aber auch dies umgangen werden.
Deklaration von Arrays
- C90 Standard
- Breite Unterstützung, nahezu alle C Compiler
- Größe eines Arrays muss zum Zeitpunkt der Übersetzung feststehen.
- Folgendes Beispiel geht nach diesem Standard nicht, da die Größe erst zur
Laufzeit bestimmt wird:
int size;
scanf(“%d”, &size);
double a[size]; - C99 Standard
- Lokale Arrays dürfen mit Variable deklariert werden, d.h. obiges Beispiel
wäre gültig.
sizeof Operator bei Arrays
● sizeof Operator liefert auch bei Arrays den belegten Platz in Byte, dividiert
durch die Größe eines Elements erhält man so die Elementanzahl
double b[1000];
printf(“b hat %d Elemente\n”, sizeof(b) / sizeof(double));
memcpy und memmove
● Funktionsdefinitionen in string.h
● Kopierfunktionen (1):
* void *memcpy(void *dest, const void *src, size_t n);
* void *memmove(void *dest, const void *src, size_t n);
* kopieren n Bytes, Speicherbereiche dürfen sich bei memcpy nicht überlappen
● Auch für andere Arrays als Strings anwendbar
● Achtung: das Stringende-Zeichen \0 wird nicht beachtet!
● Beispiel:
char text1[] = “Hamburg ist eine tolle Stadt!”;
char text2[] = “Bottrop”;
memcpy(text1, text2, 7);
printf(“%s\n”, text1);
#include <string.h></string.h>
strcpy und strncpy Funktionen für Zeichenketten
● Kopierfunktionen (2):
* char *strcpy(char *dest, const char *src);
* kopiert Zeichenkette inklusive abschließendem ‘\0’
* char *strncpy(char *dest, const char *src, size_t n);
* kopiert maximal n Zeichen, ggf. wird mit Nullen aufgefüllt
* Vorsicht: hat src keine Null in den ersten n Zeichen, ist dest nicht
Nullterminiert!
char text1[100] = “C-Programmieren macht Spaß!”;
char text2[100] = “Bottrop hat eine tolle Hochschule!”;
strcpy(text2, text1);
printf(“%s\n”, text2);
strcat und strncat Funktionen für Zeichenketten
● Aneinanderhängen von Zeichenketten:
* char *strcat(char *dest, const char *src);
* hängt die Zeichenkette src hinten an dest an
* char *strncat(char *dest, const char *src, size_t n);
* hängt maximal n Zeichen der Zeichenkette src hinten an dest an, fügt
\0 hinzu
* Achtung: Die Zielzeichenkette muss genügend Platz für beide Zeichenketten
und das abschließende \0 haben!
char text1[100] = “Bottrop ist eine tolle Stadt”;
char text2[] = “ und hat eine tolle Hochschule!”;
strcat(text1, text2);
printf(“%s\n”, text1);
strcmp, strncmp, memcp Funktionen für Zeichenketten
Vergleichsfunktionen:
* int strcmp(const char *s1, const char *s2);
* Vergleicht zwei mit \0 terminierte Zeichenketten
* int strncmp(const char *s1, const char *s2, size_t n);
* Vergleicht zwei mit \0 terminierte Zeichenketten, maximal n Zeichen
* int memcmp(const void *s1, const void *s2, size_t n);
* Vergleicht die ersten n Zeichen von zwei beliebigen Arrays
* Rückgabewert für alle drei Funktionen:
* < 0, wenn s1 kleiner als s2 (d.h. alphabetisch s1 vor s2 kommt, wenn nur
Buchstaben A-Z verwendet werden)
* > 0, wenn s1 größer als s2 (d.h. alphabetisch s1 nach s2 kommt, wenn nur
Buchstaben A-Z verwendet werden)
* 0, wenn s1 gleicher Inhalt wie s2
char str1[101];
char str2[101];
printf(“Text 1: “);
scanf(“%100s”, str1);
printf(“Text 2: “);
scanf(“%100s”, str2);
int c = strcmp(str1, str2);
if(c > 0) {
printf(“%s kommt nach %s\n”, str1, str2);
} else if(c < 0) {
printf(“%s kommt vor %s\n”, str1, str2);
} else {
printf(“%s gleich %s\n”, str1, str2);
}
*strchr und *strrchr und *strpbrk und *strstr Funktionen für Zeichenketten
● Suchfunktionen:
* char *strchr(const char *s, int c);
char *strrchr(const char *s, int c);
Rückgabewert: Zeiger auf erstes/letztes Auftreten von c in s
* char *strpbrk(const char *s, const char *accept);
Rückgabewert: Zeiger auf erstes Auftreten eines der Zeichen aus accept in s
* char *strstr(const char *haystack,
const char *needle);
Rückgabewert: Zeiger auf erstes Auftreten von needle in haystack
char str1[] = “Heute ist ein toller Tag!”;
char *str2;
str2 = strstr(str1, “ein”);
printf(str2);
strlen und memset Funktionen für Zeichenketten
● Länge einer Zeichenkette:
size_t strlen(const char *s);
Rückgabewert: Länge der Zeichenkette s
● Auffüllen eines Feldes:
void *memset(void *s, int c, size_t n);
Füllt die ersten n Bytes von s mit c.
● Weitere Funktionen in string.h (siehe Literatur):
– strspn strcspn
strerror strtok
memchr
puts gets fgets Funktionen für Zeichenketten
● Funktionsdefinitionen in stdio.h
● Ein-/Ausgabe von Zeichenketten:
* int puts(char *s);
* schreibt die Zeichenkette s und einen nachfolgenden Zeilenumbruch auf den Bildschirm
* char *gets(char *s);
* liest eine Zeichenkette und speichert sie in s. Das Return der Eingabe wird in \0
umgewandelt.
* Vorsicht: Wenn eingegebener Text länger ist als der Speicherplatz von s, wird über das
Ende von s hinaus in den Speicher geschrieben => Sicherheitsrisiko. Daher besser
folgende Funktion verwenden:
* char *fgets(char *s, int size, FILE *stream);
* Für stream verwende stdin, Details im Kapitel Dateioperationen
* Liest bis zum Zeilenumbruch, aber maximal size-1 Zeichen
* \n bleibt erhalten, fügt \0 am Ende an