Frage von Beell1951, 99

c++ Zahl als "*" ersetzen?

Hi :)

Ich bin gerade dabei, einn c++ programm zu schreiben, was eine Zahl als " * " ersetzt.

z.B. Die Zahl n=8 wird eingegeben und es sollen 8 Sterne nebeneinander am Bildschirm ausgedruckt werden.


+) Gib eine Zahl zwischen 3 und 20 ein...

+) Ich gib die Zahl 8 ein

+) Dann kommen statt diesem Text 8 Sternchen

Hilfreichste Antwort - ausgezeichnet vom Fragesteller
von TeeTier, Community-Experte für programmieren, 26

Die bisherigen Antworten gefallen mir überhaupt nicht, da sie sich a) entweder auf C beziehen, obwohl eindeutig nach C++ gefragt wurde, oder b) total naiv implementiert sind, und es eindeutig an Eleganz mangelt.

Ich würde es so machen:

#include <iostream>
#include <cstdlib>
#include <cstddef>

int main(void) {
using namespace std;

const size_t mi = 3;
const size_t ma = 20;

cin.tie(&cout);

while (true) {
cout << "Zahl (" << mi << " bis " << ma << "): ";

size_t choice = 0;
cin >> choice;

if (mi > choice || ma < choice) {
cerr << "Abbruch!" << endl;
break;
}

cout << string(choice, '*') << endl;
}

return EXIT_SUCCESS;
}

Das Programm liest so lange Ganzzahlen ein und gibt diese als Reihe von Sternchen aus, bis der definierte Bereich über- oder unterschritten wird.

Noch einige Anmerkungen:

- cstddef wird für size_t eingebunden, auch wenn die anderen beiden Header das theoretisch erledigen sollten

- cstdlib wird für EXIT_SUCCESS benötigt; hab mir das anstelle von "return 0" in main() angewöhnt, da portabler

- Die using-Direktive ist funktionslokal, und da wir außer der STL ja sowieso keine weiteren Bibliotheken einsetzen, spart man sich damit eine menge unschöner "std::" Auflösungen. So etwas sollte man aber nicht dateilokal tun!

- Alle Integer-Werte sind als size_t definiert, da ein negativer Wert in der vorliegenden Aufgabe überhaupt keinen Sinn ergeben würde, und ich mir das Casten bei der Bereichsprüfung oder im string-Konstruktor sparen möchte. (Ich weiß, muss man nicht tun, aber gerade im Falle von String wäre es im Hinblick auf die Zukunft sinnvoll.)

- cout wird mithilfe der tie()-Funktion an cin gebunden, was für ein automatisches flush() sorgt, sodass wir uns darum nicht mehr kümmern müssen.

- die "merkwürdige" Reihenfolge bei den Vergleichen der Bereichsprüfung hat ihren Sinn darin, Programmierfehler zu vermeiden.

- Die Kernaufgabe wird einfach im string-Konstruktor erledigt, der für uns einen String, bestehend aus Sternchen mit der gewünschten Länge erzeugt ... ganz ohne Schleifen.

So, das wars. :)

Noch eine Anmerkung an den Fragensteller selbst, alle anderen Mitleser und die bisherigen Antworter: Nehmt euch mal die Zeit um die Standardbibliothek zu lesen! Mir fällt bei solchen Programmierfragen immer auf, dass viele Leute ständig und immer wieder das Rad neu erfinden wollen, und teils Ansätze auf absolutem low-level Niveau verfolgen. Dabei sind fast alle der gängigen Probleme schon in der STL gelöst.

Für den Anfang bitte einfach mal die Dokumentation zu den verschiedenen Konstruktoren der string-Klasse lesen, und evtl. nachschauen, was tie() eigentlich so macht. :)

Schönen Tag noch! :)

Kommentar von ralphdieter ,

Endlich mal 'ne brauchbare Antwort. Gib zu, Du hast schon heimlich ein paar Zeilen C++ codiert! Hier geb' ich noch meinen Senf dazu:

  • Ich schreibe gern zu jedem Header wenigstens ein importiertes Objekt dazu: #include<cstdlib> // EXIT_SUCCESSDas erspart oft längliche Erklärungen.
  • cin.tie(&cout) ist unnötig, da voreingestellt (siehe ISO/IEC 14882:1998, 27.3.1).
  • Und zur Eleganz: Ich selbst würde einfach nichts ausgeben und dabei mit '*' auf die Feldbreite choice auffüllen:
cout << setw(choice) << setfill('*') << "";
Kommentar von TeeTier ,

Die Idee mit der Feldbreite ist sehr schick! Gefällt mir! :)

Und der Hinweis mit den Includes ist auch sehr schön, aber da hatte ich schon ganz grottige embedded C-Compiler, die Kommentare nach Präprozessor-Direktiven fehlinterpretiert haben, aber das ist dann ja eigentlich ein Compiler-Bug ... naja egal. :)

Ich war kurz davor zu schreiben, dass cin standardmäßig an cout gebunden ist, aber dann dachte ich mir: "Das merkt sowieso keiner, und sprengt den Rahmen" ... und jetzt kommst du. :)

