Programmieren in C - Arrays (Felder)

in #programmieren6 years ago (edited)

Bild Referenz: https://commons.wikimedia.org/wiki/File:The_C_Programming_Language_logo.svg

Intro

  Hallo, ich bins @drifter2! Der heutige Artikel ist an meinen englischen Artikel: "C Beginner Arrays" basiert von wo ich die Programme nehmen werde. Aber weil ich dort direkt in das eingemachte gegangen bin, werde ich bei dieser übersetzten Version erstmal ein bisschen erklären was diese Arrays überhabt sind und wie und wieso man die benutzt! Ich empfehle euch den vorherigen Artikel zu lesen bevor ihr diesen ließt.

Array (Feld)

     Ein Feld (in englisch field oder array) ist eine Datenstruktur-Variante womit gleichartig strukturierte Daten verarbeitet werden. Es ist also eine Anordnung oder Aufstellung von gleichartigen Daten. Der Zugriff an bestimmte Inhalte eines Feldes erfolgt mit der Hilfe von Indizes (Indexes auf Englisch) die dessen Position bezeichnen. Eine solche Datenstruktur kann mit vielen unterschiedlichen Ausdrücken bezeichnet werden: Array, Tabelle, Vektor, Reihe, Reihung, Datenfeld, Aufstellung, Bereich, Gate Array, Matrix/Matrize usw. das an dem Einsatz, der Programmiersprache und vielem mehr abhängt. In mathematischen Problemen reden wir z. B. eher über Tabellen, Vektoren oder Matrizen.

Indizes

    Wir haben vorhin die Indizes (Indexes) erwähnt aber noch nicht direkt erklärt. Zur Adressierung eines einzelnes Elements in einem Feld wird ein "Index" verwendet. Das heißt natürlich das jeder Index nur ein einziges gewisses Element anzeigt und. Bei mehrdimensionalen Feldern haben wir einen Index für jede Dimension. Bei den meisten Programmiersprachen wird dieser Index als Ganzzahl angegeben. Die Elemente eines Feldes werden im Speicher eins nach dem anderen eingespeichert. Deswegen zeigt uns der Index auch den relativen Abstand zum Feld-Beginn. Ihr könnt auch bestimmt verstehen das der Index auch als Suchschlüssel dient weil man durch eine Feld sehr leicht mit einen Loop durchgeht.

Maximale Größe

    Bei Statischen (Fixen) Feldern muss man eine gewisse Maximale Feld-Größe definieren. Bei Dynamische wird diese Dynamisch bei der Ausführung kontrolliert. Die Elemente werden von 0 oder 1 bis zu der beliebigen Größe (N-1 oder N) adressiert. Wir müssen-können natürlich verschiedene Größen für jede Dimension anlegen.

Deklarieren

