Forum: PC-Programmierung char und char*


von Boardgeist (Gast)


Lesenswert?

Hallo, ich versuch mich hier grad in ANSI C und habe eineen µC der mir 
einen String gibt. (Welchen er vorher empf. hat und zwischenspeichert, 
aber egal)

char *VarName ="String";   //Ist klar, baut nen String
char VarName2 = A;         //Ist ein einzelnes char

Die Fkt. RecvChar(*Ptr) gibt mir den char wieder
ich habe geschrieben RecvChar(A) und er sagt mir:
expected: 'signed char*' given 'int' .
ich habe es doch als char deklariert.

was bedeutet es, wenn der Pointer hinter dem char steht (char*)?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

1
char VarName2 = A;         //Ist ein einzelnes char

Mit Sicherheit nicht.
1
char VarName2 = 'A';         //Ist ein einzelnes char

dürfte besser funktionieren.

> Die Fkt. RecvChar(*Ptr) gibt mir den char wieder
> ich habe geschrieben RecvChar(A) und er sagt mir:
> expected: 'signed char*' given 'int' .
> ich habe es doch als char deklariert.

Die Funktion erwartet einen Pointer auf char (char*), bekommt von Dir 
aber eine int-Konstante geliefert. 'A' ist eine int-Konstante.

> was bedeutet es, wenn der Pointer hinter dem char steht (char*)?

Das Sternchen steht hinter dem Datentyp.
1
char* p;
2
char *q;
3
char * r;

ist dasselbe.

Literaturhinweis:
Kernighan&Ritchie, "Programmieren in C", zweite Auflage, Hanser-Verlag

von Uwe M. (lifthrasil)


Lesenswert?

Hallo Bordgeist,
also VarName2 müsstest du eigentlich so initialisieren:
1
char VarName2 = 'A'; bzw char VarName2 = 0x41; // 0x41 ASCII-Code für A
Das selbe glit auch für deine Funktion wenn sie so definiert ist.
1
void RecvChar(char* cWhatever){}
 (also mit 'A' bzw. 0x41). Willst du allerdings VarName2 übergeben 
müsste es so aussehn
1
RevcChar(&VarName2)
.

> was bedeutet es, wenn der Pointer hinter dem char steht (char*)?
... öhm soweit ich weiß steht der * immer hinter dem char was kein 
unterschied macht char* cBla bzw. char *cBla!

von Boardgeist (Gast)


Lesenswert?

Ja, gut. Hat geklappt. Habe es so gelöst:
AS1_RecvChar((signed char*)empf);

Danke euch.
MfG

von Karl H. (kbuchegg)


Lesenswert?

Boardgeist wrote:
> Ja, gut. Hat geklappt. Habe es so gelöst:
> AS1_RecvChar((signed char*)empf);
>

Die Wahrscheinlichkeit, dass du lediglich den Compiler
ruhiggestellt hast und nicht das Problem gelöst hast
ist höher als 80%.

Aber ohne mehr Code kann man das nicht genauer diagnostizieren.

von Board G. (boardgeist)


Lesenswert?

;)
Habe mich mittlerweile mal Angemeldet auf diesem Board hier, die 
Umgebung gefällt, es gibt nur wenig Leute die ihre Meinung mit Füßen 
vertreten und das nächste halbe Jahr bleib ich hier.

Du meinst bestimmt das mein Casting nicht die Elegante ist... und ja 
hast recht. Aber. Mein µC Erkennt die ihm zugesendeten Signale. Es 
klappt also, als ich gecastet hab, hab ich auch nicht dran geklaubt... 
aber hey :)

Wenn es mal Probs. an der Stelle gibt, denk ich an dich.
MfG

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Rufus t. Firefly wrote:

[...]
>> was bedeutet es, wenn der Pointer hinter dem char steht (char*)?
>
> Das Sternchen steht hinter dem Datentyp.

Hm, besser gesagt: es steht links vom Objekt.
Gern gemachter Fehler:
1
char* a, b, c, d;

a ist ein Pointer auf Typ char, b, c, und d sind vom typen char.
Der besseren Lesbarkeit halber:
1
char *a, *b, c, d;

a und b sind Pointer auf Typ char, c und d sind vom Typen char. Jetzt 
kann man das aber wesentlich besser erkennen ;-)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Das ist selbstverständlich richtig so, ich wollte nur den armen nicht 
gleich damit überfordern. Denn das ist ein Spezialfall der nur bei der 
Variablendeklaration auftritt.
Mir scheint, daß der "Boardgeist" noch mit viel grundlegenderen 
Problemen zu kämpfen hat:

