Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

03.01.2014, 00:48

C Pointer/Zeiger

Hi,

wollte mich mal mit C befassen und bin auf ein paar Probleme im Umgang mit Zeigern gestoßen, daher wollte ich fragen ob mir jemand sagen kann auf welche Adressen/Werte ich jeweils in folgendem Quelltext zugreife:

ich komme aus der Java-Welt, da existiert dieses ganze Zeiger-Ding nicht - Java hat nur Referenzen

C-/C++-Quelltext

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
#include <stdio.h>
#include <stdlib.h>

main ()
{
    int zahl = 8;
    int *zeiger;
    *zeiger = zahl;
    int **zeig = &zeiger;

    printf("\nPointer auf Variablen\n\n");
    printf("Integer\n");
    printf("zeiger: %d\n", zeiger);
    printf("*zeiger: %d\n", *zeiger);
    printf("&zeiger: %d\n\n", &zeiger);
    printf("Pointer\n");
    printf("zeiger: %p\n", zeiger);
    printf("*zeiger: %p\n", *zeiger);
    printf("&zeiger: %p\n\n\n", &zeiger);
    printf("Pointer auf Pointer\n\n");
    printf("Integer\n");
    printf("zeig: %d\n", zeig);
    printf("*zeig: %d\n", *zeig);
    printf("**zeig: %d\n", **zeig);
    printf("&zeig: %d\n", &zeig);
    printf("Pointer\n");
    printf("zeig: %p\n", zeig);
    printf("*zeig: %p\n", *zeig);
    printf("**zeig: %p\n", **zeig);
    printf("&zeig: %p\n", &zeig);

    system("PAUSE");
    return 0;
}



Ausgabe:

Quellcode

1
2
3
4
5
6
Pointer auf Variablen
Integerzeiger: 2686824*zeiger: 8&zeiger: 2686696
Pointerzeiger: 0028FF68*zeiger: 00000008&zeiger: 0028FEE8

Pointer auf Pointer
Integerzeig: 2686696*zeig: 2686824**zeig: 8&zeig: 2686692Pointerzeig: 0028FEE8*zeig: 0028FF68**zeig: 00000008&zeig: 0028FEE4



Wäre nett wenn ihr mir dies erklären könntet und falls ich wichtige Dinge zum Thema vergessen habe auch diese - vllt noch wo ich wie auf Zeiger/adressen schreibe bzw. diese manipuliere.

Danke im Voraus und ein gesundes neues Jahr

Edit by dot: Formatierung fixed

Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von »dot« (03.01.2014, 01:50)


dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

2

03.01.2014, 02:23

ich komme aus der Java-Welt, da existiert dieses ganze Zeiger-Ding nicht - Java hat nur Referenzen

Wobei Java Referenzen allerdings konzeptionell eher sowas wie Pointer sind... ;)

C-/C++-Quelltext

1
main ()

Ich weiß nicht, ob das durch meinen Edit verloren ging, aber es müsste eigentlich int main() heißen. Falls dein Compiler das wirklich kompiliert, solltest du dringend auf einen aktuellen Compiler wechseln, denn das ist kein Standard-C. Falls du das in einem Buch gelesen hast, solltest du das Buch dringend durch ein aktuelles Buch ersetzen...

Um deine Frage zu beantworten, kommentiere ich am Einfachsten wohl gleich direkt deinen Code:

C-/C++-Quelltext

1
2
3
4
    int zahl = 8;
    int *zeiger;
    *zeiger = zahl;  // Fehler: zeiger ist uninitialisiert, dass das nicht crashed ist pures Glück.
    int **zeig = &zeiger;  // Ok: zeig zeigt nun auf zeiger


C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    printf("\nPointer auf Variablen\n\n");
    printf("Integer\n");
    printf("zeiger: %d\n", zeiger);  // Fehler: Du übergibst an printf einen Pointer, dein Format-String sagt aber, dass es sich um einen Integer handelt. Dass das nicht crashed, ist pures Glück.
    printf("*zeiger: %d\n", *zeiger);  // Ok
    printf("&zeiger: %d\n\n", &zeiger);  // Selber Fehler wie vorhin: &zeiger ist ein Pointer und kein Integer.
    printf("Pointer\n");
    printf("zeiger: %p\n", zeiger);  // Hier ist es nun richtig.
    printf("*zeiger: %p\n", *zeiger);  // Dafür stimmt das nun nicht, *zeiger ist ein Integer und kein Pointer, dein Format-String sagt aber, dass es sich um einen Pointer handelt. Dass das nicht crashed, ist pures Glück.
    printf("&zeiger: %p\n\n\n", &zeiger);  // Ok, &zeiger ist ein Pointer.
    printf("Pointer auf Pointer\n\n");
    printf("Integer\n");
    printf("zeig: %d\n", zeig);  // Wieder selber Fehler, zeig ist ein Pointer und kein Integer.
    printf("*zeig: %d\n", *zeig);  // Fehler: *zeig ist ebenfalls ein Pointer und kein Integer.
    printf("**zeig: %d\n", **zeig);  // Ok, **zeig ist ein Integer.
    printf("&zeig: %d\n", &zeig);  // Fehler: &zeig ist ein Pointer.
    printf("Pointer\n");
    printf("zeig: %p\n", zeig);  // Ok
    printf("*zeig: %p\n", *zeig);  // Ok
    printf("**zeig: %p\n", **zeig); // Fehler: **zeig ist ein Integer, kein Pointer. Dass das nicht crashed, ist pures Glück.
    printf("&zeig: %p\n", &zeig);  // OK