Ich habe auch damit gehadert, ob ich diesen Teil nun weg lasse, oder dazu schreibe, habe mich dann aber für letzteres entschieden (im Hinblick auf mögliche Legacy-Flags, wobei du natürlich Recht hast, und heutzutage kaum noch jemand mit weniger als C++98 kompilieren wird)

Allerdings stellen hier oft viele Leute Fragen zu C++, welche die eingestellte Original-Version von Dev-C++ einsetzen, mit dem ebenso veralteten Compiler, und genau diese Leute stoßen dann evtl. auf Probleme.

Das ist auch der Grund, warum ich ...

size_t choice = 0;

... statt ...

size_t choice {};

... geschrieben habe, da hier viele Einsteiger oft nicht die Version des Standards berücksichtigen, und man sich so späteres Nachfragen spart, wenn man die Codebeispiele so allgemein wie möglich hält. :)

Persönlich bevorzuge ich bei neuen Projekten immer den aktuellsten Standard, und verwende C++11 als Minimum, wobei ich die neuen Features von C++14 nur noch ungern missen möchte. Für Codebeispiele setze ich aber bewusst oftmals auf "ältere" Standards.

(Wenn es nur um Beispiele von Algorithmen geht, die Kunststücke mit Zeigern machen, achte ich sogar oftmals auf Kompatibilität zu C90, wenn es nicht unbedingt anders sein muss.)

Auf jeden Fall ist die Idee mit der Feldbreite sehr schön! :)

Antwort
von ceevee, 36

Ungefähr so müsste die Schleife aussehen.

-----------

// Eingabe n... das hast du ja soweit schon.

if (n >= 3 && n <= 20) {

int cnt = 0;

do {

printf("*");

cnt++;

}

while (cnt < n)

}

Kommentar von Beell1951 ,

Genau das, was ich brauche! Danke :D

Kommentar von TeeTier ,

Ein ...

cout << string(n, '*') << endl;

... war zu einfach, oder? :)

Kommentar von ceevee ,

Eleganz war hier für mich nebensächlich, ich hab mich am Beispielcode des Fragestellers orientiert (deswegen auch printf statt cout) und versucht, eine für ihn verständliche Lösung zu schreiben.

Kommentar von ralphdieter ,

Natürlich ist auch printf() in C++ erlaubt, aber dann bitte richtig:

 printf("%c", '*');

Soll in der nächsten Teilaufgabe '%' statt '*' ausgegeben werden, ist das bei allen Beispielen hier kein Problem. Aber printf("%") kann einen mehreren Stunden lang mit Fehlersuche beschäftigen.

Und wenn schon formatiert wird, kann man das ausnutzen:

printf( "%.*s\n", n, "********************" );

Das erspart einem die ganze Schleifenkonstruktion.

Antwort
von MaganRevan, 62

Hi,

du könntest in der Ausgabe eine For-Schleife vorschalten und diese dann durchlaufen, von 0 - kleiner Zahl. Und die Ausgabe ist dann eben * und wenn es dann bei zahl - 1 angekommen ist, dann wird ein Zeilenumbruch mit angefügt. Code musst du selber schreiben ;)

LG
MaganRevan

Kommentar von Beell1951 ,

Danke.

Wir haben in der Schule aktuell nur "float", "int" und die "do-while Schleife" gelernt.

Wie funktioniert die For-Schleife?

Kommentar von MaganRevan ,

Der Beitrag von charles2520 zeigt es dir.

Kommentar von Beell1951 ,

ok. danke :)

Kommentar von Beell1951 ,

Mein Code sieht aktuell so aus: pasted.co/a87fdd5e

Kommentar von MaganRevan ,

sollte so klappen, Angabe aber ohne Gewähr ;) konnte es nicht testen, bin aktuell unterwegs und hab' es mit dem Handy geschrieben:

#include 
using namespace std;

int main(){
int a,b,c;
b = 3;
c = 20;

cout << "Bitte gib eine Zahl zwischen " << b << "und " << c << " ein" << endl;
cin >> a;

if(a > b && a < c){
for(int i = 0; i < a; i++){
if(i != a-1){
cout << '*' << endl;
}
else{
cout << '*\n' << endl;
}
}
}
else{
cout << 'Eingabe nicht valide' << endl;
}

}
Kommentar von Beell1951 ,

Es funktioniert! Super :)

Wie kann ich es machen, dass die "*" nebeneinander sind und nicht untereinander?

Und zum Schluss kommt immer so eine komische Zahl ^^

Siehe:

Bitte gib eine Zahl zwischen 3 und 20 ein

3

*

*

10762

Kommentar von ralphdieter ,

Die Sternchen stehen untereinander, weil Du nach jedem einen Zeilenumbruch (endl) ausgibst. Lass es einfach weg.

Die "komische Zahl" ist der Wert des Multibyte-char 'Eingabe nicht valide'.  Nur mit doppelten Anführungszeichen wäre das ein String.

Kommentar von MaganRevan ,

Da hast du recht, ralphdieter, daran hab' ich, als ich es vorhin im Zug schrieb nicht gedacht.

Keine passende Antwort gefunden?

Fragen Sie die Community