> Du meinst bestimmt das mein Casting nicht die Elegante ist... und ja
> hast recht. Aber. Mein µC Erkennt die ihm zugesendeten Signale. Es
> klappt also, als ich gecastet hab, hab ich auch nicht dran geklaubt...
> aber hey :)

Einer Funktion, die einen Pointer auf char erwartet, wird ein zu einem 
Pointer gecasteter char übergeben. Und das soll also "klappen". O Weh.

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Allerdings!

Da wirkt der Cast wie Aspirin - die Kopfschmerzen verschwinden erst 'mal 
'ne Zeit lang...

von Karl H. (kbuchegg)


Lesenswert?

Fa Dam wrote:
>
> Du meinst bestimmt das mein Casting nicht die Elegante ist...

Das meine ich eigentlich nicht.
Es geht nicht um Eleganz. Es geht schlicht und ergreifend
darum, dass ein derartiger cast an dieser Stelle meist
einfach nur den Compiler ruhigstellt, also die Symptome
und nicht die Ursache bekämpft. Und die Ursache ist:
Die Funktion möchte (logisch gesehen) ganz was anderes
in der Schnittstelle haben als was der Aufrufer bereit ist
zu liefern.

> hast recht. Aber. Mein µC Erkennt die ihm zugesendeten Signale. Es
> klappt also,

Das heist nicht viel. Es gibt viele Fehlerszenarien, bei denen
es zuerst so aussieht als ob alles in Butter ist. Und dann,
nachdem noch ein paar Programmerweiterungen vorgenommen
werden, dann tauchen da plötzlich so seltsam anmutende
Fehler auf: Variablen verändern plötzlich ihren Wert, obwohl
sie in der gegenständlichen Aktion gar nicht beteilgt sind;
ein return aus einer Funktion kommt plötzlich nicht mehr
dorthin zurück, von wo der call herkam; ....

Aber wie gesagt:
Es ist möglich, dass das was du geschrieben hast durchaus
richtig ist (du hast ja die Deklaration von 'empf' nie
gezeigt, und auch das Innere der Funktion wäre interessant),
die Wahrscheinlichkeit spricht allerdings gegen dich.

von Board G. (boardgeist)


Lesenswert?

Achso, ja ich kämpfe ja grad mit soetwas.

Wie wäre denn die elegante? Die deklaration des char passiert ausserhalb 
main mit:
1
char *empf;

worauf dann dies Passiert:
1
if (AS1_GetCharsInRxBuf()>0) {AS1_RecvChar((signed char*)empf);
2
   
3
                     if (empf=(signed char*)'a')  
4
                     {AS1_SendBlock(resend,(word)21,sendblockcounter1); };
5
                                };

//Diese zeilen sollen mir durch das senden des Strings resend nur zeigen 
ob er ordentlich empfangen hat und auch genau das empfangen hat was ich 
gesendet habe. sende ich per HyperTerminal ein "a" hin kommt der 
"resend-string" zurück. was auch klappt.

Recv_Char tut im hintergrund dies, falls du es sehen willst.

Lerne dabei jetzt bestimmt was, habe pointer nie richtig verinnerlicht, 
nur mir gemerkt wie man Sie nutzt.
1
byte AS1_RecvChar(AS1_TComData *Chr)
2
{
3
  byte Result = ERR_OK;                /* Return error code */
4
5
  if(AS1_InpLen > 0) {                 /* Is number of received chars greater than 0? */
6
    EnterCritical();                   /* Save the PS register */
7
    AS1_InpLen--;                      /* Decrease number of received chars */
8
    *Chr = *(InpPtrR++);               /* Received char */
9
    if(InpPtrR >= (InpBuffer + AS1_INP_BUF_SIZE)) { /* Is the pointer out of the receive buffer? */
10
      InpPtrR = InpBuffer;             /* Set pointer to the first item into the receive buffer */
11
    }
12
    Result = (byte)((SerFlag & (OVERRUN_ERR|COMMON_ERR|FULL_RX))?ERR_COMMON:ERR_OK);
13
    SerFlag &= ~(OVERRUN_ERR|COMMON_ERR|FULL_RX|CHAR_IN_RX); /* Clear all errors in the status variable */
14
    ExitCritical();                    /* Restore the PS register */
15
  } else {
16
    return ERR_RXEMPTY;                /* Receiver is empty */
17
  }
18
  return Result;                       /* Return error code */
19
}

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Bitte die Code-Tags nutzen, sonst verwüstet das Forum die 'Indentation'.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Die deklaration des char passiert ausserhalb
> main mit:
1
char *empf;

