Forum: PC-Programmierung C-Array vom typ Zeiger


von Dirk_30 (Gast)


Lesenswert?

Hallo zusammen,

ich habe mal eine Frage zum Thema Array und Zeiger in C.

Folgendes:

char *p[]={"Guten Tag"};
printf("%s",p[0]);

Fragen:

1.)Wieso ist Variable p nur 4Byte gross?
2.)Spielt es keine Rolle welchen Datentyp ich nehme (char, int, float), 
warum nicht ?

3.) Muss ich nicht bei der Ausgabe mit *p[0] arbeiten, weil ich mir doch 
den Wert ansehen möchte?

4.) Wo genau wird der String "Guten Tag" abgelegt, kann ich auf die 
einzelnen Buchstaben zugreifen?

gruß,

Dirk

von Johann L. (radiostar)


Lesenswert?

Ich versuch's mal:

> char *p[]={"Guten Tag"};
> printf("%s",p[0]);

> 1.)Wieso ist Variable p nur 4Byte gross?

p[] ist ein Array aus Pointern auf char und enthält genau einen Pointer, 
nämlich den auf den String "Guten Tag"

> 2.)Spielt es keine Rolle welchen Datentyp ich nehme (char, int, float),
> warum nicht ?

Pointer sind immer gleich groß und die Größe ist abhängig vom 
Prozessor/Betriebssystem

> 3.) Muss ich nicht bei der Ausgabe mit *p[0] arbeiten, weil ich mir doch
> den Wert ansehen möchte?

%s erwartet einen Pointer, deshalb: nein.

> 4.) Wo genau wird der String "Guten Tag" abgelegt, kann ich auf die
> einzelnen Buchstaben zugreifen?

p[0] enthält den Pointer, d.h. die Adresse, an der der String abgelegt 
ist.

p[0][0] müßte dann der erste Buchstabe sein, wenn ich mich nicht irre. 
Eine andere Methode, auf die einzelnen chars dews Strings zuzugreifen 
wäre, den Ponter selbst weiterzuzählen:

char a = *p[0];
char b = *(p[0]+1);
oder
char b = *++p[0];

usw.

(alle Angaben ohne Gewähr, selbstverständlich)

von amateur (Gast)


Lesenswert?

p ist 4 Bytes groß, weil die Zeiger deines Compilers 32 Bit groß sind.
Zeiger ist Zeiger. Ob auf char, int oder float ist unwichtig, da er ja 
nur eine vollständige Adresse enthalten muss. Es gibt auch einen Zeiger 
auf void, bei dem erst gar kein Datentyp festgelegt wurde. Ist gut zum 
Rechnen (Zeigerarithmetik).

Der Befehl:
char *p[]={"Guten Tag"};
bewirkt mehreres:
1. Reservieren eines Zeigers. Bei Dir 4 Byte lang.
2. Anlage einer Konstanten irgendwo im Speicher. Bei Dir: "Guten Tag\0"
3. Initialisieren von p mit der Adresse von "G".

Wenn Du wissen willst wo im Speicher der String liegt: "p" weiß es.

von Dirk_30 (Gast)


Lesenswert?

Hallo und danke für Antworten,

also wird irgendwo im Speicher eine Variable mit unbekannten Name 
angelegt, die den String "Guten Tag" aufnehmen kann und aufnimmt.

Es müsste ja dann eine char -Variable bzw. Array sein, mir der grösse 
von 10 Bytes?

von amateur (Gast)


Lesenswert?

Ich vergaß:
Vorsicht bei der Manipulation von p
Am Anfang zeigt er ja auf 'G'.
++p oder p++
bewirkt, dass *p auf 'u' zeigt.

Niemand außer "p" weis wo der Buchstabe "G" steht. Deshalb, wenn 
möglich, niemals p direkt manipulieren.

Ab diesem Zeitpunkt (++p) bewirkt die Ausgabe mit >>printf("%s",p[0]);<<
"uten Tag"

Also im obigen Falle dass --p oder p-- nicht vergessen. Alternativ 
zwischenspeichern.

von amateur (Gast)


Lesenswert?

Solltest Du, warum auch immer, wissen wollen wo den Dein guter Tag 
rumhängt, so musst Du das selber in die Hand nehmen.
Z.B.
char TachChen [] = "Guten Tag";
char *p;
...
p =  TachChen;


printf("%s",p);

von Dirk_30 (Gast)


Lesenswert?

Okey, werde das ganze mal in Ruhe durcharbeiten um die Logik zu 
verstehen. Eigentlich bin ich da nur zu gekommen, als ich die 
main-Funktion so programmierte, dass man beim Aufruf des Programmes, 
Parameter übergibt.

void main(int argc, char*argv[])

Denn dort taucht diese Array-Zeiger Geschichte auf, die ich so noch 
nicht kannte.

von Rolf M. (rmagnus)


Lesenswert?

amateur schrieb:
> Es gibt auch einen Zeiger auf void, bei dem erst gar kein Datentyp
> festgelegt wurde. Ist gut zum Rechnen (Zeigerarithmetik).

Das nun gerade nicht, denn Zeigerarithmetik geht nicht mit Zeigern auf 
void. Ist auch logisch, denn der Compiler nutzt ja die Größe des 
Zieltyps als Basis, und void hat keine Größe.

