zeiger.inc 25.2 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
<TABLE width="595" border="0" cellspacing="0" cellpadding="0">
<TR>
    <TD>
        <h1><u>Eine kurze Einfuehrung in die Geheimnisse des Speichers und
        der Zeigerprogrammierung (Pointer) in C/C++</u></h1><br>
        <br>
        Autor: <i>Georg Steffers (georg@steffers.org)</i><br>
        Copyright (c)2001 Georg Steffers<br>
        <br>
        Ueber mich: Zur Zeit bin ich in einer Web-Agentur als Programmierer 
        beschaeftigt.
        Ich programmiere seit meinem 16. Lebensjahr in C was mittlerweile satte
        11 Jahre macht und ich denke ich kann mich durchaus als fortgeschritten
        bezeichnen. Trotzdem koennen sich natuerlich in diesen Text Fehler
        eingeschlichen haben. Wenn irgend jemandem einer auffallen sollte bitte
        einfach eine Mail an obige mail-Adresse schicken, danke :-)<br>
        <br>
        Sollte dieser Text als Lehrstoff genutzt werde bitte ich darum ihn wie
        er ist abzudrucken und an die Lernenden weiterzugeben. Bei Zitaten oder
        Teilausdrucken bitte ich darum das ich weiterhin als Autor erkennbar
        bin. Danke.<br>
        <br>
        Ich habe versucht diesen Text so einfach wie moeglich zu halten um
        Anfaengern eine verstaendliche Einfuehrung in die Problematik von
        Pointern unter C zu geben. Dazu werde ich zunaechst eine einfache
        Schematische Darstellung des Speichers erklaeren um dann darauf
        einzugehen, wie man in einem Programm auf diesen zugreift (Variablen)
        und darauf aufbauend Zeiger erklaeren.<br>
        Dieses Wissen ist leider elementar und man kann nicht darauf verzichten,
        wenn man in C programmieren moechte. Auch nicht wenn man VisualC oder
        aehnliches verwendet. Denn leider bleibt es immer am Programmierer
        haengen wenn irgendetwas nicht funktioniert und um ein Programm debuggen
        (Fehler beseitigen) zu koennen muss man leider verstehen, wie es
        funktioniert.<br>
        <br>
        Ich rate dazu jedes Kapitel das einem noch nicht bekannt ist mehrfach
        zu lesen und dazwischen ein paar Pausen einzulegen um das gelesene zu
        verarbeiten. Wenn nach mehrfachem lesen Dinge immer noch nicht klar
        sind, habe ich sie nicht ausreichend erklaert und ich bitte darum mir
        die entsprechende Frage zu mailen. Ich werde dann mein bestes tun um
        das Problem zu loesen.<br>
        <br>
        Ich versuche in diesem Text kein Vorwissen vorauszusetzen. Sollte das
        irgendwo nicht geklappt haben schicken Sie mir bitte eine Mail und ich
        versuche den Fehler zu korrigieren.<br>
        <br>
        <br>
        <br>
        <b><u>Zu Bits und Bytes:</u></b><br>
        <br>
        Ein Rechner ist eine elektronische Maschine und auch die Daten in einem
        Rechner werden elektronisch gespeichert und verarbeitet. Genau wie jedes
        Elektronisches Geraet kennt der Rechner und somit ein einzelnes
        Speicherelement zwei Grundlegende zustaende (an/aus). Das ist
        vergleichbar mit einer Gluehbirne. Man kann sie einschalten oder
        ausschalten.<br>
        Wenn man jetzt dem ausgeschalteten Zustand des Speichers den Wert 0
        zuweist und dem eingeschalteten den Wert 1 koennen wir schon mal zwei
        Werte speichern. Voila, das waere ein Bit.<br>
        Nu hat man in modernen (und auch in den aelteren) Programmen aber meist
        mehr Werte zu verarbeiten als 0 und 1. Leider gibt es keinen Schalter
        der mehr als ein oder ausschalten kann (mal abgesehen von Dimmern
        vielleicht, aber Dimmer haben wir leider nicht in einem Rechner).<br>
        <br>
        Hier hilft uns wie so oft bei Rechnern die Mathematik. Wenn sie sich mit
        verschiedenen Zahlensystemen (Dual oder Binaer, Oktal, Dezimal, 
        Hexadezimal) auskennen koennen Sie die folgenden Zeilen zum goessten
        Teils ueberfliegen und zum naechsten Absatz weitergehen. Fuer alle
        anderen hier eine kurze Einfuehrung in Zahlensysteme.<br>
        Wie ihnen vielleicht bekannt ist rechnen wir normalerweise im
        dezimalsystem. Das bedeute unsere Zahlen bilden sich auch Ziffern zur
        basis 10 oder anders ausgedrueckt, jede Stelle einer Zahl kann Werte von
        0 bis 9 annehmen. Fuer einen Rechner ist das wie ich oben schon
        festgestellt habe eher bloed, weil unsere kleinste Speichereinheit das
        Bit nur entweder 0 oder 1 darstellen kann. Es gibt aber ein Zahlsystem,
        das genau diese anforderung Erfuellt. Das Dual oder Binaersystem. In
        diesem Zahlensystem werden Zahlen nur aus folgen von 0 und 1 gebildet.
        Dabei werden Zahlen zu einem grossen Teil genauso behandelt wie im
        Dezimalsystem. Wenn wir im Dezimalsystem mit einer Stelle nicht mehr
        auskommen, so erhoehen wir den Wert in der naechsten Stellen.
        Wir gehen von 9 nach 10 und von 49 nach 50. Genau dasselbe tun wir im
        Binaersystem auch, mit dem unterschied das wir halt nicht erst bei 9
        eine neue Stellen bekommen sondern bereits nach 1. <br>
        <br>
        Im Rechner werden die Daten binaer abgebildet. im Binaersystem sehen
        die Zahlen dann folgendermassen aus:<br>
        <br>
        <pre>
              dez  ->    bin
              0    ->      0
              1    ->      1
              2    ->     10
              3    ->     11
              4    ->    100
              5    ->    101
              6    ->    110
              7    ->    111
              8    ->   1000
              9    ->   1001
              10   ->   1010
              11   ->   1011
              12   ->   1100
              13   ->   1101
              14   ->   1110
              15   ->   1111
              16   ->  10000
        </pre><br>
        Wir haben also fuer jede Ziffer im Binaersystem immer nur den Wert 0
        oder 1 und diese koenne wir in unserem Bit darstellen.<br>
        Um jetzt Werte zu verarbeiten, die groesser als 0 oder 1 sind fasst man
        eine bestimmte Menge Speicherelement zusammen und betrachtet diese dann
        als eine Zahl. Bei dieser Zusammenfassung hat man sich auf bestimmte
        Mengen geeinigt. Die kleinste dieser Mengen fasst 8 Bits zusammen und 
        nennt sich Byte. In einem Byte kann man also Werte von 00000000 bis
        11111111 binaer darstellen. Das mach Dezimal 0 - 255. Fuer groessere
        Zahlen wurden dann groessere &lt;&lt;Datentypen&gt;&gt; eingefuehrt,
        die alle ein  vielfaches von 8 Bits bilden:<br>
        <br><pre>
   Byte        ->  8 Bit
   Word        -> 16 Bit
   double word -> 32 Bit
        </pre><br>
        <br>
        <br>
        <b><u>Der Speicher (und wie der Rechner (das Programm) ihn sieht):
        </u></b><br>
        <br>
        Da es hoechst selten vorkommt, das man wirklich nur 0 oder 1 benoetigt
        organisieren Rechner ihren Speicher nicht Bitweise sonder in groesseren
        Einheiten. <br>
        Hier sei nur kurz erwaehnt, das es vom Rechner abhaengt, was
        als kleinst moegliche Datenmenge angesehen wird, in diesem Text gehe ich
        davon aus , das der Rechner den Speicher Byteweise organisiert. Das soll
        fuer diesen Text reichen. Die Erkenntnisse aus diesem Text lassen sich
        aber auch problemlos auf Speicherorganisationen anwenden.
        Trotzdem moechte ich darauf hinweisen, da dieser Umstand in Programmen
        manchmal zu auf den ersten Blick nicht leicht zu findenden Fehlern
        fuehren kann.<br>
        Also, unser Rechner organisiert den Speicher Byteweise. Dabei wird
        intern jedem Byte eine &lt;&lt;Adresse&gt;&gt; zugewiesen.
        Diese Adresse ist einfach eine Zahl, die vom ersten Byte des Speichers
        bis zu seinem letzten Byte hochgezaehlt
        wird. Haben wir also nur 16 Byte Speicher in unserem Rechner so erreicht
        der Rechner das erste Byte ueber die Adresse 0 und das letzte ueber die
        Adresse 15. Jedes dieser Bytes kann dann einen anderen Wert haben.<br>
        Das kann man sehr schoen auf folgenden Art darstellen:<br>
        <br><pre>
                  Speicher     Adresse
                  --------- 
                 |   32    |   0
                 |---------|
                 |    0    |   1
                 |---------|
                 |   12    |   2
                 |---------|
                 |    0    |   3
                 |---------|
                 |    0    |   4
                 |---------|
                 |    0    |   5
                 |---------|
                 |    0    |   6
                 |---------|
                 |    0    |   7
                 |---------|
                 |   48    |   8
                 |---------|
                 |    0    |   9
                 |---------|
                 |   156   |   10
                 |---------|
                 |    0    |   11
                 |---------|
                 |    0    |   12
                 |---------|
                 |    0    |   13
                 |---------|
                 |    0    |   14
                 |---------|
                 |    0    |   15
                  --------- 
        </pre><br>
        Nun ist es fuer ein Programm nich besonders praktisch wenn man sich fuer
        alle Daten, die man speichern moechte die Adresse merken muesste. Bei 16
        Bytes mag das noch gehen aber moderne Computer habe haeufig 64 Millionen
        oder sogar noch mehr Bytes an Arbeitsspeicher (die bekannte MByte Zahl
        fuer den  Hauptspeicher.) Das wuerde dann doch ein wenig
        unuebersichtlich. <br>
        Deshalb kann man in einem C/C++ Programm einer Speicherstelle einen
        Namen geben. Das tut man wenn man Variablen deklariert:<br>
        <br><pre>
