mikrocontroller.net

Forum: PC-Programmierung C-Programmierung - Such Aufgaben zu Post und Prefix!


Autor: Hans Wurst (wursthans)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Leute!

Ich suche schwierige Aufgaben zum selbst "durchrechnen", also ohne 
Compiler/Debugger der Form von sowas hier:


int x = 11, y = 20, w = 3;

y = --w*10;
x -= ++y/7+4;



Habt ihr da ein paar Aufgaben für mich? Ich weiß, dass das jetzt 
durchaus blöd klingt, aber da ich das grad am Lernen bin und mein Buch 
dazu leider keine Übungsaufgaben ausspuckt hab ich keine Ideen wo ich 
das jetzt herbekomme. Natürlich kann ich mir selber Aufgaben stricken, 
aber das bringt mir nix, denn die Aufgaben sind dann nur so schwer so 
weit eben mein "Horizont" reicht. Aber: Wenn jemand mehr kann als das 
was ich weiß, wird mich das mehr fordern und ich kann dabei noch mehr 
lernen...

Könnt ihr mir helfen?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es gibt hier keine 'schwierigen' Aufgaben.

Bei x++ setzt du in die weitere Berechnung den 'alten' Wert von x in die 
Berechnung ein. Bei ++x setzt du den bereits erhöhten Wert ein.

Ditto sinngemäss für --


Da nach schwierigen Berechnungen zu fragen, ist so wie wenn du nach 
'schwierigen' Beispielen für Formeln suchst, in denen eine Wurzel 
vorkommt. Die Berechnung einer Wurzel ist immer gleich, egal in welchem 
Zusammenhang sie vorkommt.
2*sqrt(3) ist nicht schwieriger zu berechnen als sqrt( a*a + b*b )

So auch hier: das x++ bzw ++x wird immer gleich behandelt. Einmal geht 
der alte Wert in die Berechnung weiter ein, das andere mal der bereits 
erhöhte.

Das einzige was man sich merken muss. Wann genau die Erhöhung von x 
abgeshchlossen ist und wann x daher seinen neuen Wert bekommt, ist nicht 
weiter definiert. Es muss vor dem nächsten Sequenz-Punkt passiert sein, 
aber wo genau, das darf der Compiler machen wie er will. Daher darf in 
so einem Fall das x nur einmal in diesem Statement vorkommen.

  x = x++;

hat daher undefiniertes Verhalten.
Genauso wie

  j = x++ + x++;

oder gar

  j = ++x++;

oder

  printf( "%d %d", x++, x++ );

oder andere Variationen derselben Grundidee.


Und die restlichen 'unübersichtlichen' Kombinationen, sind mehr Übungen 
in der Rangfolge der Operatoren, als das sie etwas mit ++ an sich zu tun 
haben. In

  int  i = 5;
  int* p = &i;

  *p++;

was wird erhöht? Der Pointer oder der Wert auf den der Pointer zeigt 
oder gar beides? Ist das daher gleichbedeutend mit

   (*p)++;
oder
   *(p++);
oder
   (*(p++)++);

Autor: Hans Wurst (wursthans)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zitat:

"int  i = 5;
  int* p = &i;

  *p++;

was wird erhöht? Der Pointer oder der Wert auf den der Pointer zeigt
oder gar beides? Ist das daher gleichbedeutend mit

   (*p)++;
oder
   *(p++);
oder
   (*(p++)++);"




Also ich hab mir dazu jetzt Gedanken gemacht und bin zu dem Entschluss 
gekommen, dass

*p++; den Pointer erhöht, nicht aber den Wert.

Das wäre doch dann gleichbedeutend mit: (*p)++.


*(p++), erhöht doch dann den Wert, oder?


Bei (*(p++)++) wird zuerst der Wert erhöht und dann der Pointer, oder?

Autor: Hans Wurst (wursthans)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab da mal noch eine Aufgabe bei der Ich mehrere Probleme hab:

  char zk[2][6] = {"Hallo", "Welt"};
  char *p, *q;
  int j = 3;


  p = &zk[0][0];
  q = p + 6;
  *(p++) = *q;
  *(p+1) = 's';
  zk[0][j] = '\0';
  *q = 'g';
  *(p+7) = 'h';



