Hallo Zusammen,
habe eine Frage zum STM32F429. So wie ich verstanden habe, gibt es Libs,
die von privat auf verschiedenen Webseiten hochgeladen werden. Als C++
Programmierer hab ich da aber ein Problem.
In meinem Code werden folgende Parameter gefragt: int sprintf ( char *
str, const char * format, ... );
Dachte in C gibt es keine Zeiger? Und wenn, warum schreibe ich dann
"sprintf (buffer, "%d plus %d is %d", a, b, a+b);" ohne Adressoperator
vor der buffer-char?
Zweitens habe ich eine andere Funktion, bei der ebenfalls der Zeiger
einer Variablen erwartet wird, als Parameter übergebe ich dann das hier:
UB_Font_DrawString(10,70,"Pressed
,&Arial_11x18,RGB_COL_BLACK,RGB_COL_GREEN);
Hier wird vor dem Arial-Font der Adressoperator verwendet?!?! Bin
verwirrt.
Michael schrieb:> Dachte in C gibt es keine Zeiger?
wie kommst du darauf. Bei C und C++ gehören schon immer Zeiger zur
Sprache.
Michael schrieb:> Dachte in C gibt es keine Zeiger? Und wenn, warum schreibe ich dann> "sprintf (buffer, "%d plus %d is %d", a, b, a+b);" ohne Adressoperator> vor der buffer-char?
weil es C ist, und Arrays(strings) immer also Zeiger übergeben werden.
Michael schrieb:> UB_Font_DrawString(10,70,"Pressed> ,&Arial_11x18,RGB_COL_BLACK,RGB_COL_GREEN);
kann alles mögliche Bedeuten, da das " kein Gegenstück hat.
Michael schrieb:> Dachte in C gibt es keine Zeiger? Und wenn, warum schreibe ich dann> "sprintf (buffer, "%d plus %d is %d", a, b, a+b);" ohne Adressoperator> vor der buffer-char?
C hat genauso Zeiger wie C++
was du vermutlich meinst sind Referenzen, die in deinem Beispiel ja auch
überhaupt nicht benutzt werden, sondern schlichtes call-by-value ...
Also übergebe ich char bzw. Arrays immer ohne Adressoperator? Und was
ist mit dem Adressoperator bei meinem Beispiel mit der Schriftart? Ist
doch auch ein string.
In C *genau wie in C++* werden Arrays grundsätzlich als Pointer
übergeben, daher ist der Adressoperator dort überflüssig und darf dort
nicht verwendet werden. Bei deinem "&Arial_11x18" - Beispiel, wenn
Arial_11x18 ein char* ist, übergibst du die Adresse der Adresse, also
einen Doppelpointer (char**).
Das muss ich mir nachher noch einmal genauer anschauen.
Eikne Frage noch.
Struct adres
{
};
Ist eine Struktur vom Datentyp adres. enn ich bei einer Funktion eine
Struktur als Ruckgabewert habe, warum wird das dan so geschrieben:
Struct adres *ptr_Adresse ()
{
}
Ich dachte immer, dass der Ruckgabetyp dem Datentyp entsprechen muss und
mein Datentyp ist adres, warum wird aber überall struct vor der Funktion
gesetzt, wenn doch adres der Datentyp ist?
Wenn ich beispielsweise Klassen als Parameter übergebe, gebe ich auch
nur den Klassentyp und en Namen der Klasse z.B. Funktion(myklass
Klasse1) ohne das class davor. Danke
Michael schrieb:> warum wird aber überall struct vor der Funktion> gesetzt, wenn doch adres der Datentyp ist?
weil in c der Datentype nunmal ein "struct xx" ist. Erst bei späteren
Versionen (C99??) oder C++ darf man das struct weglassen.
Peter II schrieb:> weil es C ist, und Arrays(strings) immer also Zeiger übergeben werden.
Man könnte auch die Adresse auf das erste Element übergeben.
Macht zwar keiner, aber vllt. trägt es zum Verständnis bei.
1
&myArray[0]
Peter II schrieb:> Versionen (C99??) oder C++ darf man das struct weglassen.
Oder über typedef:
Hallo nochmal,
hier das Beispiel mit den Pointern:
Funktion: void UB_Font_DrawString(uint16_t x, uint16_t y,char *ptr,
UB_Font *font, uint16_t vg, uint16_t bg)
{...}
und hier der Aufruf mit Adressoperator:
UB_Font_DrawString(10,70,"Pressed
",&Arial_11x18,RGB_COL_BLACK,RGB_COL_GREEN);
UNd hier das zweite Beispiel:
UB_Font_DrawString(10,300,buf,&Arial_11x18,RGB_COL_BLACK,RGB_COL_GREEN);
Warum verwende ich bei meinem char-Array buf kein Adressoperator, aber
bei Arial_11x18 schon?
Stimmt, deswegen wurde auch oben gesagt, dass wenn Arial_11x18 ein char
Array wäre, ich dann eine Adresse der Adresse übergeben wurde. Da es
aber kein char Datentyp ist, passt das. Besten Dank.
Michael schrieb:> Da es aber kein char Datentyp ist,
Nochmal lesen. Weil es KEIN ARRAY ist; mit "char" hat das NICHTS zu tun.
Bei einem "int" array müsstest du auch kein '&' eingeben.
Michael schrieb:> Als C++ Programmierer hab ich da aber ein Problem.
Mehr als Hello World kannst du da aber auch nicht programmiert haben...
Also ich denke schon, dass ich richtig liege. Bei einer Struktur wie
oben übergebe ich die Adresse. Bei einem char entfällt das und ich
benötige keinen Adressoperator ...
Michael schrieb:> Also ich denke schon, dass ich richtig liege.
Bitte, wenn du das denkst. Der C++ Standard denkt aber anders.
> Bei einer Struktur wie> oben übergebe ich die Adresse.
Ja.
> Bei einem char entfällt das und ich> benötige keinen Adressoperator ...
Nein, s.o.
Sorry, falsch ausgedrückt. char ist zwar ein Array, aber würde auch für
einen anderen Datentyp gälten. Ok betrifft Array und nicht char. Habe es
verstanden :-)
Bei mir handelt es sich m char[30], also ein Array. Bin bei Strukturen
sowieso etwas verwirrt. Derzeit ist mir auch nicht klar, weshalb in der
lib, auf die ich zugreife, typdef verwendet wird. Ob ich einen neuen
DatentypBezeichner definiere oder nicht, ich spare mir in _ doch
hoechstens das struct vor der Erzeugung einer Instanz.
Michael schrieb:> Derzeit ist mir auch nicht klar, weshalb in der> lib, auf die ich zugreife, typdef verwendet wird
die Library (und Seite) ist von mir und wie schon geschrieben schau
einfach in ein C-Buch, da stehen so sachen drinn
1
// das hier erzeugt nur eine Struktur :
2
structs1{
3
chara;
4
};
5
6
// zum benutzen muss eine Variable deklariert werden (mit struct)
7
structs1v1;
8
9
// der Zugriff erfolgt dann per
10
v1.a=5;
dann gibt es noch eine verkürzte Schreibweise :
1
// das erzeugt eine Struktur und legt gleich noch eine Variable davon an
2
structs1{
3
chara;
4
}v1;
5
6
// der Zugriff erfolgt dann per
7
v1.a=5;
und ich verwende in meinen Beispielen wieder was anderes :
1
// das hier erzeugt nur eine Struktur :
2
typedefstructs1{
3
chara;
4
}s1;
5
6
// zum benutzen muss eine Variable deklariert werden (ohne struct !!)
Uwe B. schrieb:> ...ich sollte doch noch ein Buch schreiben :-)
Wir brauchen hier lediglich eine Forum-Funktionalität in der man auf
Knopfdruck den Text zu einem Standardproblem schreibt...
Anfangsvorschläge:
* Compiler&Linker Optionen in eclipse & CoIDE eingeben
* typedef struct
* float ohne FPU
* Programmer tut nicht
etc.
Bücher in denen das alles steht gibts ja schon zuhauf, aber diese Fragen
kommen trotzdem alle 2 Tage...
Ok, danke für den Hinweis. Zum Thema Adressen und char nochmal: char ist
ja nicht ARRAY, wie vorher diskutiert wurde. Aber irgendwie ist doch
jeder char ab 1 Zeichen doch ein Array oder nicht?
ftk (char *ptr) wartet auf einen Zeichensatz, in dem Fall beispielsweise
"ERROR", Hier verwende ich ja keinen Adressoperator, genau wie bei allen
anderen Strings ja auch. Oder bin ich jetzt total falsch?
Ich habe Bücher, aber bin verwirrt.
Bei void Funktion(int *ptr) übergebe ich die Adresse einer Variable mit
&.
Bei voi Funktion (char *ptr) mache ich das ohne Adressoperator.
Aber weiter oben wurde gesagt, dass es allgemein für Arrays gilt, dass
da kein Adressoperator vorangestellt wird. Aber void Funktion (int
*ptr[2]) habe ich auch noch nicht gesehen. ???
Daher nehme ich es einfach mal so hin, dass ich Arrays, egal ob char
oder int oder sonstige ohne Adressoperator übergebe.
Habe es dann so abgeändert:
1
voidFunktion(int*ptr)
2
{
3
cout<<*ptr<<endl;
4
cout<<ptr[1]<<endl;
5
6
};
7
8
9
intmain()
10
11
{
12
intPunkte[2];
13
14
Punkte[0]=100;
15
Punkte[1]=200;
16
17
Funktion(Punkte);
18
19
system("PAUSE");
20
return0;
21
}
Versuche mir das jetzt einfach zu merken. Ich denke mal, dass ich bei
ptr[1] keinen "*"-Operator benbötige, da ich hier ja durch den Index die
Zahl an der Adresse bereits anspreche.
Arrays werden immer per Call by reference an Funktionen übergeben und
die Angaben zur Grösse kannst du in der Parameterliste weglassen, da
eine Anfangsadresse existiert und über diese alle Elemente erreicht
werden können. Schau mal bei Google nach openbook C Galileo. Dort kannst
die alles nachlesen.
Ok, aber wichtig ist, dass in meiner Parameterliste entweder int *ptr
oder int ptr[] steht.
Also wenn ich ein Array an eine Funktion übergebe mit
Funktion(MeinArray) muss ich als Parameter void Funktion(int DasArray[])
oder aber int *DasArray angeben? Adressoperator brauche ich hier also
nicht dafür aber muss ich angeben, dass es ein Zeiger sein soll, der auf
Anfangsadresse des Arrays zeigt?!
Michael schrieb:> Ok, aber wichtig ist, dass in meiner Parameterliste entweder int *ptr> oder int ptr[] steht.
Kommt drauf an, was du jetzt mit wichtig meinst.
Wenn du denkst, dass es einen Unterschied macht, ob du die Form "int
*ptr" benutzt, oder doch lieber "int ptr[]", dann hast du dich
geschnitten. Beides sind nur 2 verschiedene Schreibweisen für dasselbe.
> Also wenn ich ein Array an eine Funktion übergebe mit> Funktion(MeinArray) muss ich als Parameter void Funktion(int DasArray[])> oder aber int *DasArray angeben?
Wie oft denn noch?
Ja. Denn Arrays werden immer an eine Funktion übergeben, in dem die
Startsdresse des Arrays übergeben wird. Also muss es eine Pointer
Variable geben, die in der Funktion dann diese Adresse aufnimmt.
> Adressoperator brauche ich hier also> nicht
Nein.
Der ist bei Arrays implizit. Wird der Name eines Arrays benutzt, ohne
Indexoperation, dann ist damit automatisch immer die Startadresse des
Arrays gemeint.
Und das gilt nur und ausschliesslich für Arrays und für sonst nichts
anderes.
Michael schrieb:> Versuche mir das jetzt einfach zu merken. Ich denke mal, dass ich bei> ptr[1] keinen "*"-Operator benbötige, da ich hier ja durch den Index die> Zahl an der Adresse bereits anspreche.
Auch auf die Gefahr hin, dich jetzt noch mehr zu verwirren:
Der Indexoperator ist in C so definiert.
1
a[i] ist equivalent zu *(a + i)
In der Indexoperation steckt also der Dereferenzier-* automatisch mit
drinnen. Array Indizierung ist in C (und nicht nur dort) in Form von
Pointer-Arithmetik definiert.
> Also wenn ich ein Array an eine Funktion übergebe ...
Wenn man es ganz streng sieht, dann wird ein Array eigentlich überhaupt
nicht an eine Funktion übergeben.
Du kannst einen int übergeben
1
voidfoo(inta)
2
{
3
a=8;
4
}
5
6
intmain()
7
{
8
intb=5;
9
10
foo(b);
11
}
Hier wird beim Funktionsaufruf, der Wert von b genommen und an die
Funktion übergeben. Dieser Wert wird innerhalb der Funktion an die
dortige lokale Variable a gebunden. a hat also nach dem Betreten der
Funktion ebenfalls den Wert 5, weil dieser Wert an die Funktion
übergeben wurde. Aber ansonsten haben das a in der Funktion und das b in
main() nichts mehr miteinander zu tun. Die Funktion hat eine Kopie des
Wertes erhalten.
Und genau dieses, das Übergeben von Werten geht bei Arrays nicht. Und
zwar nur bei Arrays. Arrays können nicht so übergeben werden.
Was man statt dessen macht ist, dass man der Funktion die Startadresse
des Arrays übergibt
1
voidfoo(int*werte)
2
{
3
werte[0]=8;
4
werte[1]=9;
5
}
6
7
intmain()
8
{
9
intnummern[2]={1,2};
10
11
foo(nummern);
12
}
da 'nummern' ein Array ist, und hier der Name des Arrays alleine
vorkommt (also ohne Indexoperation), ist durch die Nennung des Array
Namens automatisch die Startadresse des Arrays gemeint. Und genau diese
Startadresse wird an die Funktion übergeben. Die Funktion fängt diese
Startadresse in einem dafür geeignetem Datentyp auf, eben einer Pointer
Variablen.
Der wesentliche Punkt an dieser Stelle ist aber, das die Funktion somit
Zugriff auf das Array des Aufrufers hat. Die Funktion hat NICHT wie oben
eine eigene lokale Kopie der Werte, sondern sie benutzt das Array des
Aufrufers. Ein Beschreiben über die lokale Pointer-Variable 'werte',
verändert die Inhalte von 'nummern' beim Aufrufer.
Im ersten Beispiel war die Sache so
1
main
2
3
b
4
+------+
5
| 5 |
6
+------+
7
8
Funktionsaufruf, die Variable a wird erzeugt
9
10
a
11
+-------+
12
| |
13
+-------+
14
15
und dieser Variablen wird eine Kopie des Wertes
16
zugewiesen.
17
18
a
19
+-------+
20
5 .......................> | 5 |
21
+-------+
22
23
Während die Funktion läuft, existieren 2 Variablen,
24
jede vom Typ int, die voneiander vollkommen unabhängig sind
25
26
27
b
28
+-------+ a
29
| 5 | +--------+
30
+-------+ | 5 |
31
+--------+
32
33
wird a verändert, dann wirkt das nur auf a und auf sonst nichts
34
a = 8;
35
36
b
37
+-------+ a
38
| 5 | +--------+
39
+-------+ | 8 |
40
+--------+
etwas anders ist der Array-Fall. Denn Arrays werden nicht übergeben.
Ihre Startadresse wird übergeben
1
Wieder beginnt die Sache mit den Variablen in main. Diesmal aber mit einem Array
2
3
main
4
5
nummern
6
+-------+
7
| 8 |
8
+-------+
9
| 9 |
10
+-------+
11
12
Im Zuge des Funktionsaufrufs wird in der Funktion die Variable werte erzeugt.
13
14
werte
15
+--------+
16
| |
17
+--------+
18
19
Diese ist aber ein Pointer ... sie muss ein Pointer sein, denn Arrays
20
werden ja nicht übergeben, indem die Inhalte des Arrays übergeben werden,
21
sondern in dem die Startadresse des Arrays übergeben wird. Nachdem diese
22
Startadresse in werte abgelegt wurde, sieht die Sache also so aus
23
24
werte
25
+--------+
26
+----------------------------------------o |
27
| +--------+
28
|
29
| nummern
30
| +-------+
31
+->| 8 |
32
+-------+
33
| 9 |
34
+-------+
35
36
werte ist zu einem Zeiger geworden, der auf die originalen Inhalte in
37
main() durchzeigt. Würde über 'werte' etwas verändert, sei es über
38
39
werte[0] = 1
40
41
werte
42
+--------+
43
+----------------------------------------o |
44
| +--------+
45
|
46
| nummern
47
| +-------+
48
+->| 1 |
49
+-------+
50
| 9 |
51
+-------+
52
53
oder sei es über explizite Pointer-Syntax
54
55
*( werte + 1 ) = 2;
56
57
werte
58
+--------+
59
+----------------------------------------o |
60
| +--------+
61
|
62
| nummern
63
| +-------+
64
+->| 1 |
65
+-------+
66
| 2 |
67
+-------+
68
69
dann wird diese Änderung im original Array des Aufrufers gemacht. Aber zu
70
keinem Zeitpunkt ist jemals eine Kopie des originalen Arrays des Aufrufers
71
gemacht worden.
das unterscheidet Arrays von allen anderen Datentypen in C. Und dieser
Unterschied gilt nur für Arrays und sonst nichts anderes. Alle anderen
Dinge, seien es Strukturen, seien es Unions, seien es die primtiven
Datentypen wie int, float, char, long, .... werden genau wie das erste
Beispiel in diesem Post behandelt: Beim Aufruf wird eine Kopie des
Inhaltes gemacht und diese Kopie wird an eine frisch erzeugte Variable
innerhalb der Funktion gebunden. Nur bei Arrays gibt es diesen
Mechanismus nicht. Dort muss man immer über den Mechanismus der Übergabe
der Adresse und einer funktionslokalen Pointer-Variablen gehen. Genauso
wie man es mit den restlichen Datentypen auch machen muss, wenn man der
Funktion den Zugriff auf die originale Variable beim Aufrufer
ermöglichen will, so dass die Funktion nicht mit einer Kopie arbeitet,
sondern die Variable des Aufrufers ändern kann
1
voidfoo(int*a)
2
{
3
*a=8;
4
}
5
6
intmain()
7
{
8
intk=7;
9
10
foo(&k);
11
}
1
main
2
k
3
+-------+
4
| 7 |
5
+-------+
6
7
Funktionsaufruf: foo( &k );
8
9
a
10
+-------+
11
+-------------------------------------o |
12
| +-------+
13
|
14
| k
15
| +------+
16
+->| 7 |
17
+------+
18
19
Zuweisung: *a = 8;
20
21
a
22
+-------+
23
+-------------------------------------o |
24
| +-------+
25
|
26
| k
27
| +------+
28
+->| 8 |
29
+------+
und ehe die Frage kommt:
Nein, die Funktion kann für sich alleine nicht entscheiden oder
feststellen, ob die Adresse die sie bekommt jetzt auf ein Array zeigt
oder auf eine einzelne Variable. Das ist schlicht und ergreifend der
Funktion nicht möglich und es obliegt einzig und allein deiner Sorgfalt,
dass hier nichts schief geht.
Vielen Dank für die ausführliche Antwort. Mittlerweile hat es auch bei
mir "Klick" gemacht :) An sich mag das Thema vielleicht nicht so
schwierig sein, aber manche brauchen eben dann doch länger :)