int main(void) {
    char erste;   /* Deklariert die Variable &lt;&lt;erste&gt;&gt; als char */
    char zweite;  /* Deklariert die Variable &lt;&lt;zweite&gt;&gt; als char */

    .
    .
    .
    .

    return 0;
}
</pre><br>
        C/C++ kennt intern unterschiedliche Datentypen. Diese Datentypen nehmen
        vielfaches von einem Byte an Speicher in Anspruch. Bei einem char ist
        das immer 1 Byte. Bei einer deklaration wird einem Namen in dem Programm
        eine Adresse im Speicher zugewiesen, hinter der genuegend Bytes fuer
        diese Variable frei sind. Wenn es geht werden Variablen wenn sie direkt
        hintereinander
        deklariert wurden auch direkt hintereinander im Speicher abgelegt.<br>
        Die obige deklaration koennte in unserem Beispielspeicher also
        folgendermassen aussehen.<br>
        <br><pre>
                  Speicher     Adresse   Variable
                  --------- 
                 |   32    |     0
                 |---------|
                 |    0    |     1
                 |---------|
                 |   12    |     2
                 |---------|
                 |    0    |     3       
                 |---------|
                 |    0    |     4
                 |---------|
                 |    0    |     5        erste
                 |---------|
                 |    0    |     6        zweite
                 |---------|
                 |    0    |     7
                 |---------|
                 |   48    |     8
                 |---------|
                 |    0    |     9
                 |---------|
                 |   156   |    10
                 |---------|
                 |    0    |    11
                 |---------|
                 |    0    |    12
                 |---------|
                 |    0    |    13
                 |---------|
                 |    0    |    14
                 |---------|
                 |    0    |    15
                  --------- 
