Christian Seiler: Einige C-Fragen

Beitrag lesen

Hallo,

Mit diesen Beispielcode habe ich es nun geschafft. Über einen kleinen Punkt bin ich aber noch hängengeblieben:

Ich wollte folgendes machen:

output[0] = name; // name ist dabei vom Typ char *

Dies führt aber stets zu komischen Ergebnissen.

Ja klar. Wenn Du Dir die Variable »output« mal aufmalst, dann sieht die so aus:

+--------+         +-----------+                  +------------------+
| output |-------->| output[0] |----------------->|                  |
+--------+         | output[1] |---               +------------------+
                   | output[2] |-  \              +------------------+
                   +-----------+ \  ------------>|                  |
                                  \               +------------------+
                                   \              +------------------+
                                    ------------>|                  |
                                                  +------------------+

+------+                  +------------------+
                        | name |----------------->|                  |
                        +------+                  +------------------+

Die leeren Kästchen sind alles Speicherbereiche, in denen Strings zu finden sind.

Wenn Du nun strcpy machst, dann wird einfach der Inhalt von dem Puffer, auf den die Variable name zeigt, in den Puffer output[0] kopiert. [1] Die Zeiger selbst ändern sich nicht.

Wenn Du dagegen output[0] = name machst, dann sieht das ganze so aus:

+--------+         +-----------+                  +------------------+
| output |-------->| output[0] |-------           |                  |
+--------+         | output[1] |---    \          +------------------+
                   | output[2] |-  \    |         +------------------+
                   +-----------+ \  ---|-------->|                  |
                                  \     |         +------------------+
                                   \    |         +------------------+
                                    ---|-------->|                  |
                                         \        +------------------+
                                          \                         +------+           \      +------------------+
                        | name |------------+---->|                  |
                        +------+                  +------------------+

Das heißt: Sowohl output[0] und name zeigen jetzt auf den gleichen Speicherbereich. Jetzt gibt es damit schon drei potentielle Probleme:

  1. Ich weiß nicht, woher bei Dir die Variable name jetzt kommt. Wenn das ein lokaler Puffer ist, hast Du das Problem, dass der Stack ja wieder weg ist, sobald die aufgerufene Funktion endet - (die gleiche Problematik wie wenn Du das direkt per return zurückgibst!).

  2. Da (zumindest wenn Du meinem Beispiel folgst) die Elemente von output alle per malloc() alloziert werden, werden sie auch hinterher mit free() wieder freigegeben. Wenn Du free() aber auf einen Puffer anwendest, der nicht per malloc() alloziert wurde, dann hat das böse Konsequenzen. Und selbst wenn (!) der Puffer von name bereits per malloc() alloziert wurde, würdest Du name selbst ja vmtl. auch an anderer Stelle per free() wieder loswerden und zweimal free() auf die gleiche Variable ist genauso schlecht.

  3. Der Puffer, auf den output[0] urpsrünglich zeigte, wird nirgends mehr referenziert und bleibt daher im Speicher bestehen. Er wird erst freigegeben, sobald das Programm sich beendet. Bei länger laufenden Programmen führt das zu sogenannten "Speicherlecks", d.h. die Programme verwenden immer mehr Speicher, selbst wenn sie ihn nicht mehr benötigten.

Ich habe mir das Buch, mit dem Du C lernen wolltest, jetzt nicht angesehen, aber anscheinend scheint es gerade auf die Subtilitäten bei Zeigern nicht gut genug einzugehen. Ich empfehle Dir daher mal das Standardwerk Programmieren in C von Kernighan/Ritchie.

Viele Grüße,
Christian

[1] Übrigens: Auch hier wieder: strcpy() ist so wie Du es verwenden willst vermutlich böse, weil keine Bereichsprüfung für den Zielpuffer durchgeführt wird.