SUCHE MIT Google
Web virtualuniversity.ch
HOME DIDAKTIK ECDL ELEKTRONIK GUIDES HR MANAGEMENT MATHEMATIK SOFTWARE TELEKOM
DIENSTE
Anmeldung
Newsletter abonnieren
Sag's einem Freund!
VirtualUniversity als Startseite
Zu den Favoriten hinzufügen
Feedback Formular
e-Learning für Lehrer
Spenden
Autoren login
KURSE SUCHEN
Kurse veröffentlichen

Suche nach Datum:

Suche mit Schlüsselwort:

Suche nach Land:

Suche nach Kategorie:
PARTNER
ausbildung24.ch - Ausbildungsportal, Seminare, Kursen... 

 
HTMLopen.de - Alles was ein Webmaster braucht

 
PCopen.de - PC LAN Netze und Netzwerke - alles was ein IT Profi und Systemtechnicker braucht

SOFTWARE
| a | b | c | d | e | f | g | h | i | j |\0 | x | y | z |\0 | | | ^s1 ^s2 printf("%s\n",s1); --> "abcdefghij" printf("%s\n",s2); --> "" Natürlich hängt es sehr von der Speicherorganisation ab, wo die Variablen im einzelnen abgelegt sind (oft sind sie auf eine Wortgrenze ausgerichtet, besitzen also etwas Spielraum!). Gibt man einen solchen String an eine Funktion weiter, so ist innerhalb der Funktion nur die Startadresse bekannt (Feldname ist Anfangsadresse). Man kann dann nur mit einem weiteren Argument überprüfen, ob der Speicherbereich überschritten wird:
                                       int getline(char buf[], int len);    /* Deklaration (Prototyp) von getline */
                                       
                                       main ()
                                         {
                                         int ll;
                                         char string[80];
                                       
                                         ll = getline(string, sizeof string); /* Aufruf von getline */
                                         return 0;
                                         }
                                       
                                       int getline(char s[], int lim);
                                         {
                                         int i = 0;
                                         for(i=0; i<lim-1; i++)
                                           s[i] = ....;
                                         s[i] = '\0';
                                         return i;
                                         }
                                       
Folgende Regeln lassen sich daraus ableiten:
  • Felder immer groß genug wählen
  • Feldgrenzen immer abfragen
  • Bei Strings auf die abschließende'\0'achten
Werden diese Hinweise beachtet, können viele Speicherabstürze vermieden werden.

Falsch gesetzte Semikolons

  • Einer der häufigen Fehler das Vergessen des Semikolons am Ende der Anweisung. Dummerweise merkt der C-Compiler das oft erst in der nächsten Zeile und weist erst dann darauf hin. Aber immerhin handelt es sich um einen Compile-Fehler.
  • Auch das Vergessen des Semikolons am Ende einer Strukturdeklaration kann merkwürdige Auswirkungen haben. Wird gleich anschließend das Hauptprogramm ohne Returntyp definiert, interpretiert der Compiler die Struktur als Returntyp des Hauptprogramms.
  • for( ... ; ... ; ...) ;
    { ... }

    beendet Schleifenrumpf, analog bei while
  • Ein ähnliches Problem ist das Vergessen der Blockklammer in Kontrollstrukturen:
                                           while (i > O)
                                             tuwas();
                                             i++;
                                           
    Hier besteht die Schleife nur aus dem Kopf mit der Bedingung und dem Aufruf der Funktion tuwas() Der Zähler i++ ist bereits außerhalb der Schleife - also wieder eine Endlos-Schleife!

Falsche Einrückung

Bei der if-Kontrollstruktur ist oft nicht klar, zu welchem if ein else gehört:
                                       if (i > j)
                                         if (k < 100)
                                           tuwas();
                                       else
                                         tuwasanderes();
                                       
