Forum: Mikrocontroller und Digitale Elektronik Pointer incrementieren schlägt fehl?!


von Jan H. (janiiix3)


Lesenswert?

Hallo.

Auf nem MEGA32 klappt es, nur auf dem Rechner nicht. Es wird nichts 
angezeigt. Wieso?
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <string.h>
4
5
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
6
7
8
9
void ausgabe(char *str){
10
  
11
  int x = 0;
12
  
13
  *str++ = 'A';
14
  *str++ = 'B';
15
  *str++ = 'C';
16
  
17
  //str[x++] = 'A';
18
  //str[x++] = 'B';
19
  //str[x++] = 'C';
20
  
21
  printf(str);
22
}
23
24
25
int main(int argc, char *argv[]) 
26
{
27
  char *buff = (char*)calloc(11,sizeof(char));
28
  ausgabe(buff);
29
30
  return 0;
31
}

von Peter II (Gast)


Lesenswert?

Jan H. schrieb:
> printf(str);

überlege doch mal wo der Zeiger str nach deinen str++ steht?

von Tom (Gast)


Lesenswert?

Jan H. schrieb:
> *str++ = 'C';

Tip: Wohin zeigt str nach dieser Zeile?

von Adam P. (adamap)


Lesenswert?

Für printf und andere String-Fkt. würde ich einen String auch imemr mit 
'\0' abschliessen.

Würde mich wundern wenn genau der Source aufm µC läuft.
FEHLER beim Copy&Paste ? ;-)

Versuch das:
1
void ausgabe(char *str){
2
  
3
  char *tmp = str;
4
5
  *tmp++ = 'A';
6
  *tmp++ = 'B';
7
  *tmp++ = 'C';
8
  *tmp   = '\0';
9
 
10
  printf(str);
11
}

: Bearbeitet durch User
von Sinus T. (micha_micha)


Lesenswert?

Denk daran, dass ein String mit /0 abgeschlossen werden muss

von Adam P. (adamap)


Lesenswert?

P.S. Entschuldigt bitte, dass ich jetzt den "Ratespaß" vermiest habe :)

von Peter II (Gast)


Lesenswert?

Adam P. schrieb:
> Für printf und andere String-Fkt. würde ich einen String auch imemr mit
> '\0' abschliessen.

hat doch

> calloc

Sinus T. schrieb:
> Denk daran, dass ein String mit /0 abgeschlossen werden muss

hat er

von Jan H. (janiiix3)


Lesenswert?

Denkfehler. Habs gefunden!

von Reinhold (Gast)


Lesenswert?

Tipp am Rande: Bei der Inkrementierungs-Dereferenzierungs-Geschichte 
Klammern setzen. Dann ist auf Anhieb klar was deine Intention war und 
was der Code macht wenn man die C Operator Precedence gerade nicht parat 
hat ;)

von Adam P. (adamap)


Lesenswert?

Peter II schrieb:
> hat doch

Ja hast recht, hatte es übersehen.

von Tom (Gast)


Lesenswert?

Mit dem Verändern von Parametern innerhalb einer Funktion kann man sich 
wie man hier sieht sehr elegant und effizient selbst hereinlegen.
1
void ausgabe(char *str)
2
{
3
    char* write_cursor = str;
4
    *write_cursor++ = 'A';
5
    *write_cursor++ = 'B';
6
    *write_cursor++ = 'C';
7
     
8
    printf(write_cursor);
9
}
In dieser Version wäre der Fehler offensichtlich gewesen. 'str' ist im 
Hinterkopf als "der String, in den ich schreibe" abgelegt. Wenn man den 
String am Ende der Funktion ausgeben will, liegt 'printf(str)' nahe; 
dass man 'str' vorher verändert hat, hat man an der Stelle leicht schon 
wieder vergessen.

von Peter II (Gast)


Lesenswert?

Adam P. schrieb:
> printf(str);

oder ganz böse
1
printf(str-3);

von Adam P. (adamap)


Lesenswert?

Tom schrieb:
> In dieser Version wäre der Fehler offensichtlich gewesen.

