so habe ich dann ein Array von 10 Zeigern geschaffen oder?
Also wenn ich einem von 10 Zeigern eine Adresse geben will, dann muss
ich schreiben:
1
zahl[5]=&irgendeineZahl
Das habe ich alles ausprobiert. Jedoch gibt es noch die Variante mit dem
Doppelzeiger, die ich überhaupt nicht verstehe. Daher meine Frage wann
verwende ich jetzt was?
Gruß Smakka
Es gibt nicht noch DIE Variante mit Doppelzeigern. Es gibt Zeiger auf
Zeiger, und die verwendet man halt, wenn man Zeiger auf Zeiger benötigt.
Wenn du da eine konkrete Frage hast, dann zeig das Codebeispiel mit
Zeiger auf Zeiger, welches du nicht verstehst.
Oliver
Danke schonmal für die Erläuterungen.
Dr. Sommer schrieb:> Tipp dazu: http://cdecl.ridiculousfish.com/?q=long+*zahl[10]%3B
Das hier ist wirklich sehr interessant
Was genau sind denn jetzt eigentlich die Anwendungen von Zeiger auf
Zeiger??
Ich habe einmal ein Testprogramm geschrieben, und weiß nicht, ob man es
auch so richtig macht. Es funktioniert jedenfalls:
1
intmain(){
2
char*zeigerKette[10];
3
zeigerKette[0]="Hallo Welt1";
4
zeigerKette[1]="Hallo Welt2";
5
zeigerKette[2]="Hallo Welt3";
6
7
printf("%s\n",zeigerKette[0]);
8
printf("%s\n",zeigerKette[1]);
9
printf("%s\n",zeigerKette[2]);
10
11
zeigerKette[0]="555";
12
13
printf("%s\n",zeigerKette[0]);
14
printf("%s\n",zeigerKette[1]);
15
printf("%s\n",zeigerKette[2]);
16
17
18
return0;
19
}
Ich bin mir bei diesen Zeigern nie sicher was man machen darf und was
nicht. Dann kommen noch diese Zeiger auf Zeiger.
Manchmal sehe ich sowas:
1
long**funtion();
und ich weiß einfach nicht was das ist! Wird hier einfach ein Zeiger auf
einen Zeiger zurückgegeben? Was hat das für einen Sinn, wenn doch ein
Zeiger auf Zeiger immer noch ein Zeiger ist. Wieso übergebe ich nicht
einfach nur einen Zeiger. Das hat doch die selbe Performance oder nicht?
Gruß
Die erste Motivation, wenn man Zeiger auf Zeiger benötigt, ist in der
Argumentliste einer Funktion, die einen übergebenen Zeigen manipulieren
soll. Und zwar so, dass beim Aufrufer diese Manipulation sichtbar ist.
Mal ein einfacheres Beispiel.
Das hier
1
voidfoo(inti)
2
{
3
i=8;
4
}
5
6
intmain()
7
{
8
intk=5;
9
10
foo(k);
11
12
// hier hat k immer noch den Wert 5
13
}
ist dir hoffentlich klar.
Was passiert hier?
Die Funktion foo bekommt ein Duplikat des Wertes von k. Beim
Funktionsaufruf wird dieser Wert (5) an i innerhalb der Funktion
gebunden und steht auch so in der Funktion zur Verfügung. Du kannst i
innerhalb der Funkion verändern, aber diese Veränderung wirkt sich nicht
auf k aus, da ja zwischen dem i und dem k keinerlei Verbindung besteht.
i hat seinen Wert von k erhaltem, aber das wars dann auch schon.
Jetzt gibt es aber Fälle, da möchte man genau das nicht. Man möchte eine
Funktion in die Lage versetzen, so dass sie auf die Variable des
Aufrufers 'durchgreifen' kann und die Variable beim Aufrufer verändern
kann. Wie geht das?
1
voidfoo(int*i)
2
{
3
*i=8;
4
}
5
6
intmain()
7
{
8
intk=5;
9
10
foo(&k);
11
12
// hier hat k den Wert 8 !
13
}
anstett dem Wert von k wird der Funktion die Adresse von k übergeben.
Diese Adresse wird an i zugewiesen, so dass i damit auf die Variable k
zeigt. Wird mittels *i der Wert an dieser Adresse verändert, dann
verändert man damit k, denn die Adresse war ja die Adresse an der k im
Speicher existiert.
So weit so gut. Das allgemeine Schema ist also.
Sie T ein bestimmter Datentyp, dann ermöglicht man mit dem Schema
1
voidfoo(T*i)
2
{
3
*i=WertderfürTzulässigist;
4
}
5
6
intmain()
7
{
8
Tk=Wert;
9
10
foo(&k);
11
}
der Funktion den Durchgriff auf die Variable des Aufrufers, so dass die
Funktion die Variable beim Aufrufer ändern kann. Und zwar unabhängig vom
tatschlichen Datentyp T. In diesem Beispiel war T der Datentyp int.
Was aber, wenn T der Datentyp char * ist?
Folgende Motivation:
Wir haben eine Variable text in main, die auf den konstanten Text
"Hallo" zeigen soll. Das ist leicht
1
intmain()
2
{
3
char*text="Hallo";
4
}
Jetzt soll es eine Funktion geben, die text verändern soll. Und zwar
soll text danach auf den String "Juhu" zeigen. Also im Grunde das hier
1
intmain()
2
{
3
char*text="Hallo";
4
5
text="Juhu";
6
}
würde man danach einen
1
printf("%s\n",text);
machen, dann würde das selbstverständlich "Juhu" ausgeben.
Aber: Jetzt wollen wir diese Zuweisung nicht in main machen, sondern in
einer eigenen Funktion.
Das hier
1
voidfoo(char*str)
2
{
3
str="Juhu";
4
}
5
6
intmain()
7
{
8
char*text="Hallo";
9
10
foo(text);
11
}
kann nicht die Lösung sein, denn Analog zum ersten Beispiel mit dem int,
kriegt die Funktion ja nur eine Kopie der Adresse in text. SIe kann mit
dieser Adresse machen was sie will, aber sie kann damit nicht text
selber verändern.
Will eine Funktion eine Variable beim Aufrufer ändern, dann lautete das
allgemeine Schema
1
voidfoo(T*i)
2
{
3
*i=WertderfürTzulässigist;
4
}
5
6
intmain()
7
{
8
Tk=Wert;
9
10
foo(&k);
11
}
und genau dieses Schema brauchen wir. Bei uns ist T der Datentyp char *,
und genau das setzen wir da jetzt mal ein anstelle von T ein
1
voidfoo(char**str)
2
{
3
*str="Juhu";
4
}
5
6
intmain()
7
{
8
char*text="Hallo";
9
10
foo(&text);
11
12
printf("%s\n",text);
13
}
Jetzt gibt dieses Programm tatsächlich "Juhu" aus. Die Funktion hat über
einen Pointer auf den Pointer text, die Adresse verändert auf die text
zeigt.
Willkommen bei deinen ersten Schritten in der Welt der 2-Stern
Programmierung.
@Karl Heinz Buchegger: Das war ja wirklich sehr sehr gut erklärt!! Danke
dafür!
So langsam beginne ich zu verstehen wohin das hinführt. Aber konkret
meinte ich so ein Beispiel:
Schreiben Sie eine Funktione, die eine Zeichenkette an ein Feld von
Zeichenketten anhängt und einen Zeiger auf das vergrößerte Feld
zutrückliefert.
1
char **store_in_array(char **storage, long length, char *newitem);
Ich weiß ich brauche ein Feld von Zeichenketten, aber wie lege ich das
konkret an? Diese Doppelsterne verwirren mich als, dass sie helfen es
übersichtlicher zu machen.
Smakka schrieb:> Schreiben Sie eine Funktione, die eine Zeichenkette an ein Feld von> Zeichenketten anhängt und einen Zeiger auf das vergrößerte Feld> zutrückliefert.
Komisch, wer macht denn in den Ferien Hausaufgabe?
Ein Feld von Zeichenketten:
1
char*foo[10];
Ein Pointer auf das Feld mit Zeichenketten:
1
char**pfoo=&(foo[0]);
Das lässt sich auch so schreiben:
1
char**pfoo=foo;
aber da sieht man das "Pointer auf Pointer" nicht so offensichtlich.
Oliver
Oliver S. schrieb:> Ein Feld von Zeichenketten:
Eben da hängt es ja wieder, da ja ein String angehängt werden soll. Das
heißt ich muss mit Malloc speicher reservieren um ihn eventuell mit
realloc zu erweitern. Ich weiß aber nicht wie das mit einem Array von
Zeichenketten und Malloc gehen könnte. Das ist mir im Moment einwenig
sehr abstrakt.
Oliver S. schrieb:> Komisch, wer macht denn in den Ferien Hausaufgabe?
EIgentlich nehme ich über die Ferien Nachhilfe.
Gruß
SO, habe jetzt folgendes versucht dynamischen Speicher als Array zu
reservieren, als Vorbereitung für die Strings, jedoch haut das noch
nicht so ganz hin:
1
intmain(){
2
int**array_2D=calloc(10,sizeof(int*));
3
inti=0;
4
while(i<10){
5
*array_2D=calloc(10,sizeof(int));
6
array_2D++;
7
i++;
8
}
9
10
*(*(array_2D))=12;
11
*(*(array_2D)+1)=33;
12
*(*(array_2D+1))=12;
13
*(*(array_2D+1)+1)=33;
14
15
return0;
16
}
Ich weiß nicht wieso es nicht funktioniert. Die Schleife passt, jedoch
stimmt bei der Zeigerarithetik irgendetwas nicht. Ich weiß nur nicht
was.
Gruß
Smakka schrieb:> while(i < 10){> *array_2D = calloc(10, sizeof(int));> array_2D++;> i++;> }>> *(*(array_2D)) = 12;
du versauchst dir deine variabel array_2D weil du dir nicht den alten
wert merkst.
Peter II schrieb:> for( i = 0; i < 10; ++i ){> array_2D[i] = calloc(10, sizeof(int));> }
Danke, obwohl ich noch nicht ganz verstehe, was dahintersteckt und wieso
das gleichwertig ist. Werds mir zugemüte ziehen, wenn mein Code
funktioniert.
Smakka schrieb:> *(*(array_2D)) = 12;> *(*(array_2D) + 1) = 33;> *(*(array_2D+1)) = 12;> *(*(array_2D+1) + 1) = 33;
Wieso funktioniert das hier nicht?
Ich verstehe das überhaupt nicht.
Smakka schrieb:> Danke, obwohl ich noch nicht ganz verstehe, was dahintersteckt und wieso> das gleichwertig ist. Werds mir zugemüte ziehen, wenn mein Code> funktioniert.
*(a+i) = a[i]
Smakka schrieb:>> *(*(array_2D)) = 12;>> *(*(array_2D) + 1) = 33;>> *(*(array_2D+1)) = 12;>> *(*(array_2D+1) + 1) = 33;>> Wieso funktioniert das hier nicht?
keine Ahnung was geht dann nicht, bekommst du einen fehler?
lesbar sollte es so genauso gehen
array_2D[0][0] = 12;
array_2D[0][1] = 33;
...
(bin mir nicht 100% sicher, doppelzeiger braucht man recht selten)
Smakka schrieb:> Smakka schrieb:>> *(*(array_2D)) = 12;>> *(*(array_2D) + 1) = 33;>> *(*(array_2D+1)) = 12;>> *(*(array_2D+1) + 1) = 33;>> Wieso funktioniert das hier nicht?> Ich verstehe das überhaupt nicht.
Bezogen auf den ursprünglichen Code?
Weil du in der Schleife davor array_2D fleißig inkrementiert hast.
Smakka schrieb:> So funktioniert das jetzt!
und genau das habe ich doch schon oben geschrieben, nur das ich dabei
noch einen schritt weitergegangen bin.
Peter II schrieb:> *(a+i) = a[i]
Dieses Mysterium wird wohl für die nächste Zeit ein Mysterium bleiben.
Ich muss es wohl akzeptieren.
Ich weiß, dass ein Zeiger:
int *array = malloc(10*sizeof(int));
auch darauf zugegriffen werden kann mit array[i] = WERT;
Jedoch ist mir dabei irgendwie unklar was da C eigentlich macht.
Wenn ich aber schreibe:
1
int**array_2D=calloc(10,sizeof(int*));
2
array_2D[0]=malloc...
greife ich dann mit array_2D[0] auf einen Zeiger zu? Muss ja sein oder?
Also konkret: Ist array_2D[0] der 0llte Zeiger,sprich der erste Zeiger
von den 10??
Smakka schrieb:> Jedoch ist mir dabei irgendwie unklar was da C eigentlich macht.
genau das gleiche. Es ist am ende nur eine andere Schreibweise,
es ensteht genau der gleiche code.
> greife ich dann mit array_2D[0] auf einen Zeiger zu?
ja, dann es ist nichts anders als ein *(array_2D+0)
Smakka schrieb:> greife ich dann mit array_2D[0] auf einen Zeiger zu? Muss ja sein oder?> Also konkret: Ist array_2D[0] der 0llte Zeiger,sprich der erste Zeiger> von den 10??
genau
zum verständis, kannst du den Typ auch durch was anderes substituieren.
1
typedefint*MyType;
2
3
MyType*array_2D=calloc(10,sizeof(MyType));// legt ein array von 10 Elementen MyType an
4
MyTypeelement0=array[0];// ließt das 0. element aus
Das MyType selbst ein Zeiger ist, ist für das Konstrukt irrelevant.
Du solltest in jedem Fall im Hinterkopf haben, dass der Speicher
uninitialisiert ist, sprich die Zeiger auf zufällige Adressen Zeigen.
Edit:
oh ich seh grad calloc nullt den Speicher sogar
Ok, lieben lieben Dank an euch. Das ist sehr gut erklärt. Ich wüsste
nicht was ich machen würde ohne Mikrocontroller.net.
Das mit der Stringtabelle funktioniert trotzdem noch nicht so ganz
richtig. Wie soll ich denn einen String einlesen und ihn an einem
dynamischen Speicher anhängen?? Der String steht ja in einem Char array
und nicht an einer bestimmten Addresse. Da müsste ich für jeden String
ein eigenes Char Array machen, was aber wiederrum das Konzept der
dynamischen Speicherung auf den Kopf wirft. Konkret habe ich diesen Code
hier geschrieben, jedoch keine Idee wie ich das Char Array als eigne
Adresse in den Speicher verschiebe.
Was mache ich aber wenn ich einen String einlesen will und dann in das
dynamische Array hineinladen will.
Dann brauche ich ja einen Puffer in das ich zuerst einlese. Aber was
kommt danach? Wenn ich im dynamischen Speicher immer nur auf den Puffer
verweise, so bringt das nichts, denn dieser verändert sich ja immer.
Welche Maßnahmen muss ich hier treffen?
Gruß
Smakka schrieb:> Was mache ich aber wenn ich einen String einlesen will und dann in das> dynamische Array hineinladen will.http://stackoverflow.com/questions/4023895/how-to-read-string-entered-by-user-in-cSmakka schrieb:> Wenn ich im dynamischen Speicher immer nur auf den Puffer> verweise, so bringt das nichts, denn dieser verändert sich ja immer.> Welche Maßnahmen muss ich hier treffen?
du musst für jede Eingabe natürlich einen neuen Puffer holen.
Vlad Tepesch schrieb:> du musst für jede Eingabe natürlich einen neuen Puffer holen.
Das meine ich nicht. Ich meine wenn ich schreibe
char *zeichenkette = "Hallo Welt";
dann ist ja der String "Hallo Welt" irgdendwo im Speicher abgelegt, und
die Addresse wo das ist liegt im Zeiger zeichenkette.
Wenn ich jedoch einen String einlese, so muss ich ihn zuerst in einen
Puffer einlesen, zum Beispiel so:
char puffer[100];
scanf("%s", puffer);
Und die Frage jetzt natürlich ist, wie ich diesen String einem Feld von
Zeichenketten hinzufüge, wenn doch das Feld dynamisch sein soll.
Also wie kann ich die zweite Methode wie die erste verwenden? Oder wie
macht man das generell?
Gruß
D. h. überall, wo man einen Zeiger auf das i-te Element eines Arrays a
braucht, kann man statt der expliziten Adressbildung mit dem &-Operator
auch einfach den Index zum Array (oder Zeiger) addieren. Die
Zeigersemantik von C bewirkt dabei, dass der Zeiger nicht etwa um i
Bytes, sondern um i Elemente weitergezählt wird.
Smakka schrieb:> char puffer[100];> scanf("%s", puffer);>> Und die Frage jetzt natürlich ist, wie ich diesen String einem Feld von> Zeichenketten hinzufüge, wenn doch das Feld dynamisch sein soll.>> Also wie kann ich die zweite Methode wie die erste verwenden? Oder wie> macht man das generell?
Meinst Du vielleicht
char *zeichenkette = puffer;
Das Anlegen des Speicherplatz braucht's natürlich trotzdem, denn im 1.
Fall macht das der Compiler, der legt aber nur genau soviel
Speicherplatz an wie Du für "Hallo Welt" brauchst.
Und bei der 2. Methode musst Du vorher festlegen, wie lang Deine
maximale Eingabe sein darf (zumindest in C).
Wenn Du
scanf("%s", puffer);
mit einer zu langen Eingabe aufrufst, dann kracht's.
Deshalb ist
scanf("%100s", puffer);
puffer[99] = '\0';
besser