Es hat hier den Anschein, als ob das else zum ersten if gehört - das ist falsch. Ein else gehört immer zum nächst höheren if, das noch kein else hat - also zum zweiten if! Korrektur durch eine Block-Klammer:
                                       if (i > j)
                                         {
                                         if (k < 100)
                                           tuwas();
                                         }
                                       else
                                         tuwasanderes();
                                       

Die switch-Falle

Eine weitere Kontrollstruktur kann Kummer machen: switch. Wird hier ein break vergessen, so arbeitet C sequentiell weiter, auch wenn andere Marken anstehen. Jede Auswahl sollte also normalerweise mit break abgeschlossen werden.
                                       switch (c) 
                                         {
                                         case '1': tuwas(); break; 
                                         case '2': tudies(); break;
                                         case '3': tujenes(); break;
                                         default:  printf("error\n"); break;
                                         }
                                       
Vielleicht kann hier der Präprozessor helfen:
                                       #define CASE break;case
                                       #define DEFAULT break;default
                                       
Dann kann die Auswahl so aussehen:
                                       switch (c) 
                                         {
                                         CASE '1': tuwas();  
                                         CASE '2': tudies();
                                         CASE '3': tujenes();
                                         DEFAULT:  printf("error\n");
                                         }
                                       

Float-Ausdrücke

Eine weitere Falle ist folgende Rechnung:
double d = 3/4; Hier wird zunächst 3 durch 4 geteilt - was für Integerwerte natürlich 0 ist. Dann wird dieses Ergebnis d zugewiesen als 0.000000 (über eine implizite Typumwandlung) und bleibt somit natürlich 0. Abhilfe schafft die Verwendung der richtigen Konstanten 3.0 und 4.0 als double (zumindest eine):
double d - 3.0/4.0;

Vergleichsoperator vs. Zuweisungsoperator

In Vergleichen vergißt man leicht, daß der Vergleichsoperator = = und der Zuweisungsoperator = unterschiedliche Funktionen haben. Eine (scheinbare) Bedingung while (i = 20) weist der Variablen i den Wert 20 zu, was logisch gesehen wahr (ungleich 0) ist, also wieder eine Endlosschleife ergibt. Natürlich kann dies (z. B. bei Strings) auch positev genutzt werden:
                                       char s1(100), s2[100];
                                       
                                       /* s1 nach s2 kopieren (bis Stringende '\0') */
                                       while (s2[i] = s1[i])
                                         i++;
                                       

Reihenfolge der Auswertung

  • i++ * i++ undefiniert
  • Reihenfolge nur definiert bei &&, ||, Komma und ?:, dort sogar bedingte Auswertung
  • Alle Argumente einer Funktion werden in unbestimmerter Reihenfolge vor dem Aufruf ausgewertet

Eingabe-Probleme