Das deklariert einen Pointer auf char, nicht einen char. Wo zeigt der 
hin? Wenn "empf" nicht initialisiert wird, zeigt dieser Pointer ins 
Nirvana, und bei Zugriffen auf diesen Pointer wird dieses Nirvana 
überschrieben/ausgelesen.

Das ist mit Sicherheit nicht das, was bezweckt wird.

Die hier aufgelistete Funktion
1
byte AS1_RecvChar(AS1_TComData *Chr)

erwartet keinen Pointer auf char. Sondern einen Pointer auf einen 
anderen Datentyp namens "AS1_TComData".

Wie ist der deklariert?

Zurück zum eigentlichen Thema:

Angenommen, es gebe eine Funktion
1
int Receive(char *p);

die einen Statuscode als int zurückliefert und ein Zeichen in p, dann 
muss diese Funktion wie folgt aufgerufen werden:
1
char c;
2
int status;
3
4
status = Receive(&c);

Hier wird der Funktion die Adresse der char-Variablen c übergeben, und 
das ist nichts anderes als ein Pointer.

Alternativ (und unnötig) wäre auch
1
char c;
2
char *p;
3
int status;
4
5
p = &c;
6
status = Receive(p);

möglich, da wird vor dem Aufruf die Adresse von c in p geschrieben und 
die wiederum an Receive übergeben.

DRINGENDER! Literaturhinweis:

Kernighan & Ritchie, "Programmieren in C", zweite Auflage, 
Hanser-Verlag.

von Karl H. (kbuchegg)


Lesenswert?

> Lerne dabei jetzt bestimmt was, habe pointer nie richtig
> verinnerlicht,

Das ist im Grunde ganz simpel. Nur machen die meisten Neulinge
ein Drama draus.

Ein Pointer ist eine Variable, deren Inhalt eine Adresse
im Speicher darstellt. So wie ein int eine Zahl speichert,
so speichert ein Pointer eine Speicheradresse, wo die eigentlichen
Daten abgelegt sind.

Verkompliziert wird das Ganze durch den Sprachgebrauch:
Der Begriff Pointer wird oft für 2 Dinge gleichzeitig
benutzt.
* Zum einen für eine Variable, die eine Adresse speichert.
  Wir sagen:
     int * pPtr;
  pPtr ist ein Pointer.
* Zum anderen für die Adresse selbst.
  Wir sagen
     &i
  liefert einen Pointer auf i.

Wenn man aber strikt zwischen Pointer (im Sinne einer
Variablen, die eine Adresse speichert) und dem Begriff
"Adresse" unterscheidet wird alles ganz einfach.

void foo( char* i )

Diese Funktion erwartet eine Speicheradresse. Bei Aufruf
der Funktion wird diese übergebene Speicheradresse in
einem Pointer (einer Pointervariablen) gespeichert und dieser
Pointer heist i.

Das ist nichts anderes, als bei

void bar( int j )

Diese Funktion erwartet eine Zahl. Bei Aufruf der Funktion
wird diese übergebene Zahl in einer Variablen gespeichert
und diese Variable heist j.

Nun möchte die Funktion foo aber auch etwas mit dieser
in i gespeicherten Speicheradresse machen. Zb. möchte
sie in der Speicherzelle, die durch diese Adresse beschrieben
ist, etwas ablegen. Dazu benötigt man eine Möglichkeit
zu sagen: Wenn ich i sage, meine ich nicht die in i gespeicherte
Adresse, sondern die Speicherzelle die durch diese Adresse
beschrieben wird. Gemeinhin bezeichnet man das als "dereferenzieren"
und schreibt es in C durch einen '*'

  *i = 5;

Der Stern sort also dafür, dass die 5 nicht in i gespeichert
werden, sondern an der Speicherstelle, deren Adresse in i
abgelegt ist.

  andere_Variable = *i;

Die Umkehrung dazu. Hier sorgt der Stern dafür, dass nicht der
Inhalt von i (also die Speicheradresse) ausgelesen und an
andere_Variable zugewiesen wird, sondern dass der Inhalt von
i, also die Speicheradresse, benutzt wird um einen Wert aus
dem Speicher und zwar genau von jener Speicheradresse auszulesen.

Soweit so gut.
Wie ist die Situation beim Aufrufer?
Die Funktion war ja:
void foo( char* i)