</pre><br>
        Dann waehre &lt;&lt;erste&gt;&gt; ein Synonym fuer Adresse 5 im 
        Speicher und &lt;&lt;zweite&gt;&gt; ein Synonym fuer adresse 6. Um jetzt
        Werte im Speicher abzulegen kann man einfach folgendes machen:<br>
        <br><pre>
int main(void) {
    char erste;
    char zweite;

    erste=7;    /* Zuweisung */
    zweite=10;  /* Zuweisung */

    .
    .
    .
    .

    return 0;
}
        </pre><br>
        Das nennt man einer Variable einen Wert zuweisen. Diese Zuweisung kann
        auch aus einer Arithmetischen Operation bestehen z.B. erste=7+4. Dann
        wuerde zuerst die berechnung durchgefuehrt und das Ergebnis der Variable
        zugewiesen. Nach obigem Beispiel saehe unser Speicher so aus:<br>
        <br><pre>
                  Speicher     Adresse   Variable
                  --------- 
                 |   32    |     0
                 |---------|
                 |    0    |     1
                 |---------|
                 |   12    |     2
                 |---------|
                 |    0    |     3       
                 |---------|
                 |    0    |     4
                 |---------|
                 |    7    |     5        erste
                 |---------|
                 |   10    |     6        zweite
                 |---------|
                 |    0    |     7
                 |---------|
                 |   48    |     8
                 |---------|
                 |    0    |     9
                 |---------|
                 |   156   |    10
                 |---------|
                 |    0    |    11
                 |---------|
                 |    0    |    12
                 |---------|
                 |    0    |    13
                 |---------|
                 |    0    |    14
                 |---------|
                 |    0    |    15
                  --------- 
        </pre><br>
        an die Stelle im Speicher mit der Adresse 5 wurde eine 7 geschrieben und
        an die folgende mit der Adresse 6 wurde eine 10 geschrieben. Wenn man
        seine Variable jetzt irgendwoanders als in einer Zuweisung verwendet so
        wird dar Name der Variable durch den Inhalt des Bytes im Speicher
        ersetzt auf das er verweist. Wir koennen zum Beispiel mit unseren
        Variablen rechnen:<br>
        <br><pre>