Die abstrakte Formulierung eines Feldes kann wie folgend aussehen:

  • Feldname (Größe) -> wird in der Sprache PL/I benutzt
  • Feldname [Größe] -> in den meisten C-like Programmiersprachen
  • Feldname [][]... -> um mehrere Dimensionen zu formulieren (C, Java, C# usw.)
  • "Feldname array (Größe)", "Feldname occurs Größe" UND "Dim Feldname (Größe, ...)" und mehr...

Statischer und Dynamischer Datentyp

    Die Feldinhalte sind meistens auf einen einzelnen Datentyp eingeschränkt. In objektorientierten Programmiersprachen (wir Java, C# usw.) wo es aber Objekte gibt kann man aber auch beliebigen Inhalt haben durch die so genannte Polymorphie. In dynamischen typisierenden Programmiersprachen können aber Objekte und Datenstrukturen in fast jeder beliebigen Zusammensetzung und Reihenfolge gespeichert werden. In solchen Sprachen haben wir aber meistens nur assoziative Arrays.

Arrays (Felder) in der Sprache C

Definition

    In C kann man mehrere Werte des desselben Datentyps zusammen in einer Array speichern, im Gegensatz zu Variablen und Konstanten die nur einen Wert speichern. Ein solches Array/Feld kann mit verschiedenen Arten definiert werden. Die einfachste Variante besteht aus den folgenden drei Teilen:

  1. Datentyp der enthaltenen Elemente/Werte
  2. Gewünschter Name der Array
  3. Anzahl der Element / Größe des Arrays

Das allgemeine Schema ist also:

DATENTYP FELDNAME [GRÖßE]

Ein Feld/Array das z. B. zum speichern drei Ganzzahlen (Integer) dienen soll ist:

int numbers [3];

    In der vorherigen Variante haben wir die Feldwerte nicht initialisiert. Der Compiler wird die Werte nur auf 0 initialisieren wenn es sich um globale oder statische Felder handelt. In jedem anderen Fall wird also nicht 0 sondern "Müll" in Speicher sein. Sagen wir mal das wir die Werte 4, 2 und 0 abspeichern wollen. Die Definition eines solchen Feldes/Arrays ist:

int numbers [] = {4, 2, 0};

    Wie ihr sehen könnt habe ich keine Größe angegeben. Das heißt das die Größe 3 sein wird und so die Anzahl an den angegeben Werten. Um z. B. ein Feld mit 5 Feldern zu definieren wo nur drei davon direkt einen Wert haben schreiben wir:

int numbers [5] = {4, 2, 0};

Wo jetzt dir restlichen zwei Felder auf 0 initialisiert werden...

    Ein sehr interessantes Feld is die so genannte Zeichenkette (String auf englisch) die ein Feld aus char's ist. Mit der Definierung:

char string[] = "test";

    definieren wir ein Feld mit 5 Feldern. Der Compiler fügt automatisch den Wert '\0' am Ende einer Zeichenkette hinzu. Wir werden nächstes mal mehr über Strings reden...

Ein paar mehr interessante Dinge über die Definition:

  • Als Feld-Datentyp können alle vordefinierten und selbstdefinierte (struct) Datentypen verwendet werden außer void.
  • Der Name eines Feldes muss natürlich den Inhalt beschreiben.
  • Nach der Definition kann man die Größe eines Feldes nicht mehr ändern. Ein Feld bleibt deswegen gleich groß während der gesamten Laufzeit des Programms.
  • In C starten die Arrays bei 0 oder Null.

Wertzuweisung

    Nach der Definition eines Feldes kann man die eingespeicherten Werte lesen oder zuweisen. Dazu muss man natürlich den Index des Wertes angeben. Sagen wir mal wir haben das Vorherige Feld das aus drei Ganzzahlen besteht. Die Indizes dieser drei Werte sind natürlich: 0, 1 und 2 (0 ... Größe - 1). Sagen wir mal wir wollen die ersten zwei Werte "lesen" und den letzten einen neuen Wert zuweisen. Das aus wie folgend:

printf("%d\n", numbers[0]); /* Konsole wird '4' ausdrucken*/
printf("%d\n", numbers[1]); /* Konsole wird '2' ausdrucken*/
numbers[2] = 1; /* Wert wird von '0' jetzt '1' */

Mehrdimensionale Felder

Die Definition mehrdimensionaler Felder ist wie folgend:

float nums[2][4]; /* Zweidimensionales Feld aus Float's */
double nums[1][2][3]; /* Dreidimensionales Feld aus Double's */

Mehr über Felder wird in den folgenden Artikeln kommen...

Anfänger Programm Erweitern

    Das Programm das wir letztes mal erklärt haben kann in mehreren Wegen erweitert werden. Sagen wir mal wie wollen nicht nur die gesamten Einnahmen von jeder Kategorie ausdrucken aber wollen auch Zahlungs-Informationen abspeichern. Die Fahrzeug und Maut Informationen werden also jetzt in Arrays abgespeichert. Zusätzlich werden wir jetzt auch die Anzahl die mit einer gewissen Zahlungsweise bezahlt hat auch nach Fahrzeugtyp "sortieren".

    Wir haben bis jetzt noch nicht über Dynamische Arrays geredet also wird die eigentliche Speichergröße erstmals Statisch sein. Wir werden die Größe dieser Arrays mit einem "define" Statement kontrollieren wo die Anzahl an Fahrzeugen 'N' sein wird. Ν kann z. B. 100 sein.

    So viele verschiedene Informationen zu eingeben würde sehr viel Zeit in Anspruch nehmen. Deswegen werden wir die ID des Fahrers jetzt mit einem Nummernschild (number-plate) für jedes Fahrzeug austauschen und dieses Nummernschild zufällig mit einem "random" Befehl generieren. Der Typ und das Kartenguthaben werden jetzt auch "random" generiert und der Typ wird könnte an dem Nummernschild basiert werden (wie davor) aber ich werde das hier nicht machen weil das unnötig ist... Nach N Fahrzeugen wird das Programm terminieren und die Resultate ausdrucken.

    Für die eigentliche Wiederholung können wir einen for oder while Loop benutzen. Einen for der von '0' startet und bis nach "i<N" geht oder einen while der die selbe Bedingung überprüft und auch be '0' startet. Bei beiden inkrementieren wir den Loop-Counter (Zähler) nach jeder Wiederholung. Um beides zu benutzen sagen wir mal das wir einen while-loop zum "Eingeben" benutzen und einen for-loop zum "Ausdrucken".

 Der Code ist wie folgend:

#include <stdio.h> // Ein- und Ausgabe Funktionen
#include <stdlib.h> // rand() Funktion
// wir wollen das die Anzahl an Fahrzeugen anpassbar ist
// deswegen benutzen wir das folgende Statement was die
// Fahrzeuganzahl zu N = 100 initialiert 
#define N 100 
int main(){
   // Loop counter (Zähler)
   int i=0;
   // Zähler Variablen für jeden Typ und alle zusammen
   int vehicles=0, cars=0, bikes=0, trucks=0;
   // Zähler Variablen für die Zahlungsweisen 
   int card=0, cash=0, both=0;
   // Ζähler Variablen für Zahlungsweisen nach Fahrzeugtyp
   int card_b=0, cash_b=0, both_b=0;
   int card_c=0, cash_c=0, both_c=0;
   int card_t=0, cash_t=0, both_t=0;

   // Nummernschild vom jetzigen Fahrzeug
   int plate; 
   // Nummernschild-Array für alle Fahrzeuge
   int plates[N]; 

   // Gebühr-Maut von dem jetzigen Fahrzeug
   int fee;
   // Kartenguthaben vor und nach der Bezahlung
   int balance_bef[N], balance_aft[N];

   // Gesamtes Einkommen für alle Fahrzeuge und jeden Typ alleine
   int total, total_cars, total_bikes, total_trucks;
   // Gesamtes Einkommen für jede Zahlungsweise
   int total_card=0, total_cash=0;
   // Arrays um die Maut, das Bargeld und dieKartenausgabe
   // von jedem Fahrzeug einzuspeichern
   int fees[N], cash_p[N], card_p[N];

   // zufällige nummer die den Typ bestimmt
   int r; 
   // Fahrzeugtyp der von r bestimmt wird
   char type; 
   // Αrray der die Fahrzeugtypen einspeichert 
   char types[N];
   // Array der die Bezahlungsweisen einspeichert
   char p_types[N];

   // Float für den Durchschnitt
   float avg; 

   // Der "Seed" der rand() Funktion wird zur jetztigen Zeit initialisiert
   // so das jede Ausführung des Programs andere Ergebnisse ausgibt 
   srand(time(NULL));

   // Loop solange i<N, also bis i == N Fahrzeuge
   while(i<N){ 
       // Nummernplate ist eine zufällige Nummer im Βereich 10000...90000
       // eine generelle Formulierung um zufällige Nummern zu generieren ist:
       // r = start + rand()%(end - start +1) und deswegen haben wir:
       plate = 10000 + rand()%(90000 - 10000 + 1);
       // jetziges Nummernschild im Array abspeichern
       plates[i] = plate;

       // Kartenguthaben ist im Bereich 0...10
       balance_bef[i] = rand()%11;

       // zufällige Nummer generieren um Typ und Maut zu bestimmen
       // Wert wird 1, 2 oder 3 sein
       r  = 1 + rand()%3;
       if(r == 1){
          type = 'b'; // Motorrad
          bikes++;
          fee = 3;
       }
       else if(r == 2){
           type = 'c'; // Auto
           cars++;
           fee = 5;
       }
       else{ //if 3
          type = 't'; // LKW
          trucks++;
          fee = 10;
       }
       // Typen und Maut in Array abspeichern
       types[i] = type;
       fees[i] = fee;
       vehicles++;

       // Zahlung
       if ( balance_bef[i] >= fee){ // nur Kretikkarte
          balance_aft[i] =  balance_bef[i] - fee; // neues Guthaben
          cash_p[i] = 0; // nichts mit Bargeld bezahlt
          card_p[i] = fee; // Maut mit Kreditkarte bezahlt
          card++;
          total_card += fee;
          // Bezahlungstyp einspeichern als 'c' (card)
          p_types[i] = 'c'; 
       }

       else if( balance_bef[i] == 0){ // Nur Bargeld 
       	  balance_aft[i] = 0; // Guthaben bleibt 0
          cash_p[i] = fee; // Maut mit Bargeld bezahlt
          card_p[i] = 0; // nicht mit Kreditkarte bezahlt
          cash++;
          total_cash += fee;
          // Bezahlungstyp einspeichern als 'm' (money)
          p_types[i] = 'm';
       }

       else{ // Beides
          balance_aft[i] = 0; // neues Guthaben ist 0
          cash_p[i] = fee -  balance_bef[i]; // Bargeld-Ausgabe abspeichern
          card_p[i] = balance_bef[i]; // Kreditkarten-Ausgabe abspeichern
          both++;
          total_cash += cash_p[i] ;
          total_card += balance_bef[i];
          // Bezahlungstyp einspeichern als 'b' (both)
          p_types[i] = 'b';
       }        
       // Zähler steigt 1 um zum nächsten Fahrzeug zu gehen
       i++; 
   }
   // Zähler Rechnungen ausdrucken
   // Ich werde '\t' benutzen um tab-space frei zu lassen
   printf("Plate\tType\tBalance bef.\tFee\tBalance aft\tCash\tCard\tPayment Type\n\n");
   for(i = 0; i < N; i++){
      printf("%d\t",plates[i]);
      if(types[i]=='b') printf("Bike\t");
      else if(types[i]=='c') printf("Car\t");
      else if(types[i]=='t') printf("Truck\t");
      printf("%d\t%d\t%d\t%d\t%d\t", balance_bef[i], fees[i],balance_aft[i], cash_p[i], card_p[i]);
      if(p_types[i]=='c') printf("Card Only\n");
      else if(p_types[i]=='m') printf("Cash Only\n");
      else if(p_types[i]=='b') printf("Card and Cash\n");
   }

   // Statistiken
   printf("A total of %d Vehicles passed by\n", vehicles);
   printf("Cars: %d, Bikes %d, Trucks %d\n", cars, bikes, trucks);
   // Einkommen Berechnen für jeden Fahrzeugtyp
   total_bikes = bikes * 3;
   total_cars = cars * 5;
   total_trucks = trucks * 10;
   total = total_bikes + total_cars + total_trucks;
   // Datentyp-Umwandlung um den Durchschnitt zu berechnen
   avg = (float) total / vehicles;
   printf("We earned %d in total\n", total);
   printf("From Cars: %d, Bikes: %d, Trucks: %d\n", total_cars, total_bikes, total_trucks);
   printf("Average is %.2f\n", avg);

   // Berechnungen und Einkommen von Kreditkarten und Bargeld
   printf("%d paid with Cash, %d with Card and %d with Both\n", cash, card, both);
   printf("We earned %d from Cash and %d from Card\n", total_cash, total_card);
   // Anzahl an Bezahlungweisen per Fahrzeugtyp berechnen
   for(i = 0; i < N; i++){ 
      if(types[i]=='b'){  
         if(p_types[i]=='c') card_b++;
         else if(p_types[i]=='m') cash_b++;
         else if(p_types[i]=='b') both_b++;  
      }
      else if(types[i]=='c'){
         if(p_types[i]=='c') card_c++;
         else if(p_types[i]=='m') cash_c++;
         else if(p_types[i]=='b') both_c++;      
      }
      else if(types[i]=='t'){
         if(p_types[i]=='c') card_t++;
         else if(p_types[i]=='m') cash_t++;
         else if(p_types[i]=='b')    both_t++;       
     }
   }   
   // Bezahlungsweisen-Zähler ausdrucken
   printf("Payment Type Counters:\n");
   printf("Bikes:\nCard Only: %d,Cash Only: %d,Card and Cash: %d\n", card_b, cash_b, both_b);
   printf("Cars:\nCard Only: %d,Cash Only: %d,Card and Cash: %d\n", card_c, cash_c, both_c);
   printf("Trucks:\nCard Only: %d,Cash Only: %d,Card and Cash: %d\n", card_t, cash_t, both_t);
   printf("All Together:\nCard Only: %d,Cash Only: %d,Card and Cash: %d\n", card, cash, both);
}


Eine Ausführung für N = 10 kann z. B. das folgende ausgeben:

Ja ich weiß ist nicht sooo gut "linearisiert" aber ist auf jeden Fall cool :)

    In C darf man eigentlich nicht Deutsch schreiben, also ist dies die Programmausführung der "englischen" Version die natürlich das selbe Programm ist aber mit anderen Kommentaren...

Referenzen

  1. https://de.wikipedia.org/wiki/Feld_(Datentyp)
  2. https://de.wikipedia.org/wiki/Felder_in_C

Vorherige(r) Artikel

Einführung -> Programmiersprachen, die Sprache C, Anfänger Programme

     Und das war's dann auch mit diesem Artikel. Ich hoffe euch hat das ganze gefallen und wir sehen uns dann nächstes mal wieder wo wir über "Zeiger" reden werden!

Tschüss!

Sort:  

@drifter2, I gave you an upvote on your post! Please give me a follow and I will give you a follow in return and possible future votes!

Thank you in advance!

Index ist bereits Deutsch. Plural von Index ist Indices oder Indizes, nicht aber Indizen. Eben so wenig ist Indiz eine Singularfrom von Index.

Hier der Duden Eintrag

Mehrzeiligen Quelltext kannst du durch drei Backticks einleiten.
Dann hast du keine Scrollbalken für jede einzelne Zeile.

Das macht dann den Quelltext lesbarer.
Return Type deiner Main Funktion ist integer, deshalb solltest du auch return 0; am Ende ausführen, damit du einen sauberen Exit-Code hast.

Oh wirklich? Lustig weil in Wikipedia irgendwie Indiz als das Deutsche Wort für Index benutzt wurde...werde dann einfach auf den Englischen Begriffen bleiben weil die ja auch meistens verständlicher sind :D
return 0; ist nicht nötig weil der Compiler das sowieso hinzufügt auch wenn man es selber vergisst :) Für einen "richtigen" Code müsste man das eigentlich hinzufügen aber man muss nicht so streng sein...
Das mit den Backticks ist mir neu, werde es beim nächsten Artikel versuchen zu benutzen. Eigentlich benutze ich letztens Screenshots aus dem IDE oder Text-Editor das meistens schöner aussieht. ;)
Danke für deinen hilfreichen Kommentar :)