Aber wer nutzt ein temp. Arbeitszeiger um etwas zu verändern und 
übergibt printf dann nicht das Original?

Peter II schrieb:
> Adam P. schrieb:
>> printf(str);
>
> oder ganz böse
> printf(str-3);

:-D  Ja, wer drauf steht!

von Adam P. (adamap)


Lesenswert?

Jan,
du kannst es aber auch so machen:
1
void ausgabe(char *str)
2
{
3
  str[0] = 'A';
4
  str[1] = 'B';
5
  str[2] = 'C';
6
 
7
  printf(str);
8
}

...gibt 1000 Wege.


edit:
Ah, so hattest du es wohl schon mal - jedoch auskommentiert. OK.

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

Jan H. schrieb:
> char *buff = (char*)calloc(11,sizeof(char));

sizeof(char) ist per Definition immer 1. Du kannst also einfach 
calloc(11,1) oder noch einfacher malloc(11) schreiben. Der Grund ist, 
dass sizeof die Größe des Typs als Vielfache von der Größe von "char" 
zurückgibt, und "char" ist nunmal genau 1 char groß, also ist es immer 
1. (Siehe z.B. http://en.cppreference.com/w/c/language/sizeof )

Der Cast nach char* ist übrigens in C nicht nötig, nur in C++ - aber da 
würde man onehin lieber "new" nutzen.

von Peter II (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Der Cast nach char* ist übrigens in C nicht nötig, nur in C++ - aber da
> würde man onehin lieber "new" nutzen.

bei new müsst man aber wieder die 0 reinschreiben.

von Dr. Sommer (Gast)


Lesenswert?

Peter II schrieb:
> bei new müsst man aber wieder die 0 reinschreiben.
Welche 0? Ich hätte jetzt so gesagt in C++:
1
char *buff = new char [11];
Und eben in C:
1
char* buff = malloc (11);

von Peter II (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Welche 0? Ich hätte jetzt so gesagt in C++:

er hat aber calloc verwenden das initialisiert den Speicher mit 0, das 
macht new und malloc nicht.

von Jan H. (janiiix3)


Lesenswert?

Habe das gerade mal ausprobiert.
Da stürzt die .exe ab.
1
void ausgabe(char *str)
2
{
3
    char* write_cursor = str;
4
    *write_cursor++ = 'A';
5
    *write_cursor++ = 'B';
6
    *write_cursor++ = 'C';
7
     
8
    printf(write_cursor);
9
}
10
11
int main(int argc, char *argv[]) {
12
  
13
  ausgabe("WIRD EH NICHT BENUTZT^^");
14
  
15
  return 0;
16
}

von Adam P. (adamap)


Lesenswert?

Peter II schrieb:
> das
> macht new und malloc nicht.

wie ist es mit:
1
char *buf = new char[11]();

...das macht ein Zero-Memory.

von Adam P. (adamap)


Lesenswert?

Jan H. schrieb:
> Habe das gerade mal ausprobiert.
> Da stürzt die .exe ab.

War das jetz nur aus Neugier?

von Peter II (Gast)


Lesenswert?

Jan H. schrieb:
> Habe das gerade mal ausprobiert.
> Da stürzt die .exe ab.

ja, weil du versucht einen kontante, die im nicht schreibbaren Speicher 
steht zu überschreiben. Das würde auf einen µC funktionieren, auf den 
meisten PCs nicht mehr.

von Jan H. (janiiix3)


Lesenswert?

Peter II schrieb:
> Jan H. schrieb:
>> Habe das gerade mal ausprobiert.
>> Da stürzt die .exe ab.
>
> ja, weil du versucht einen kontante, die im nicht schreibbaren Speicher
> steht zu überschreiben. Das würde auf einen µC funktionieren, auf den
> meisten PCs nicht mehr.

Wenn ich jetzt mit calloc(), den Speicher "freigebe", klappt es!

von Peter II (Gast)


Lesenswert?

Jan H. schrieb:
> Wenn ich jetzt mit calloc(), den Speicher "freigebe", klappt es!

mit calloc kann man keinen Speicher freigeben. Keine Ahnung was du 
gemacht hast und was dann klappt.

von Sebastian S. (amateur)


Lesenswert?

Es ist doch immer wieder Interessant, wie viele Fehler man in so wenig 
Zeilen machen kann.

Interessant ist auch, dass das ganze auf 'nem Mega32 geklappt haben 
soll.


Da war doch irgendwo eine uralte Schwarte mit den Grundlagen zu "C".

Oder kann es sein, dass man so etwas heute nicht mehr braucht?

Also ich würde sagen man kann den Ansatz: "Learning by doing" auch 
übertreiben.

von Johnny B. (johnnyb)


Lesenswert?

Adam P. schrieb:
> Versuch das:
>
>
1
> void ausgabe(char *str){
2
> 
3
>   char *tmp = str;
4
> 
5
>   *tmp++ = 'A';
6
>   *tmp++ = 'B';
7
>   *tmp++ = 'C';
8
>   *tmp   = '\0';
9
> 
10
>   printf(str);
11
> }
12
>

In der Praxis würde ich jeweils noch die Länge des reservierten 
Speichers für die Zeichenkette mitgeben und beachten. Ansonsten kann es 
bei späteren Anpassungen und Unachtsamkeit durch einen selbst oder 
andere Entwickler schnell mal passieren, dass man über den reservierten 
Speicher hinaus schreibt und es dann zu nicht gewolltem Verhalten führen 
kann, welches nur sehr mühsam aufzuspüren ist.

von xxx (Gast)


Lesenswert?

Jan H. schrieb:
> *str++ = 'A';

Wie ist denn da die Reihenfolge?
Zuerst pointer erhöhen (str++) dann dereferenzieren (*(str++)) und dann 
'A' zuweisen? Dann würde aber an der ersten übergebenen Adresse nichts 
stehen.

von Adam P. (adamap)


Lesenswert?

Johnny B. schrieb:
> In der Praxis würde ich...

Ich habe lediglich seine "fehlerhafte" Fkt. korrigiert, selbst würde ich 
so nicht programmieren.

edit:
Die Fkt. ist ansich schon "sinnfrei", wenn eine Fkt. "ausgabe" heißt, 
dann soll deren Aufgabe die Ausgabe sein und nicht String-Manipulation 
:-D

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

xxx schrieb:
> Wie ist denn da die Reihenfolge?
> Zuerst pointer erhöhen (str++) dann dereferenzieren (*(str++)) und dann

nein.

str++ ist post Inkrement also nach dem ;

von S. R. (svenska)


Lesenswert?

xxx schrieb:
> Jan H. schrieb:
>> *str++ = 'A';
>
> Wie ist denn da die Reihenfolge?

Sinnvoll: Schreibe ein 'A' an *str, dann incrementiere str.

von (prx) A. K. (prx)


Lesenswert?

Reinhold schrieb:
> Tipp am Rande: Bei der Inkrementierungs-Dereferenzierungs-Geschichte
> Klammern setzen.

Der Ausdruck *str++ ist derart grundlegend für C, dass ich geradezu 
davon abraten würde, dort Klammern zu setzen. Sondern raten würde, zu 
verstehen, warum das so funktioniert.

An dieser Stelle Klammern zu setzen sorgt eher für Erheiterung 
erfahreneren Publikums als für Verständnis beim Lesen.

Es gibt gute Gründe dafür, solche Seiteneffekt-Operationen abzulehnen, 
unbeschadet des intuitiven oder unintuitiven Vorrangs der Operatoren. 
Aber dann richtig. Also
  *str = 'A'; str += 1;
  *str = 'B'; str += 1;
um Diskussionen zu vermeiden, was bei
  *str++ = *str++ = *str++ = 0;
alles rauskommen kann. ;-)

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Reinhold schrieb:
> Tipp am Rande: Bei der Inkrementierungs-Dereferenzierungs-Geschichte
> Klammern setzen. Dann ist auf Anhieb klar was deine Intention war und
> was der Code macht wenn man die C Operator Precedence gerade nicht parat
> hat ;)

wir würdest du denn die Klammern setzen wollen?

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.