int main(void) {
    char erste;
    char zweite;
    char ergebnis;

    erste=7;    /* Zuweisung */
    zweite=10;  /* Zuweisung */

    ergebnis=erste+zweite; /* hier werden zunaechst die Variablen durch
                              den Speicherinhalt (also 7 und 10) ersetzt,
                              dann eine addition mit ihnen durchgefuehrt
                              und anschliessend das Ergebnis einer weiteren
                              Variable zugewiesen. */

    .
    .

    return 0;
}
        </pre><br>
        Unser Speicher saehe danach also folgendermassen aus:<br>
        <br><pre>
                  Speicher     Adresse   Variable
                  --------- 
                 |   32    |     0
                 |---------|
                 |    0    |     1
                 |---------|
                 |   12    |     2
                 |---------|
                 |    0    |     3       
                 |---------|
                 |    0    |     4
                 |---------|
                 |    7    |     5        erste
                 |---------|
                 |   10    |     6        zweite
                 |---------|
                 |   17    |     7        ergebnis
                 |---------|
                 |   48    |     8
                 |---------|
                 |    0    |     9
                 |---------|
                 |   156   |    10
                 |---------|
                 |    0    |    11
                 |---------|
                 |    0    |    12
                 |---------|
                 |    0    |    13
                 |---------|
                 |    0    |    14
                 |---------|
                 |    0    |    15
                  --------- 

        </pre><br>
        Das ist soweit alles was mir zu Variablen einfaellt, obwohl bestimmt
        noch hunderte von Fragen offen bleiben. Wie gesagt bitte mailen... :-)
        Jetzt kommen wir dann zu:<br>
        <br>
        <br>
        <b><u>Zeiger oder (ja wo stehen sie denn?)<br>
        oder (warum C Programmierer dauernd fluchen):</u></b><br>
        <br>
        Ein Zeiger (Pointer) ist eine spezielle Form einer Variable.
        Anstatt einen Wert zu enthalten enthaelt dies Variable eine
        Speicheradresse Der Inhalt eines Zeigers zeigt also sozusagen auf eine
        andere Stelle im Speicher.<br>
        Einer meiner Dozenten hat mal eine passende Analogie gebracht:<br>
        <br>
        Ein Zeiger ist wie ein Vorwegweiser an einer Strasse.<br>
        <ul>
        <li>Der Vorwegweiser zeigt auf den Ort wo man hinfahren moechte.
        <li>Ein Zeiger zeigt auf die Stelle im Speicher an die man moechte.
        </ul><br>
        Im Moment ist es sicher schwierig den Sinn einer solchen Variable zu
        verstehen, aber Sie koennen mir glauben, wenn ich ihnen sage, das man
        in C/C++ dauernd Zeiger braucht. Machen Sie sich im Moment keine
        Gedanken darueber wann und warum sondern konzentrieren Sie sich voll
        auf das wie. Das wann und warum kommt beim programmieren und im Laufe
        des folgenden Textes von ganz alleine (hoffe ich).<br>
        <br>
        C/C++ hat eine besonder Syntax (Schreibweise) um mit Zeigern umzugehen:
        <br><br>
        Ich hoffe folgendes Programm/Diagramm mach deutlich was gemeint ist.<br>
        <br><pre> 