Du stoßt hier an eines der fundamentalen Probleme von printf(), nämlich die mangelnde Typsicherheit. printf() bestimmt den Typ der übergebenen Argumente anhand des Format-String. Wenn da ein "%d" steht, dann geht printf() davon aus, dass es sich um einen int handelt. Wenn da "%p" steht, geht es davon aus, dass es sich um einen Pointer handelt. Dies wird allerdings weder beim Kompilieren noch zur Laufzeit überprüft. Du hast es hier mit sogenanntem "Undefinierten Verhalten" zu tun: Es ist im Rahmen der Sprache C nicht garantiert, was dieser Code auf einem konkreten System genau anstellen wird. Theoretisch darf hier alles passieren, unter anderem auch was du erwartest, genauso dürfte es aber auch crashen oder die Schwerkraft umkehren. Manche Compiler werden hier eine Warnung ausspucken. Auf deinem System mit deinem Compiler ist ein int wohl gleich groß wie ein Pointer, weshalb es bei dir gerade funktioniert. Bereits mit einem anderen Compiler oder gar nur anderen Compilereinstellungen könnte es aber schon Probleme geben, beispielsweise wenn du das zu einer 64-Bit Anwendung kompilierst (Pointer haben 64 bit) auf einer Platform, wo ein int nur 32 Bit hat...

C-/C++-Quelltext

1
    system("PAUSE");

Ich würde empfehlen, hier einfach einen Breakpoint zu setzen, oder mal zu schauen, ob deine IDE dir da nicht helfen kann. system() ist problematisch, weil nicht portabel und unglaublich ineffizient. Auch erschwert es die Verwendung deiner Anwendung beispielsweise in einem Skript zur Batchverarbeitung...

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »dot« (03.01.2014, 02:34)


3

03.01.2014, 04:04

Danke schonmal.

Ich nutze die MinGW Compiler-Bibliothek und dort gcc mit Standardeinstellungen.

Sonst compiliere ich über Konsole. Solange ich kein Projekt in C starte hatte ich eigentlich nicht vor eine IDE zu verwenden.

So und nun wollte ich nochmal nach gewissen Unterschieden fragen bei
*zeig und zeig

und eigentlich müsste ja "zeiger" und "&zeiger" auch unterschiedlich sein, da "&zeiger" ja die Speicheradresse des Pointers zurück gibt und was "zeiger" alleine macht weiß ich gar nicht hab nur gemerkt, dass ich irgendeinen wert bekomme ähnlich der Speicheradresse. Wenn ich den Wert als integer ausgebe bekomme ich die ins Dezimalsystem umgerechnete Speicheradresse oder whatever das ist.

Und warum kann ich den Zeiger nicht später erst initialisieren?

macht es denn einen Unterschied ob ich:
int *zeiger, zahl = 0;
*zeiger = &zahl;

oder

int *zeiger = NULL, zahl = 0;
*zeiger = &zahl;

dann gibt es ja noch den -> Operator der auch irgendwie zum zuweisen von Zeigern benutzt wird - wann ich diesen benutze weiß ich leider auch nicht genau.

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

4

03.01.2014, 11:00

Und warum kann ich den Zeiger nicht später erst initialisieren?

Wer sagt, dass du das nicht kannst?
Klar geht das.
Bei Referenzen geht es allerdings nicht, die kannst du nur einmal setzen und danach nicht mehr "umbiegen".

So und nun wollte ich nochmal nach gewissen Unterschieden fragen bei
*zeig und zeig

*zeig ist das, worauf der Zeiger zeigt (* ist der Operator für Dereferenzierung).
zeig ist der Zeiger selbst.

und eigentlich müsste ja "zeiger" und "&zeiger" auch unterschiedlich sein

So ist es auch.

dann gibt es ja noch den -> Operator der auch irgendwie zum zuweisen von Zeigern benutzt wird - wann ich diesen benutze weiß ich leider auch nicht genau.

Der Pfeil-Operator ist nur relevant, wenn du einen Zeiger auf eine Instanz einer Klasse oder Struktur hast.
Er hat nichts mit Zuweisung zu tun, sondern mit dem Zugriff auf Members einer Klassen- oder Strukturinstanz über einen Zeiger darauf.
zeiger->etwas ist einfach nur eine andere Schreibweise für (*zeiger).etwas (es sei denn, operator -> wurde überladen, aber vergiss das erst einmal).

Werbeanzeige