Programmieren in C - Dynamische Speicherzuordnung
Bild Referenz: http://lueersen.homedns.org/Pronix_final/ckurs/ckurs65.html
Intro
Hallo, ich bins @drifter2! Der heutige Artikel ist am englischen Artikel: "C Dynamic Memory Allocation" basiert. Also werden wir vieles alles über die Dynamische Speicherzuordnung oder Zuweisung lernen. Ist nicht viel mehr zu lasen also fangen wir mal an!
Dynamischer Speicher
Bei Programmen brauchen wir meistens nicht nur statische, sondern auch dynamische Variablen. Die dynamischen Variablen, Felder, Zeiger usw. werden im so genannten Dynamischen Speicher (auch Heap) eingespeichert. Der Heap ist ein Speicherbereich der in der Laufzeit eines Programms angefordert und freigegeben kann. Nach der Freigabe und insbesondere nach der Programmausführung sollte man diesen Speicher wieder "reinigen", etwas das mit der Hilfe von Speichereinigungs-Funktionen (die meistens automatisch abgerufen werden ) gemacht wird. Durch die Benutzung von dem Heap und dem so genannten Stack (der statische Speicher) hat der Programmier jetzt viele Arten an Speichern zu Verfügung. Der Unterschied zum Stack besteht darin, dass beim Stack angeforderte Speicherabschnitte in der umgekehrten Reihenfolge wieder freigegeben werden müssen, in der sie angefordert wurden. Dies schränkt die Wiederverwendung nicht länger benötigter Stack-Bereiche ein.
Der Dynamische Speicher verspricht:
- Hohe Geschwindigkeit
- Effiziente Speichernutzung
- Geringer Verwaltungsaufwand
Speicherzuweisung/Zuordnung in C
Um diese "Fähigkeit" von C zu benutzen müssen wir die stdlib.h Standardbibliothek von C in unser Programm importieren. Diese Bibliothek enthält Funktionen für die Dynamische Speicherzuweisung, wo meistens ein Zeiger zu dieser Speicher-Stelle zurückgegeben wird. Die wichtigsten Funktionen sind:
- malloc(size) -> das zur Speicherzuteilung dient
- realloc(memory, size) -> das eine bestehende Speicherzuweisung erneut zuweist
- calloc(elements, size) -> das eine "reine" Speicherzuteilung ausführt (alles auf 0 initialisiert)
- free(pointer) -> das den Speicher wieder freigibt, oder reinigt
Sagen wir mal wir wollen ein Dynamisches Ganzzahl (Integer) Feld deklarieren. Dazu deklarieren wir einen Pointer wie folgend:
int *A;
Sagen wir mal wir wollen N-Ganzzahlen und brauchen keine Initialisierung auf 0, das heisst das malloc() uns ausreicht. Da malloc() einen void- Zeiger zurückgibt ist der Code dazu:
A = (int*) malloc(N*sizeof(int));
Wie ihr sehen könnt müssen wir eine Datentyp-Umwandlung ausführen so das der void-typ zu einem Integer-typ wird. Der Parameter enthält die sizeof() Funktion die uns die Größe von Ganzzahlen gibt und das wir dann mit N multiplizieren so das wir einen Speicher zuteilen der für N-Ganzzahlen ausreicht.
Nach der Zuweisung sollten wir jetzt den Zeiger checken ob er NULL ist, ein Wert der Fehler anzeigt (wie z. B. kein Freier Speicher). Das geht wie folgt:
if(A == NULL){
// Fehler behandeln
}
Sagen wir jetzt wir brauchen M Ganzzahlen (die mehr oder weniger als N sind). Dazu benutzen wir jetzt die realloc() Funktion. Der Code ist wie folgend:
A = realloc(A, M*sizeof(int));
Wenn M kleiner ist, werden nur die M von den N Ganzzahlen "im Speicher bleiben" (die bleiben schon, aber sind halt eigentlich nicht mehr "richtig" abgespeichert). Wenn M größer ist dann bleiben die N ganz normal abgespeichert und behalten auch ihren Wert und es werden einfach mehr Speicherplätze freigegeben.
Nachdem wir fertig sind machen wir am Ende noch eine Speicherreinigung indem wir free() benutzen...
free(A);
Beispielprogramm
Gehen wir jetzt mal in ein komplettes Programm, so das ihr das ganze besser versteht...
Wir wollen unendlich viele Steuerinformationen (Tax informations) eingeben bis eine Tax-ID von "00000" eingegeben wird.
Diese Informationen sind:
- ID (Ganzzahl aus 5 Ziffern),
- Name (Zeichenkette),
- Nachname (Zeichenkette),
- Geburtstag als Zeichenkette (Alter muss mindestens 18 sein, das wir "extrahieren"),
- Kategorie (self_employed, wage_earner),
- Einkommen als Float
- Steuern als Float
Steuern werden wie folgend abgerechnet:
- self_employed 30% ihres Einkommens
- wage_earner Gestaffelt (Staggered charge):
- 0% bis 10.000
- 20% von 10.000 bis 30.000
- 30% von 30.000 und aufwärts
Nachdem der unendliche Loop stoppt werden die Informationen als eine Matrix ausgedruckt. Da die Nummer der Steuerzahler unbekannt ist müssen wir natürlich Dynamische Felder (Arrays) benutzen, genau wie das in diesem Artikel beschrieben wurde.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Y 2018
int main(){
int *ids; //dynamic array of ids
char **names; //dynamic array of names
char **surnames; //dynamice array of surnames
int *ages; //dynamic array of ages
char *category; //dynamic array of categories of the taxpayers
float *incomes; //dynamic array of incomes
float *taxes; //dynamic array of taxes
char id[6]; // als Zeichenkette lesen fuer eine Maximale Laenge aus 5 Zeichen
char name[30], surname[30]; // Temporaere name und surname Variablen
char date[11]; // Um den Geburtstag als DD/MM/YYYY zu lesen
char *p; // Zeiger um "date" zu gearbeiten
int day, month, year; // Gesplitterter Geburtstag
float income, tax; // um Einkommen einzufuegen und Steuern zu berechnen
char cat; //temporaere Kategorie
int i; //loop Variabel
int flag; // Flagge zum checken
int count = 0; // Zahler der Steuerbezahler
printf("TAX PROGRAMM:\n");
while(1){
// ID einfuegen (5 Ziffern)
while(1){
flag = 1; // wenn 0, muss man wieder einfuegen
printf("id: ");
scanf("%5s", id);
fflush(stdin);
// Laenge check
if( strlen(id) < 5) flag = 0;
else{
// Nummern-Check
for(i = 0; i < 5; i++){
if( (id[i]<'0') || (id[i]>'9') ){
flag = 0;
break;
}
}
}
if(flag == 1) break;
}
if(atoi(id) == 0){ // Stoppen wenn "00000"
break;
}
// fuer den ersten malloc()
if(count == 0){
ids = (int*)malloc(1*sizeof(int));
}
// fuer jeden anderen
else{
ids = (int*)realloc(ids, (count+1)*sizeof(int));
}
ids[count] = atoi(id);
// Namen und Nachnamen einfuegen
printf("name: ");
scanf("%29s", name);
fflush(stdin);
printf("surname: ");
scanf("%29s", surname);
fflush(stdin);
// fuer den ersten
if(count == 0){
names = (char**)malloc(1*sizeof(char*));
surnames = (char**)malloc(1*sizeof(char*));
}
// fuer jeden anderen
else{
names = (char**)realloc(names, (count+1)*sizeof(char*));
surnames = (char**)realloc(surnames, (count+1)*sizeof(char*));
}
names[count] = (char*)malloc((strlen(name) + 1) * sizeof(char)); //allocate memory for name
strcpy(names[count], name);
surnames[count] = (char*)malloc((strlen(surname) + 1) * sizeof(char)); //allocate memory for surname
strcpy(surnames[count], surname);
// Geburtstag einfuegen
while(1){
flag = 1; // bei 0 nochmal einfuegen
printf("DD/MM/YYYY: ");
scanf("%10s",date);
fflush(stdin);
day = atoi(date);
p=strchr(date,'/');
p=p+1;
month=atoi(p);
p=strchr(p,'/');
p=p+1;
year=atoi(p);
// Tages-check
if( (day<=0) || (day>31 ) ) flag = 0;
// Monats-check
if( (month<=0) || (month>12) ) flag = 0;
// Jahres-check (easy 18)
if (year > Y - 18) flag = 0;
// bei '1' aus dem loop rausgehen
if(flag == 1) break;
}
if(count == 0){
ages = (int*)malloc(1*sizeof(int));
}
else{
ages = (int*)realloc(ages, (count+1)*sizeof(int));
}
// Jahr ins Feld abspeichern
ages[count] = Y - year;
// Einkommen einfuegen
while (1){ // muss positiv sein
printf("yearly income: ");
scanf("%f" ,&income);
fflush(stdin);
if(income > 0) break;
}
if(count == 0){
incomes = (float*)malloc(1*sizeof(float));
}
else{
incomes = (float*)realloc(incomes, (count+1)*sizeof(float));
}
incomes[count] = income;
// Kategorie
while(1){
printf("Are you self employer(s) or wage earner(w): ");
scanf("%c", &cat);
fflush(stdin);
if(cat == 's' || cat == 'w') break;
}
if(count == 0){
category = (char*)malloc(1*sizeof(char));
}
else{
category = (char*)realloc(category, (count+1)*sizeof(char));
}
category[count] = cat;
// Steuern berechnen
if(cat == 's'){ //self employed
tax = income * 0.3;
}
else{
if(income <= 10000){
tax = 0;
}
else if(income > 10000 && income <= 30000){
tax = 0 + (income - 10000) * 0.2;
}
else{ //if > 30000
tax = 0 + 20000*0.2 + (income - 30000) * 0.3;
}
}
printf("You have to pay %.2f tax!\n", tax);
if(count == 0){
taxes = (float*)malloc(1*sizeof(float));
}
else{
taxes = (float*)realloc(taxes, (count+1)*sizeof(float));
}
taxes[count] = tax;
count++; //increment count
}
// Informationen ausdrucken
printf("TAXPAYERS:\n");
printf("ID\tNAME\tSURNAME\t\tAGE\tCATEGORY\tINCOME\t\tTAXES\n");
for(i = 0; i < count; i++){
printf("%d\t%s\t%s\t%d\t", ids[i], names[i], surnames[i], ages[i]);
if(category[i] == 's') printf("Self employed\t");
else printf("Wage earner\t");
printf("%.2f\t%.2f\n", incomes[i], taxes[i]);
}
// es ist schwer alles in einer Linie auszudrucken
// also ist es besser in 2-3 Teile zu splitten...
}
Bin gerade im Urlaub also gibt es keine Programmausführung mit der Konsole...
:)
Referenzen
- https://de.wikipedia.org/wiki/Dynamischer_Speicher
- http://cppstudio.com/de/post/9088/
- http://www.c-howto.de/tutorial/arrays-felder/speicherverwaltung/
Vorherige Artikel
Einführung -> Programmiersprachen, die Sprache C, Anfänger Programme
Felder -> Felder, Felder in C, Erweiterung des Anfänger Programms
Zeiger, Zeichenketten und Dateien -> Zeiger, Zeichenketten, Dateiverarbeitung, Beispielprogramm
Und das war's dann auch mit diesem Artikel und ich hoffe ich hab alles verständlich erklärt. Νächstes mal werden wir über Strukturen (structs) und das Switch-Case Statement reden. Ich will auch einen Artikel über Funktionen machen demnächst...
Ciao!
✅ @drifter2, I gave you an upvote on your post!
If you are interested in claiming free Byteballs ($10+), just for having a Steem account, please visit this post for instructions: https://steemit.com/steem/@berniesanders/do-you-want-some-free-byteballs
I like the C language but the brackets can make it hard to know if you have closed off every function properly.
C++ is also a good language but it is also a good way to write a high density of computer bugs.
Google Übersetzer
Ich mag die Sprache C, aber die Klammern können es schwierig machen zu wissen, ob Sie jede Funktion ordnungsgemäß beendet haben.
C ++ ist auch eine gute Sprache, aber es ist auch eine gute Möglichkeit, eine hohe Dichte von Computer-Bugs zu schreiben.
Congratulations @drifter2! You have completed the following achievement on Steemit and have been rewarded with new badge(s) :
Award for the total payout received
Click on the badge to view your Board of Honor.
If you no longer want to receive notifications, reply to this comment with the word
STOP