Desweiteren gibt es oft bei der Bibliotheksfunktion scanf Schwierigkeiten. Vergißt man doch allzuleicht das Adreß-Zeichen & bei den Argumenten. Weniger durchschaubar ist aber, daß scanf das abschließende \n im Tastaturpuffer läßt, so daß ein nachfolgender getchar()-Aufruf dies als erstes geliefert bekommt. Möchte man scanf und getchar mischen, empfiehlt es sich, den Tastaturpuffer zu löschen:
                                       #include 
                                       
                                       int i, c, ret; 
                                       ret = scanf("%d",&i);         /* gepufferte Eingabe */
                                       if(ret != 1) error();        /* Fehlerbehandlung */
                                       while (getchar() != '\n';    /* Eingabepuffer leeren */
                                       getchar();                    /* Einzelzeichen lesen */
                                       
Das Überprüfen des Return-Codes ist außerdem fast ein Muß, sofern man nicht sowieso die ganze Zeile einliest und untersucht:
                                       fgets(buf, MAX, stdin);
                                       sscanf(buf, .... );
                                       
Dann kann auch auf versehentliche Leerzeilen reagiert werden.

Preprozessor

  • Ein mit #if ausgeklammertem Text muß aus gültigen Preprozessortokens bestehen
  • Makros können ebenfalls Probleme bereiten: #define sqr(x) x = x*x Hier wird ein Square-Makro definiert, der das Quadrat einer Zahl ermitteln soll.
    Dies funktioniert auch für Variablen ganz gut: int i = 10; ... sqr(i); ...
    Nun steht in i das Quadrat, also 100. Benutzt man dieses Makro aber für einen Wert (sqr(10);), so macht die Zuweisung Probleme. Also sollte man die Zuweisung im Makro unterlassen: #define sqr(x) x*x
  • i = sqr(10); funktioniert nun. Ruft man dieses Makro nun aber mit einem Ausdruck auf, gibt es wieder Probleme: i = sqr(2 + 8); wird zu 2 + 8 * 2 + 8 ersetzt und da Punktrechnung vor Strichrechnung geht, ist das Ergebnis 2 + 16 + 8 = 26, also falsch. Die zweite Regel sollte also lauten, Klammern zu verwenden:
                                           #define sqr(x) ((x)*(x))
                                           
    Doch damit ist beispielsweise sqr(++i); noch nicht gelöst, da nun ++i zweimal ausgeführt wird, und zwar ++i * ++i. Dieses Problem ist mit Makros nicht zu lösen. Also keine Zuweisungen oder andere Seiteneffekte in Makroaufrufen!

Konstante und Variable

  • Bei const char *a und char *b ist a=b ok (Erlaubnis zum Ändern wird nicht übernommen), b=a ist dagegen falsch (Erlaubnis zum Ändern wird fälschlicherweise gegeben)
  • Bei const int a und int b ist a=b falsch (Unerlaubte Änderung), b=a ist erlaubt (Verarbeitung nur einer Kopie)

(Null-)Pointer

  • NULL ist nur #define NULL 0 - Automatische Typumwandlung
  • Pointer sind keine Integer-Werte.
  • Ein Zeiger muß immer mit einer gültigen Speicherplatzadresse initialisiert sein.

Arrays und Pointer

  • In einer Datei char a[5], in der anderen extern char *a ist falsch, extern char a[] ist richtig
  • Äquivalenz der Deklarationen char a[] und char *a nur bei formalen Argumenten von Funktionen
  • char b[][] und char **b nicht äquivalent, letzteres verwendet real im Speicher vorhandene Pointer
  • Aufzeichnen: Realer Speicher bei char **a, char *a[], char (*a)[], char a[][]
  • Dynamische Allozierung mehrdimensionaler Felder: Am besten Allozieren eines Feldes mit Pointern und Allozieren jeder einzelnen Zeile

Dynamische Speicherverwaltung

  • char *s; gets(s); ist falsch, da kein Speicher bereitsteht
  • char *s="Hal",*t="lo!",*u=strcat(*s,*t) ist genauso falsch
  • Mit free() freigegebener Speicher darf nicht mehr angesprochen werden

DIPLOMARBEITEN UND BÜCHER

Diplomarbeiten zum Runterladen:

Suche im Katalog:
Architektur / Raumplanung
Betriebswirtschaft - Funktional
Erziehungswissenschaften
Geowissenschaften
Geschichtswissenschaften
Informatik
Kulturwissenschaften
Medien- und Kommunikationswissenschaften
Medizin
Psychologie
Physik
Rechtswissenschaft
Soziale Arbeit
Sozialwissenschaften


JOBS
HOME | E-LEARNING | SITEMAP | LOGIN AUTOREN | SUPPORT | FAQ | KONTAKT | IMPRESSUM
Virtual University in: Italiano - Français - English - Español
VirtualUniversity, WEB-SET Interactive GmbH, www.web-set.com, 6301 Zug

Partner:   Seminare7.de - PCopen.de - HTMLopen.de - WEB-SET.com - YesMMS.com - Ausbildung24.ch - Manager24.ch - Job und Karriere