C++ fgets, sscanf ersetzbar durch cin?!

_mclaren_

Lieutenant
Registriert
Dez. 2006
Beiträge
909
Hallo, wir steigen nun von c zu c++ um und sollen ein Programm entsprechend umändern.
printf lasst sich leicht durch cout ersetzen, aber gibts auch etwas für fgets und sscanf?

Danke
 
cout ist ja nur eine Instanz einer ostream-Klasse, cin ist eine Instanz einer istream-Klasse...
Wenn du von der Tastatur einlesen willst, klar dann nimm cin (eventuell mit der Methode geline)
Wenn von Datei dann erstelle ein Objekt der ifilestream-Klasse... (so müsste sie heißen)

Edit: ne, ifstream heißt sie
 
hi

es geht um das hier

printf("Datum im Format tt.mm.jjjj --> ");
char in[201];

fgets(in, 201, stdin);

int t, m, j;
char ch;
int test;

test = sscanf(in, "%d.%d.%d%c", &t, &m, &j, &ch);
if(test != 4 || ch != '\n') { // Eingabs syntaktisch falsch
return 0;
}

ob man das von der Überprüfung her in c++ genauso machen kann wenn ja wie.
 
Wenn du nur die Funktionen ersetzt, wird das trotzdem kein echtes C++. Ich würde empfehlen, eine Klasse "Datum" zu definieren mit Ein- und Ausgabeoperatoren. In diesen holst du dir dann die Benutzereingabe mit der globalen Funktion getline (-> <string> includen) und überprüfst mit einem regulären Ausdruck, ob die Eingabe passt.
 
hi - also die genaue Aufgabe ist
Ersetzen Sie die Konsole-IO durch die objektorientierte Variante mit Hilfe von
cout und cin.

und wir rätsln halt grad, wie man nun auf eine gültige Eingabe prüfen kann ( weil nun die Kontrolle auf '\n' wegfallt)
 
man könnte das datum in einen string einlesen.
dann könnte man mit substr die gewünschten elemete rausschneiden,
mit atoi in integer umwandeln und dann prüfen ob das ein datum sein kann.

so würde ich es in c++ machen.

Gruß
BlackMark
 
Mir war etwas langweilig und da hab ich mal nen objektorientierten Vorschlag formuliert. Zum Kompilieren brauchst du dann noch die Boost.Regex-Bibliothek (www.boost.org).
Sieht vllt. etwas langatmig aus für die kleine Anwendung, hat aber den Vorteil, dass hier Objektorientierung auftaucht wie sie leibt und lebt. Getter- und Setter-Methoden, überladene Ein- und Ausgabestreams etc. Insbesondere die verwendete Regex ist einen Blick wert. Meine Regex ist aber noch nicht ideal, weil nur geprüft wird, ob die Eingabe mit dem Datumsformat übereinstimmt und nicht, ob es überhaupt ein gültiges Datum ist. Dein Teil überlass ich dir mal ;)
Ansonsten hab ich aber extra ausführlich kommentiert, in der Hoffnung, dass du dir vllt. ein paar Dinge merkst.

datum.h
PHP:
#include <iostream>
#include <sstream> // für Konvertierung
#include <boost/regex.hpp> // für reguläre Ausdrücke -> siehe Wikipedia
#include <string> // für getline -> Datum einlesen

typedef enum monat {JANUAR=1, FEBRUAR, MAERZ, APRIL, MAI, JUNI, JULI, AUGUST, SEPTEMBER, OKTOBER, NOVEMBER, DEZEMBER}
MONAT; // eigener Datentyp für Monate. bei Eingabe von 1 wird Januar ausgewählt usw.

class Datum { // Datumsklasse
    public: // öffentlich zugreifbar
        Datum(int=1, MONAT=JANUAR, int=2000); // Konstruktor zur Erstellung eines Datums mit Standardwerten, falls keine Angabe
        Datum(const Datum &); // Kopierkonstruktor zum Kopieren eines bereits vorhandenen Datumsobjekts
        
        // getter-Methoden: Rückgabe von Eigenschaftswerten
        int getTag() const;
        MONAT getMonat() const;
        int getJahr() const;

        // setter-Methoden: Setzen dieser Werte
        void setTag(int);
        void setMonat(MONAT);
        void setJahr(int);

    private: // Eigenschaften eines Datums: nur innerhalb der oben genannten Methoden bearbeitbar
        int tag;
        MONAT monat;
        int jahr;
};

// globale Funktionen

std::ostream & operator<<(std::ostream &, const Datum &); // Ausgabeoperator für komfortable Datumsausgabe
std::istream & operator>>(std::istream &, Datum &); // dasselbe für die Eingabe -> Datumsobjekt kann komfortabel erstellt werden

int convert_to_int(const std::string &, std::stringstream &); // eine Hilfsfunktion zur Umwandlung von eingegebenen Werte in int
                            // (alle private-Attribute der Klasse sind ints)
datum.cpp
PHP:
#include "datum.h"

using std::string;
using std::cout;
using std::cin;
using std::endl;
using std::ostream;
using std::istream;

Datum::Datum(int tag, MONAT monat, int jahr) {
    this->tag = tag; // Setzen der Klassenattribute. wegen Namensgleichheit this-Zeiger benutzen (ansonsten wäre es eine Selbstzuweisung)
    this->monat = monat;
    this->jahr = jahr;
}

Datum::Datum(const Datum& datum) {
    Datum(datum.getTag(), datum.getMonat(), datum.getJahr()); // Attributwerte über getter-Methoden ermitteln und Standardkonstruktor aufrufen
}