Die erste Zeile is ja klar. Die Adresse des Arrays an den Stellen 0,0 
wird in dem Pointer p abgelegt.

In der zweiten Zeile wird nun im Pointer q die Adresse von p + 6 
gespeichert. Hier hab ich dann schon das erste Problem: Wird hier von 0 
(für die erste Adresse) losgezählt, oder von 1? Laut Compiler aber von 
0, da ich nämlich nach der Addition von 6 auf das erste Element der 
zweiten Zeile des 2-dim. Arrays zeige, also 7. 0 - 6 entspricht ja 7 
Schritten.

In der dritten Zeile wird nun der Inhalt vom Pointer q auf p 
Dereferenziert. Nun wird der Pointer p inkrementiert und zeigt auf das 
Element 2 an der Stelle 1 im Array für die Zeile 1 bzw. 0.

In der vierten Zeile wird die Adresse des Pointers p um 1 inkrementiert 
und danach an diese neue Adresse (also Element 3 an der Stelle 2 im 
Array) das 's' geschrieben.


In der fünften Zeile wird in die Zeile 1 bzw. in die 1. Dimension des 
Arrays die terminierende Null geschrieben.

In der sechsten Zeile wird an die Adrese (hier 2. dim. des Arrays, 
Element 1 an der Stelle 0) ein 'h' geschrieben.

Nun zur siebten Zeile: Hier wird doch nun der Pointer p um 7 erhöht. P 
zeigt noch immer auf das 3. Element an der Stelle 2 in der 1. dim. des 
Arrays. Hier soll ich nun um 7 erhöhen. Muss ich da jetzt von 0 - 7 
zählen oder von 1 - 7?

In der zweiten Zeile, in der ich ja q erhöht habe, hab ich von 0 an 
begonnen zu zählen. Wenn ich das nun in der 7. Zeile auch mache, dann 
komm ich um eine Stelle zu weit drüber... Was stimmt denn nun?