Für den Aufrufer bedeutet das: Die Funktion möchte eine
Speicheradresse haben. Nun muss man unterscheiden:
Was macht den dir Funktion mit dieser Speicheradresse?
Im gegenständlichen Fall benutzt die Funktion diese
Speicheradresse um an eben genau dieser Stelle im Speicher
etwas abzulegen. Also sollte man besser dafür sorgen, dass
die übergebene Adresse auch tatsächlich die Adresse einer
Speicherzelle ist, an der ein char abgelegt werden kann.

Wenn man eine char Variable hat:
  char a;
dann bekommt man mittels & die Adresse dieser Variablen.

Genau das was hier benötigt wird!

  int main()
  {
     char a;

     foo( &a );
  }

foo erwartet die Adresse einer Speicherzelle in der ein
char abgelegt werden kann. Es gibt eine derartige Speicherzelle,
ihr Name ist a, und &a liefert die Adresse dieser Speicherzelle
namens a. Genau das was foo haben möchte.

  int main()
  {
    char* b;

    foo( b );
  }

Syntaktisch ist das völlig korrekt. Aber: b ist eine Pointer-
variable, also eine Variable die eine Speicheradresse enthält.
Nur: Was ist diese Speicheradresse? Welchen Zahlenwert hat sie?
Oder etwas mehr in Computersprache: Wo zeigt b den hin?
Niemand weis es. Niemand hat es je festgelegt. Die Speicheradresse
in b ist irgendeine Adresse. Wird diese Adresse an foo übergeben,
so benutzt foo diese Adresse selbstverständlich um über diese
Adresse einen Wert abzuspeichern. Nur: Da keiner weiss, welche
Adresse in b war, weiss auch niemand wo dieser Wert hingespeichert
wurde. Wenn du Pech hast, dann ist der Wert in b zufällig der
Wert einer ansonsten nicht benutzten Speicherzelle. Wenn du
Glück hast, dann ist diese Adresse die Adresse von irgendetwas
lebenswichtigem in deinem Programm und das Programm stürzt
sofort ab.

Ansonsten kann ich mich nur Rufus anschliessen:
Literatur besorgen und lesen. Ich kann hier die Grundlagen
nur in aller Kürze anreissen.

von Karl H. (kbuchegg)


Lesenswert?

Noch was:
Wenn du in deinem jetzigen Programmierstadium im
Zusammenhang mit Pointern rumcasten musst, dann
bist du mit nahezu 100% Sicherheit unter den weiter
oben angesprochenen 80%, die durch den cast einen
Fehler nur kaschieren aber nicht beheben.

Du solltest dir merken: Ein Cast ist eine Waffe.
Effektiv schaltet er das Typ-System des Compilers
ab und teilt dem Compiler mit: "Mir ist völlig
egal, ob du denkst dass die Datentypen hier nicht
zusammenpassen. Ich bin der Programmierer und du
compilierst das gefälligst; bevor ich dir das Gas
abdrehe, denn ich weiss schon was ich tue".

Nur sollte man dann auch tatsächlich wissen,
was man tut.

von Boardgeist (Gast)


Lesenswert?

Toll, wenn man sich den Quelltext oben anschaut, habe ich zugewiesen und 
nicht verglichen.
Das er mir antwortete, heißt also nur das etwas im Buffer ankommt, 
nachdem ich daraus einen Vergleich gemacht habe, antwortet er nicht 
mehr.
Was bedeutet, er identifitziert die chars nicht, hm.. mal schaun.

von Boardgeist (Gast)


Lesenswert?

Ja, naja, was soll ich sagen... Kalle hat recht :P
Ein &empf und ja, da hat mir der Compiler gleich die blöden castings 
angemerkert und als die auch raus waren, gings.... .

Toll, thx Karl Heinz.

von arc (Gast)


Lesenswert?

Falls if (empf=(signed char*)'a') gemeint ist, wäre auch die Version mit 
== falsch!
empf ist ein Zeiger, 'a' ein Zeichenliteral das zu einem Zeiger gecastet 
wird.
Der Vergleich wird somit als 0 == 97 ausgeführt. Das mit 0 bzw. dem 
Null-Zeiger verglichen wird, liegt daran, daß der C-Standard 
vorschreibt, daß "globale" (static storage) Variablen vor dem Aufruf von 
main initialisiert sein müssen und zwar entweder mit den Werten die man 
selbst vorgibt, oder, falls dies nicht geschieht, mit 0.
1
AS1_TComData empf;
2
3
if (AS1_GetCharsInRxBuf() > 0) {
4
    AS1_RecvChar(&empf);
5
    if (empf == (AS1_TComData)'a') {

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.