// einfach nur zurückgeben
int Datum::getTag() const {return tag;}
MONAT Datum::getMonat() const {return monat;}
int Datum::getJahr() const {return jahr;}

// einfach nur setzen
void Datum::setTag(int tag) {this->tag=tag;}
void Datum::setMonat(MONAT monat) {this->monat=monat;}
void Datum::setJahr(int jahr) {this->jahr=jahr;}


// Ende der Klassenmethoden und Beginn der globalen Funktionen, die von der Klasse losgelöst sind

istream & operator>>(istream & inputStream, Datum & datum) {
    string eingabeString;
    cout<<"Bitte um Format tt.mm.jjjj eingeben: ";
    getline(std::cin, eingabeString); // Eingabe in string speichern

    boost::regex pattern("^(\\d{1,2})\\.(\\d{1,2}).(\\d{4})$"); // \d: Ziffer, Zahlen in geschweiften Klammern geben
        // Anzahl bzw. Anzahlsintervall an, Backslashes zum sog. "Escapen"
                                // {1,2
    boost::smatch substrings; // Sammelbecken für Teilstrings (Tag, Monat, Jahr)
    if(boost::regex_match(eingabeString, substrings, pattern)) { // Prüfen, ob Pattern auf String passt (ob richtige Eingabe erfolgt ist)
        std::stringstream converter_stream; // Hilfsobjekt für die Konvertierung von string nach int
        datum.setTag( convert_to_int(substrings[1].str(), converter_stream) ); // substrings[1] enthält Tag
        datum.setMonat( static_cast<MONAT> ( convert_to_int( substrings[2].str(), converter_stream) ) ); // substrings[2] enthält Monat;
                            // Hier muss das Funktionsergebnis noch nach MONAT gecastet werden. Da enum aber intern
                            // ein int ist, ist das kein Problem.
        datum.setJahr( convert_to_int(substrings[3].str(), converter_stream) ); // substrings[3] enthält Jahr
    }
    
    return inputStream; // Stream zurückgeben für mögliche Verkettungen, bspw. cin>>datum1>>datum2;
}

int convert_to_int(const std::string & substring, std::stringstream & converter_stream) {
    converter_stream << substring;
    int attribut; // kann Tag, Monat oder Jahr sein
    converter_stream >> attribut;
    
    // Stream leeren
    converter_stream.clear();
    converter_stream.str("");
    
    return attribut; // umgewandelten Wert zurückgeben
}

std::ostream & operator<<(std::ostream & output_stream, const Datum & datum) {
    std::cout<< datum.getTag() << "."<< static_cast<int>(datum.getMonat()) <<"."<< datum.getJahr();
    return output_stream;
}
main.cpp
PHP:
#include "datum.h"

int main() {
    Datum datum1, datum2;
    std::cin>> datum1>> datum2;

    std::cout<< "Datum1: "<<datum1 <<"\nDatum2: "<< datum2 <<std::endl;
}
HTH,
moagnus
 
Zuletzt bearbeitet von einem Moderator: (Link korrigiert)
_mclaren_ schrieb:
Ersetzen Sie die Konsole-IO durch die objektorientierte Variante mit Hilfe von
cout und cin.
Also alleine das attestiert dem Aufgabensteller schon eine gewisse Inkompetenz. :rolleyes: Sorry für meine Ausdrucksweise, könnte gerade an meinem Grundzustand liegen. Ist das für die Uni oder Berufsschule? Mal so neugieriger Weise.

Um mal rudimentär zu verdeutlichen, was ich meine; wir haben das hier in C++:
Code:
class A {
  int m
  void f( int x) { m = x; }
};

Was ist denn hierdran anders in C?
Code:
struct A {
  int m;
};
void f( A* this, int x) {
  this->m = x;
}

Wenn man sich nun überlegt, dass printf( ...) nix anderes ist als ein fprintf( STDOUT, ...) und der erste Parameter von fprintf im Endeffekt immer das "Objekt" ist, steht irgendwo die Überlegung an, was an C I/O weniger objektorientiert sein soll als an C++ I/O... nur weil eine Sprache nicht direkt Objektorientierung unterstützt, heißt das noch lange nicht, dass man nicht trotzdem objektorientierten Code schreiben kann... genauso wenig wie ein C++ Programm objektorientiert ist, nur weil mal irgendwo "class" drin steht.

Folgendes sollte es wohl auch rudimentär tun:
Code:
#include <iostream>

using namespace std;

int main(int argc, char* argv[])
{
  char c1, c2; // könnte man auch alles noch initialisieren
  int dd, mm, yyyy;
  if( cin >> dd >> c1 >> mm >> c2 >> yyyy) {
    char c3 = char_traits<char>().to_char_type( cin.get());
    if( c1 == '.' && c2 == '.' && c3 == '\n') {
      cout << "ok" << endl;
    }
  }
  return 0;
}
Boost und RegEx halte ich hier für ziemlichen Overkill. Und wenn dann bitte gleich spirit ;) Zumal dem TE vermutlich nicht geholfen ist, wenn er (bzw. der Aufgabensteller zur Kontrolle) eine zusätzliche Lib benötigt und vermutlich mehr Zeit mit der Installation von Boost verbringt (sofern der Compiler überhaupt unterstützt wird) als die Lösung der Aufgabe benötigt.
 
Naja, vllt. ists etwas übertrieben. Aber...
objektorientierte Variante mit Hilfe von
cout und cin
Meiner Meinung weist das eindeutig auf überladene Operatoren hin, was dann so ungefähr das ergibt, was ich oben gepostet habe. Und wirklich kompliziert sind die Regechsen auch nicht...
 

Ähnliche Themen

Zurück
Oben