Dirk_30 schrieb:
> also wird irgendwo im Speicher eine Variable mit unbekannten Name
> angelegt, die den String "Guten Tag" aufnehmen kann und aufnimmt.

Im Prinzip ja. Allerdings spricht C dann nicht von einer Variablen, 
sondern von einem Objekt. Variablen sind nämlich definiert als Objekte, 
die einen Namen haben.

> Es müsste ja dann eine char -Variable bzw. Array sein, mir der grösse
> von 10 Bytes?

Ja, genau. Es handelt sich um ein Array aus const char der Länge 10. Den 
Inhalt darf man nicht verändern.

von Karl H. (kbuchegg)


Lesenswert?

Dirk_30 schrieb:
> Okey, werde das ganze mal in Ruhe durcharbeiten um die Logik zu
> verstehen. Eigentlich bin ich da nur zu gekommen, als ich die
> main-Funktion so programmierte, dass man beim Aufruf des Programmes,
> Parameter übergibt.
>
> void main(int argc, char*argv[])
>
> Denn dort taucht diese Array-Zeiger Geschichte auf, die ich so noch
> nicht kannte.

dein Beispiel erzeugt
1
  p
2
  +------+                    +---+---+---+---+---+---+---+---+---+---+
3
  |  o----------------------->| G | u | t | e | n |   | T | a | g | \0|
4
  +------+                    +---+---+---+---+---+---+---+---+---+---+
Sieh dir p selber an. Da geht einfach nur ein Pfeil raus der irgendwo 
hin führt. Warum also sollte die Größe dieser Pointervariable variieren, 
je nachdem wo der Pfeil hingeht. Pointer ist Pointer - Pfeil ist Pfeil. 
Mit
  double * Ptr;
machst du eine Aussage darüber, was sich am >Ende< des Pfeiles befindet. 
Nämlich ein double. zb
1
     Ptr
2
     +------+                    +-------------+
3
     |  o----------------------->| 3.141592654 |
4
     +------+                    +-------------+
Aber der Ausgangspunkt des Pfeiles, die Pointervariable, wird dadurch ja 
nicht größer oder kleiner. Das worauf dieser Pointer zeigt ist größer 
geworden. Aber um den "Pfeil" zu speichern, braucht man ja nicht mehr 
oder weniger Platz, als im Fall vorher.
In
  double * Ptr;
stecken 2 Informationen drinnen!
a)  der * sagt, dass die Variable ein Pointer ist, also die Adresse
    eines anderen 'Objektes', welches irgendwo im Speicher liegt,
    enthält
b)  das double trifft eine Aussage darüber, welchen Datentyp dieses
    'Objekt', auf welches verwiesen wird, hat. Denn wenn man über
    den Pointer auf das Objekt zugreift, muss man ja wissen, was das
    ist - welchen Datentyp es hat.
    Ist das worauf der Pointer zeigt ein int, ein double, ein long?
    Wobei man nur durch den Pointer nicht unterscheiden kann, ob
    das worauf der Pointer zeigt, jetzt nur ein einzelnes derartiges
    Objekt ist, oder ob dort mehrere Objekte hintereinander abgelegt
    sind (vulgo: ob der Pointer auf ein Array zeigt). Aber im Regelfall
    weiß man dieses als Programmierer.


dein main kriegt bei einem Aufruf des Programms aus der Command Line mit 
zb dem Kommando
"test.exe arg1 arg2 /juhu"
1
  argv
2
  +------+                   +---+---+---+---+---+
3
  |   o--------------------->| t | e | s | t | \0|
4
  +------+                   +---+---+---+---+---+
5
  |   o-------------+
6
  +------+          |   +---+---+---+---+---+
7
  |   o--------+    +-->| a | r | g | 1 | \0|
8
  +------+     |        +---+---+---+---+---+
9
  |   o-----+  |
10
  +------+  |  |               +---+---+---+---+---+
11
  | NULL |  |  +-------------->| a | r | g | 2 | \0|
12
  +------+  |                  +---+---+---+---+---+
13
            |
14
            v
15
            +---+---+---+---+---+---+
16
            | / | j | u | h | u | \0|
17
            +---+---+---+---+---+---+
Also ein Array von Pointern, wobei jeder Pointer auf einen String zeigt. 
Wie genau der erste String aufgebaut ist, der den Namen des Programms 
enthält, ist nicht festgelegt und hängt vom Betriebssystem bzw. dessen 
Command Line Interpreter ab.

von Dirk_30 (Gast)


Lesenswert?

Danke für die vielen und ausführlichen Erklärungen, mit der Grafik ist 
mir jetzt klar geworden, wie sich die Zeiger verhalten.

Und wieder etwas mehr C verstanden,....

Gruß,

Dirk

von Andreas B. (andreas_b77)


Lesenswert?

Rolf Magnus schrieb:
> Das nun gerade nicht, denn Zeigerarithmetik geht nicht mit Zeigern auf
> void. Ist auch logisch, denn der Compiler nutzt ja die Größe des
> Zieltyps als Basis, und void hat keine Größe.

Der Vollständigkeit halber: Im gcc geht das schon, das ist aber eine 
gcc-spezifische Erweiterung. Der gcc nimmt dafür die Größe 1.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.