Autor: DirkB (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Überlege mal was *(p+0) bedeutet und welche Stelle das ist.

Und bei *(p+7) ist es egal ob du bei 0 oder 1 anfängst zu zählen, denn 
du musst 7 Stellen weiter gehen.

Hast du dir denn die Variablen mal ausgegeben oder im Debugger 
angesehen?

Nebenbei ist der erste Arrayindex die 0.

Autor: Hans Wurst (wursthans)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
*(p+0) ist doch die selbe Stelle wie vorher, also die Stelle 3 im Array 
oder anders index 2. Stimmt doch oder?

Autor: DirkB (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hans Wurst schrieb:
> In der vierten Zeile wird die Adresse des Pointers p um 1 inkrementiert
> und danach an diese neue Adresse (also Element 3 an der Stelle 2 im
> Array) das 's' geschrieben.

*(p+1) verändert p nicht. So wie bei i = j + 3; j auch nicht geändert 
wird.

Darum bist du immer noch an der 2. Stelle.
Dann auch für dich der Hinweis auf die gleiche Diskussion in einem 
anderem Forum:  http://www.c-plusplus.de/forum/280958

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hans Wurst schrieb:
>   char *p, *q;
>   int j = 3;
>
>
>   *(p++) = *q;
>   *(p+1) = 's';
>   zk[0][j] = '\0';
>   *q = 'g';
>   *(p+7) = 'h';
> [/c]
>
>
>

Also:

   char zk[2][6] = {"Hallo", "Welt"};
   p = &zk[0][0];

> Die erste Zeile is ja klar. Die Adresse des Arrays an den Stellen 0,0
> wird in dem Pointer p abgelegt.

genau

   q = p + 6;

> In der zweiten Zeile wird nun im Pointer q die Adresse von p + 6
> gespeichert.

Es wird nicht die Adesse 'von' p+6 gespeichert. Denn p+6 ist ein 
arithmetischer Ausdruck und der hat keine Adresse. Es wird einfach der 
um 6 erhöhte Inhalt von p in q gespeichert.

> Hier hab ich dann schon das erste Problem: Wird hier von 0
> (für die erste Adresse) losgezählt, oder von 1?

In C wird IMMER von 0 weggezählt. Egal bei was.

   *(p++) = *q;

> In der dritten Zeile wird nun der Inhalt vom Pointer q auf p
> Dereferenziert.

q ird dreferenziert und das Zeichen, das man so erhält wird dort 
abgelegt, wohin p zeigt.

  *(p+1) = 's';

> In der vierten Zeile wird die Adresse des Pointers p um 1 inkrementiert
> und danach an diese neue Adresse (also Element 3 an der Stelle 2 im
> Array) das 's' geschrieben.

Da wird nichts inkrementiert. inkrementieren bedeutet auch 
zurückschreiben. Und hier wird p nicht verändert.
's' wird an der Adresse abgelegt, die durch p+1 erhalten wird


   zk[0][j] = '\0';

> In der fünften Zeile wird in die Zeile 1 bzw. in die 1. Dimension des
> Arrays die terminierende Null geschrieben.

kann man so sagen. da j 3 ist, wird an die 4.te Array Position eine '\0' 
geschrieben

   *q = 'g';

> In der sechsten Zeile wird an die Adrese (hier 2. dim. des Arrays,
> Element 1 an der Stelle 0) ein 'h' geschrieben.

Da q noch nicht verändert wurde, denke ich hast du das richtig gesehen.


   *(p+7) = 'h';

> Nun zur siebten Zeile: Hier wird doch nun der Pointer p um 7 erhöht. P
> zeigt noch immer auf das 3. Element an der Stelle 2 in der 1. dim. des
> Arrays. Hier soll ich nun um 7 erhöhen. Muss ich da jetzt von 0 - 7
> zählen oder von 1 - 7?

0.
IMMER 0. In C wird immer bei 0 angefangen zu zählen.


> komm ich um eine Stelle zu weit drüber... Was stimmt denn nun?


Wenn du den Überblick verlierst, hilft es mitzuzeichen.

Mal dir ein entsprechend großes 2D-Gitter auf und spiel Computer. 
Verfolge welche Werte p hat, indem du einen mit 'p' beschrifteten Pfeil 
in dieses Gitter zeigen lässt und den du umzeichnest wann immer sich p 
verändert.

Wenn du denkst jetzt hast du es, dann überlg dir, wie du 
programmtechnisch verifizieren kannst, ob auch tatsächlich das passiert 
ist, was du denkst das passiert ist.

Autor: Hans Wurst (wursthans)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"In C wird IMMER von 0 weggezählt. Egal bei was."

Wenn ich das jetzt im ersten Fall tu, dann gehe ich aber doch 7 
Schritten, oder? Ich zähle quasi 0,1,2,3,4,5,6.

Wenn ich im zweiten Fall bei 2 stehe, und dann p = p + 7 machen soll, 
dann müsste ich ja 8 Schritte machen, wenn ich von der 0 weg zählen 
soll. Aber das ist doch dann nicht mehr richtig...

Autor: DirkB (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei Schritten bewegst du dich weiter. Bei 0 Schritt bleibst du wo du 
bist.
Unterscheide zwischen Index (ab 0) und Position (sprachlich ab 1.).

Nochmal: bei int a[10]; ist das Element a[0] an der 1. Position im Feld 
(Index 0). Um zu a[2] zu gelangen musst du 2 weiter zählen.

Autor: Ich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wenn ich das jetzt im ersten Fall tu, dann gehe ich aber doch 7
> Schritten, oder? Ich zähle quasi 0,1,2,3,4,5,6.

Nein, das sind zwar sieben verschiedene Indizes, aber nur sechs 
Schritte:
0 --> 1  \
1 --> 2   |
2 --> 3   |
3 --> 4    }- 7 Schritte
4 --> 5   |
5 --> 6   |
6 --> 7  /

-> du kommst bei 7 an nach 7 Schritten

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
char zk[2][6] = {"Hallo", "Welt"};
  char *p, *q;
  int j = 3;


  p = &zk[0][0];
  q = p + 6;
  *(p++) = *q;
  *(p+1) = 's';
  zk[0][j] = '\0';
  *q = 'g';
  *(p+7) = 'h';


wie ich schon sagte:
Es hilft sich die Dinge aufzumalen

Mal dir ein 2*6 Array auf
   +---+---+---+---+---+---+
   | H | a | l | l | o | \0|
   +---+---+---+---+---+---+
   | W | e | l | t | \0|   |
   +---+---+---+---+---+---+

und jetzt spielen wir Computer
  p = &zk[0][0];

Variable p einrichten und dafür sorgen, dass sie auf zk[0][0] zeigt

  p
 +-----+
 |  o------+
 +-----+   |
           |
     +-----+
     v
   +---+---+---+---+---+---+
   | H | a | l | l | o | \0|
   +---+---+---+---+---+---+
   | W | e | l | t | \0|   |
   +---+---+---+---+---+---+


  q = p + 6;

In gleichem Masse ein Variable q einrichten, die 6 Felder von p aus 
gesehen weiter zeigt.
Wo ist das? Na zählen wir doch einfach. Dort wo p hinzeigt ist 0, denn 
wenn man sich von p aus um 0 Schritte weiterbewegt, ist man immer noch 
bei p.
   +---+---+---+---+---+---+
   | 0 | 1 | 2 | 3 | 4 | 5 |
   +---+---+---+---+---+---+
   | 6 |   |   |   |   |   |
   +---+---+---+---+---+---+
dort soll also das q hinzeigen

  p
 +-----+
 |  o------+
 +-----+   |
           |
     +-----+
     v
   +---+---+---+---+---+---+
   | H | a | l | l | o | \0|
   +---+---+---+---+---+---+
   | W | e | l | t | \0|   |
   +---+---+---+---+---+---+
     ^
     |
     +------+
            |
   q        |
  +----+    |
  |  o------+
  +----+

  *(p++) = *q;
was soll passieren. Zunächst die rechte Seite der Zuweisung:
Vom Feld, auf das q zeigt, soll der Wert geholt werden. In die Zeichnung
schauen, das ist ein 'W'.
Was soll damit passieren - jetzt wird die rechte Seite der Zuweisung 
interessant.
*(p++)
Das sind 2 Operation. Die Hauptoperation ist *p. Das Zeichen soll also 
dort abgelegt werden, wo p hinzeigt. Und als Nebenoperation wird p um 1 
Feld weitergestellt. Wobei dieses Weiterstellen die Speicheroperation 
nicht beeinflusst. Zum Speichern gilt der Wert, den p zu Beginn der 
Operation hatte (wegen Postinkrement)

Nach der Hauptoperation sieht die Sache daher so aus

  p
 +-----+
 |  o------+
 +-----+   |
           |
      +----+
      v
   +---+---+---+---+---+---+
   | W | a | l | l | o | \0|
   +---+---+---+---+---+---+
   | W | e | l | t | \0|   |
   +---+---+---+---+---+---+
     ^
     |
     +------+
            |
   q        |
  +----+    |
  |  o------+
  +----+

und nach dem Postinkrement, sind wir hier:

  p
 +-----+
 |  o------+
 +-----+   |
           |
         +-+
         v
   +---+---+---+---+---+---+
   | W | a | l | l | o | \0|
   +---+---+---+---+---+---+
   | W | e | l | t | \0|   |
   +---+---+---+---+---+---+
     ^
     |
     +------+
            |
   q        |
  +----+    |
  |  o------+
  +----+

 *(p+1) = 's';
rechts vom = steht ein einzelnes Zeichen. Ein 's'.
Was soll damit geschehen?
*(p+1)
Aha. Also: von p ausgehend 1 Feld weitergehen und dort dann das s 
ablegen.
Verändert sich p selber? Nein. Davon steht nichts in der Anweisung

Wo ist p+1?
Zählen wir wieder. Ausgehend von p
   +---+---+---+---+---+---+
   |   | 0 | 1 |   |   |   |
   +---+---+---+---+---+---+
   |   |   |   |   |   |   |
   +---+---+---+---+---+---+

damit wird das 's' dort abgespeichert:

  p
 +-----+
 |  o------+
 +-----+   |
           |
         +-+
         v
   +---+---+---+---+---+---+
   | W | a | s | l | o | \0|
   +---+---+---+---+---+---+
   | W | e | l | t | \0|   |
   +---+---+---+---+---+---+
     ^
     |
     +------+
            |
   q        |
  +----+    |
  |  o------+
  +----+

 zk[0][j] = '\0';

das ist leicht. j hat den Wert 3. Also einfach das Feld [0][3] aufuschen 
und dort ein \0 reinschreiben

  p
 +-----+
 |  o------+
 +-----+   |
           |
         +-+
         v
   +---+---+---+---+---+---+
   | W | a | s | \0| o | \0|
   +---+---+---+---+---+---+
   | W | e | l | t | \0|   |
   +---+---+---+---+---+---+
     ^
     |
     +------+
            |
   q        |
  +----+    |
  |  o------+
  +----+

  *q = 'g';

dort wo q hinzeigt, in das Feld kommt ein 'g' hinein.

  p
 +-----+
 |  o------+
 +-----+   |
           |
         +-+
         v
   +---+---+---+---+---+---+
   | W | a | s | \0| o | \0|
   +---+---+---+---+---+---+
   | g | e | l | t | \0|   |
   +---+---+---+---+---+---+
     ^
     |
     +------+
            |
   q        |
  +----+    |
  |  o------+
  +----+

  *(p+7) = 'h';

und zum Schluss nochmal eine ähnliche Operation wie vorhin. Ausgehend 
von p 7 Felder weiterzählen und dort ein 'h' hineinschreiben. Wo ist 
das? (Dort wo p hinzeigt ist wieder 0)
   +---+---+---+---+---+---+
   |   | 0 | 1 | 2 | 3 | 4 |
   +---+---+---+---+---+---+
   | 5 | 6 | 7 |   |   |   |
   +---+---+---+---+---+---+

dort muss also ein 'h' hinein.

  p
 +-----+
 |  o------+
 +-----+   |
           |
         +-+
         v
   +---+---+---+---+---+---+
   | W | a | s | \0| o | \0|
   +---+---+---+---+---+---+
   | g | e | h | t | \0|   |
   +---+---+---+---+---+---+
     ^
     |
     +------+
            |
   q        |
  +----+    |
  |  o------+
  +----+


Wie schon gesagt: einfach mal ein bischen mitzeichnen. Dann verlieren 
diese abstrakten Dinge gleich ein wenig von ihrem Schrecken.

Autor: Mark Brandis (markbrandis)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz, wie erzeugst Du diese Skizzen? Die sind nicht alle von Hand 
gemacht, oder? ;-)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mark Brandis schrieb:
> Karl heinz, wie erzeugst Du diese Skizzen? Die sind nicht alle von Hand
> gemacht, oder? ;-)

Doch.
(Und massig Copy&Paste)

Autor: verärgerter Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
DirkB schrieb:
> Darum bist du immer noch an der 2. Stelle.
> Dann auch für dich der Hinweis auf die gleiche Diskussion in einem
> anderem Forum:  http://www.c-plusplus.de/forum/280958

Nett. Ich glaube der Herr M.... will uns verarschen!

Nachdem man in darauf hingewiesen hat dass er seine ähh... "Ergüsse" [1] 
[2] vielleicht nicht unter richtigem Namen posten sollte lässt er seinen 
Account (Nickname: Bandchef) löschen, meldet sich unter anderem Namen 
neu an und macht munter weiter. Vom Crossposting reden wir gar nicht 
erst.

[1] Beitrag "Array als Parameter in einer Funktion"
[2] Beitrag "Fragen zur Rekursion"

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.