return 0; ist nicht nötig weil der Compiler das sowieso hinzufügt auch wenn man es selber vergisst

Aber nicht bei ANSI-C 😉

$ gcc -Wall --std=c89 -o test main.c
main.c: In function ‘main’:
main.c:5:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^

Lustig weil in Wikipedia irgendwie Indiz als das Deutsche Wort für Index benutzt wurde

Hast du einen Link zu einem solchen Artikel?

Hab gerade wieder gecheckt...muss wohl das 's' mit nem 'n' verwechselt haben Haha!
Da stand wirklich Indizes und nicht Indizen (heißt ja was ganz anderes)
Indiz habe ich wegen dem Plural Wort benutzt...schätze ich mal :D
Hätte echt nicht erwartet das Index das selbe auf Deutsch und Englisch ist...aber Indiz heißt ja was ganz anderes. Indiz ist ja so zusagen das englische Wort für 'clue' oder 'evidence'..

Danke für deine Hilfe haha! Muss ein bisschen mit den Wörtern aufpassen. Bin ja kein Deutscher, sondern bin nur dort großgeworden also ist vieles ein bisschen verschwommen :P
Ich glaub das beste währe das ich einfach die englischen Wörter benutze...Ich schätze mal bei euren Unis lernt ihr das meiste auch auf Englisch oder nicht? Bei uns hier in Griechenland lernen wir die meisten Definitionen auf Englisch weil die griechischen Wörter meistens einfach übertriebenst lang sind .
P.s. Hab auch mal den Artikel gefixt ;)

Coin Marketplace

STEEM 0.19
TRX 0.15
JST 0.029
BTC 62827.81
ETH 2583.62
USDT 1.00
SBD 2.73