int main(void) {
    char erste;   /* Deklariert die Variable &lt;&lt;erste&gt;&gt; als char */
    char zweite;  /* Deklariert die Variable &lt;&lt;zweite&gt;&gt; als char */

    char* zeiger; /* Deklariert einen Zeiger, der auf eine Speicherbereich
                     zeigt, der die groesse eines char habe soll.
                     Kling kompliziert ich weiss...ich versuche es unten
                     in einem weiten Speicherdiagramm zu verdeutlichen. */

    /* Man kann Zeigern wie jeder anderen Variable auch Werte zuweisen. */
    zeiger=0;

    .

    return 0;
}
        </pre><br>
        das ganze sieht dann im Speicher bildlich so aus:<br>
        <br><pre>
                  Speicher     Adresse   Variable
                  --------- 
              -->|   32    |     0
             |   |---------|
             |   |    0    |     1
             |   |---------|
             |   |   12    |     2
             |   |---------|
             |   |    0    |     3       
             |   |---------|
             |   |    0    |     4
             |   |---------|
             |   |    7    |     5        erste
             |   |---------|
             |   |   10    |     6        zweite
             |   |---------|
              ---|    0    |     7        zeiger
                 |---------|
                 |   48    |     8
                 |---------|
                 |    0    |     9
                 |---------|
                 |   156   |    10
                 |---------|
                 |    0    |    11
                 |---------|
                 |    0    |    12
                 |---------|
                 |    0    |    13
                 |---------|
                 |    0    |    14
                 |---------|
                 |    0    |    15
                  --------- 
        </pre><br>
        Gut...wenn also ein Wert in einer Zeigervariable steht soll dieser fuer
        die Adresse einer Speicher stelle stehen. Das hat allerdings nur einen
        Sinn wenn ich auch an den Inhalt dieser Speicheradresse kommen kann auf
        die der Zeiger zeigt.<br>
        Benutzt man den Zeiger wie die normalen Variablen, so wird er immer
        durch die Adresse ersetzt und nicht durch den Wert der Speicherstelle an
        dieser Adresse. Folgendes kleine Programm soll das erleutern. In diesem
        Programm tauchen ein paar neue Dinge auf, die ich aber versuche direkt
        an dem Programm zu erklaeren. Dies wird das erste Programm in diesem
        Text was sie compilieren und ausfuhren koennen:<br>
        <br><pre>
int main(void) {
    char erste;      /* Variable deklarieren */
    char zweite;     /* Variable deklarieren */

    char* zeiger;    /* Zeiger deklarieren */

    erste = 7;       /* 7 zuweisen */
    zweite = 10;     /* 10 zuweisen */

    zeiger = &erste; /* Das & vor erste hat eine spezielle Bedeutung.
                        Normalerweise wird ja eine Variable durch ihren
                        Wert ersetzt. Schreibt man in C/C++ aber ein &
                        vor die Variable so wird diese durch die
                        Speicheradresse an der sie steht ersetzt. Da
                        der Inhalt eines Zeigers eine Adresse ist kann man
                        ihm diese dann zuweisen. */

    /* Jetzt folgen ein paar Ausgaben, die Zeigen sollen an welcher Adresse
       welcher Wert steht. Es ist sehr wichtig zu verstehen, was hier
       passiert. Das setzt voraus das man die printf Funktion von C
       kennt und versteht */
    
    printf("Variable:  erste - Adresse: %lu - Wert: %lu\n", &erste, erste);
    printf("Variable: zweite - Adresse: %lu - Wert: %lu\n", &zweite, zweite);
    printf("Zeiger:   zeiger - Adresse: %lu - Wert: %lu\n", &zeiger, zeiger);

    return 0;
}
        </pre><br>
        Nachdem diese Programm uebersetzt und ausgefuehrt wurde sollte man in
        etwa folgende Ausgabe erhalten (die Werte weden unterschiedlich sein):
        <br>
        <br><pre>
Variable:  erste - Adresse: 3221223243 - Wert: 7
Variable: zweite - Adresse: 3221223242 - Wert: 10
Zeiger:   zeiger - Adresse: 3221223236 - Wert: 3221223243
        </pre><br>
        Hier ist wichtig zu erkennen, das der Wert von &lt;&lt;zeiger&gt;&gt;
        der Adresse von &lt;&lt;erste&gt;&gt; entspricht.<br>
        Wie oben bereits erwaehnt waere es jetzt sinnvoll, wenn man ueber
        &lt;&lt;zeiger&gt;&gt; auch irgendwie an den Wert von
        &lt;&lt;erste&gt;&gt; kommen koennte. Tatsaechlich dienen Zeiger
        eigentlich nur diesem Zweck.<br>
        Dafuer gibt es in C wieder eine spezielle Syntax. Um an den Wert von
        &lt;&lt;erste&gt;&gt; zu kommen kann man &lt;&lt;*zeiger&gt;&gt;
        schreiben. Das nennt man dereferenzieren. Das Wort kommt daher, das
        &lt;&lt;zeiger&gt;&gt; eine  Referenz auf &lt;&lt;erste&gt;&gt; ist und
        man diese Referenz jetzt  aufloest (dereferenzieren) (klingt furchtbar
        kompliziert ich weiss).<br>
        <br>
        Diese Syntax verwirrt gerade Anfaenger haeufig, da man den * auch schon
        bei der deklaration des Zeigers benutzt hat.<br>
        Hier muss man
        strikt zwischen der deklaration eines Zeigers und dem dereferenzieren
        unterscheiden. Ich mache es mir dadurch leichter, das ich bei der
        deklaration den * immer an den Datentyp schreibe und beim
        dereferenzieren an den Variablennamen. Beispiel:<br>
        <br><pre>
 -  char* zeiger;    /* deklaration eines Zeiger */
 -  erste = *zeiger; /* dereferenzieren von Zeiger */
        </pre><br>
        Wie sich das auswirkt soll folgendes Programm zeigen. Es ist im
        wesentlichen dasselbe Programm wie vorhin mit einer zusaetzlichen
        Ausgabe:<br>
        <br><pre>
int main(void) {
    char erste;      /* Variable deklarieren */
    char zweite;     /* Variable deklarieren */

    char* zeiger;    /* Zeiger deklarieren */

    erste = 7;       /* 7 zuweisen */
    zweite = 10;     /* 10 zuweisen */

    zeiger = &erste; /* Das & vor erste hat eine spezielle bedeutung.
                        Normalerweise wird ja eine Variable durch ihren
                        Wert ersetzt. Schreibt man in C/C++ aber ein &
                        vor die Variable so wird diese durch die
                        Speicheradresse an der sie streht ersetzt. Da
                        der Inhalt eines Zeigers eine Adresse ist kann man
                        ihm diese dann zuweisen. */

    /* Jetzt folgen ein paar Ausgaben, die Zeigen sollen an welcher Adresse
       welcher Wert steht. Es ist sehr wichtig zu verstehen, was hier
       passiert. Das setzt voraus das man die printf Funktion von C
       kennt und versteht */
    
    printf("Variable:       erste - Adresse: %lu - Wert: %lu\n", &erste, erste);
    printf("Variable:       zweite - Adresse: %lu - Wert: %lu\n", &zweite, zweite);
    printf("Zeiger:         zeiger - Adresse: %lu - Wert: %lu\n", &zeiger, zeiger);
    printf("dereferenziert: zeiger - %lu\n", *zeiger);

    return 0;
}
        </pre><br>
        Das Programm sollte folgende Ausgabe machen:<br>
        <br><pre>
Variable:       erste - Adresse: 3221223243 - Wert: 7
Variable:       zweite - Adresse: 3221223242 - Wert: 10
Zeiger:         zeiger - Adresse: 3221223236 - Wert: 3221223243
dereferenziert: zeiger - 7
        </pre><br>
        Man sieht, das &lt;&lt;*zeiger&gt;&gt; identisch mit
        &lt;&lt;erste&gt;&gt; ist.<br>
        So, das solls fuers erste mal sein...ich wuerde vorschlagen mit den
        Programmen ein bisschen herumzuexperimentieren.<br>
        Noch ein Wort: Es kann Ihnen beim experimentieren durchaus passieren,
        das das Programm nachdem sie es ausfuehren ein Fehlermeldung der art 
        &lt;&lt;segmentation fault&gt;&gt; oder &lt;&lt;overflow error&gt;&gt;
        oder aehnlches (je nach dem mit welchem System sie arbeiten) ausgibt.
        Das sind Fehler, die darauf hinwiesen, das der Pointer keine gueltige
        Adresse enthaelt. Dadurch greift dann naemlich das
        &lt;&lt;*zeiger&gt;&gt; auf eine ungueltige (nicht dem eigenen Programm
        zugeordnete Adresse) zu.<br>
        <br>
        Viel Spass und bei Fragen bitte mail an mich...ich bin fuer
        Verbesserungsvorschlaege und Fragen immer offen.
    </TD>
</TR>
</TABLE>