Fehler scanf

schwegennagel

Cadet 4th Year
Registriert
Feb. 2005
Beiträge
79
Hallo,
ich benutze die Funktion scanf um float-Werte einzulesen. Wenn nun statt einem float-Wert ein Character eingegeben wird, stürzt das Programm ab(ist aber ja auch klar). Ich wollte wissen, ob es eine Funktion gibt, die das verhindert. Also, dass das Format der Eingabe irgendwie überprüft wird. Kann mir da jemand helfen??

MFG
 
Hallo,

Ich nehme mal an, dass du mit C arbeitest, da in C++ cin verwendet wird.

Mit folgendem Code kannst du dir die Rückgabewerte von Scanf anschauen:
Code:
#include <stdio.h>

int main(){
	float f;
	int test = -32;
	
	printf("Float eingeben: ");
	fflush(NULL);
	test = scanf("%f",&f);
	printf("\nWert war: %f [Scanf liefert ->%d]\n",f,test);
	
	return 0;
}

Wie man sieht liefert scanf bei erfolgreicher Eingabe eines floatwertes "1" zurück, während ein Char zu einer "0" führt.
Bei mir gibts aber selbst dann keinen Absturz.

Zur Vertiefung des Themas kannst du dir auch noch das hier durchlesen:
http://www.gidnetwork.com/b-63.html

Generell ist das Problem einfach, dass scanf recht universell ist, es ist also nicht auf das Einlesen von einem Datentyp beschränkt, daher eben auch fehleranfällig.

Zum Einlesen von Strings würde sich fgets() und zum Einlesen von Chars getchar() anbieten. Für Zahlen ist scanf aber eigentlich ganz ok.

mfg
 
Zuletzt bearbeitet:
Also, ich meine C++.
Wenn ich jetzt schreibe:
scanf("%d",&variable);
und der Benutzer gibt aus Versehen ein a ein, stürzt das Programm ja ab. Gibt es eine Funktion/Möglichkeit dies zu verhindern??
 
Code:
#include <iostream>
int main() {
	float f;
	std::cin>>f; std::cout<<"blub";
}

In C++ wird für die Eingabe der "cin>>"-Operator verwendet. Und damit stürzts auch nicht ab, wie du siehst. :)
 
@moagnus:
.. stürzt vielleicht nicht ab, prüft aber genauso wenig.

Code:
#include <iostream>
int main() {
	float f;
	if( std::cin >> f) {
		std::cout << f << std::endl;
	}
	else {
		std::cout << "Datenfehler" << std::endl;
		std::cin.clear();
	}
}
 
Ich glaub für solche Zwecke müsstest du dann eine eigene Funktion schreiben und den Eingabestream einfach entsprechend behandeln. Die Standardfunktionen sind darauf ausgelegt auf viele verschiedene Datentypen zu "reagieren".

Also zumindest mir ist keine Standardeingabefunktion bekannt, die auf floats überprüfen kann. Das einzigste was noch im entferntesten in die Richtung geht, sind Typcasts und damit den Typ abzufragen. Aber das wird kaum funktionieren, da das ja eben erst nach "cin" gemacht werden kann.

Von daher -> musste wohl was eigenes programmieren!
 
Also zumindest mir ist keine Standardeingabefunktion bekannt, die auf floats überprüfen kann.
cin.operator>>(float& f) ?
scanf?

Tun beide genau das was sie sollen und das ziemlich gut (siehe Locales z.B.).

Das einzigste was noch im entferntesten in die Richtung geht, sind Typcasts und damit den Typ abzufragen.
Mmmh? Was meinst du?
 
Zuletzt bearbeitet:
Hallo,

7H3 N4C3R schrieb:
cin.operator>>(float& f) ?
scanf?

Tun beide genau das was sie sollen und das ziemlich gut (siehe Locales z.B.).

Ja und wo bitte verhält sich das jetzt anders als "cin" für diesen expliziten Fall? Wenn er
Code:
cin>>(float&) eingabe;
benutzt und ein 'f' eingegeben wird, das hat die Variable den Wert "2.8026e-045". Ich glaube kaum, dass es das ist, was der Threadersteller sich erwartet. Nach meinem Verständnis möchte er gerne eine Fehlerabarbeitung realisieren, so dass bei Eingabe eines Characters eine Ausgabe erscheint, die darauf hinweist, dass kein gültiger Fließkommawert eingegeben wurde.

Wenn es nur darum geht, dass das Programm nicht abstürzen soll und stattdessen mit "irgendeinem Wert" weitergearbeitet werden soll, dann tuts auch ein einfaches "cin>>eingabe".

Mmmh? Was meinst du?

Ich meinte, dass man versuchen könnte mit einem cast den Typen der Eingabevariable zu bestimmten. Aber im Nachhinein halte ich das für den falschen Ansatz, für die Erklärung siehe weiter oben.
 
cin hat einen typsicheren Eingabeoperator für floats. Also wo ist das Problem. Der ist absolut typsicher und verrichtet seine Arbeit gut (erkennt Standardnotation, wissenschaftliche Notation, kann mit richtigem Locale Dezimaltrennzeichen erkennen und 1000er Trennzeichen ebenfalls erkennen).

Wenn ein cin >> f; fehlschlägt, steht in f das drin, was vorher drinstand - es wird nicht verändert. Und wenn f vorher uninitialisiert war, ist es immernoch uninitialisiert. Und zusätzlich wird von cin das failbit gesetzt, woran man erkennt, dass die Eingabe fehlgeschlagen ist. Das kannst du entweder mit einem Aufruf von cin.fail() feststellen oder aber mit if (cin >> f). Bei letzerem gibt der operator>> cin zurück, von diesem wird dann operator void* (welcher im fail-Fall einen Nullzeiger liefert) aufgerufen implizit in einen bool konvertiert und damit die if-Bedingung erfüllt. Also if (cin >> f) ist der positive Test, cin.fail der Negative. Wichtig ist, wenn das failbit gesetzt ist, dann sind alle weiteren Operationen auf dem Stream ein No-Op, d.h. sie tun genau garnichts. Bis man mit .clear() die Fehlerbits wieder zurück setzt. Ich hoffe du verstehst nun etwas mehr von Input in C++.

Zu der Sache mit dem Cast, kommst du zufällig irgendwo aus der Java-Ecke bzw. irgendeine Sprache mit schwacher Typsicherheit? Sowas geht in C/C++ nicht über Casts. Das ist nicht nur der falsche Ansatz, das geht garnicht.
 
Zuletzt bearbeitet:
Hallo,

Danke für die ausführliche Erklärung, da hab ich wieder was dazugelernt.

Und zu deinem letzten Satz:
Nein ich komme aus "gar keiner Ecke". Wir haben in der FH erst C, danach C++ und parallel dazu Algorithmen & Datenstrukturen in C und C++ gemacht und zuletzt Java (in den ersten 3 Semestern). Vielleicht weißt du auch aus eigener Erfahrung, dass für intensive Behandlung von Streams leider die Zeit in den Vorlesungen fehlt, auch wenn ich das Glück hatte hervorragende Professoren als Lehrer zu haben.

Dynamic_cast haben wir kurz im Zusammenhang mit Polymorphie behandelt.

Zur Erläuterung ein kleiner Code Ausschnitt:
Code:
//Versuch eines dynamic_cast für einen falschen Pointertypen
//liefert 0 als Ergebnis

#include<iostream> // Main.cpp
#include"Punkt3DFarbe.h"

int main(){
	PunktFarbe *pf=
	      new PunktFarbe(1,2,PunktFarbe::GRUEN);
	Punkt3D *p3D= new Punkt3D(3,4,5);
	Punkt* p[2]={pf,p3D};  // Punkt3D und PunktFarbe erben von der Grundklasse Punkt
	
	for(int i=0;i<2;i++)
		if(dynamic_cast<Punkt3D*>(p[i])!=0)
			std::cout<<"Ist 3DPunkt\n";
		else
			std::cout<<"Kein 3DPunkt\n";
	return 0;

}

Nun etwas klarer was ich meinte? Es geht schon, nur wie gesagt ist es für diesen Fall nicht relevant.

mfg,
sam
 
Zuletzt bearbeitet:
Hmmm
Warum schreibst du

Code:
scanf("%d", &Variable);

hast du statt dem "echten" float zufällig n double genomen?!? Der Fehler liegt meines erachtens darin, dass du %d schreibst, denn ein double ist auch n float, also muss auch beim double %f stehn. probier das mal aus.
 
Hmm das hatte ich überlesen...
Übrigens ich glaube double wäre "%lf", "%d" ist für Integer zusammen mit "%i".

Aber du solltest trotzdem cin nehmen, das ist die C++ Standardeingabemethode.
 
samotyr schrieb:
Nein ich komme aus "gar keiner Ecke".
War ja auch nicht böse gemeint, sondern eher Neugier :) Ich lerne ja auch gerne dazu, wenn es z.B. eine Sprache mit solchen Möglichkeiten gibt.

Die Sache mit der Polymorphie und dynamic_cast kann nicht funktionieren, weil float ein eingebauter Datentyp ist, der nicht über RTTI verfügt. Außerdem sind eingebaute Datentypen keine Klassen-Typen sondern POD-Typen (Plain Old Data), Laufzeitpolymorphie funktioniert aber nur mit Klassentypen.
Zudem muss bereits ein Objekt eines konkreten Typs erzeugt worden sein, in den eingelesen wird. Wenn dieser Typ nicht passt, schlägt das Einlesen fehl und auch ein nachträglicher Cast hilft nicht. Dazu bräuchte man sonst beim Einlesen eine Typ-Information, welcher konkrete Typ denn nun genau eingegeben wurde, damit man weiß welche Einlesefuntion man benutzen muss. In einer Datei könnte man das entsprechend markieren, bei Benutzereingabe ist das nicht wirklich sinnvoll möglich.
 
7H3 N4C3R schrieb:
War ja auch nicht böse gemeint, sondern eher Neugier :) Ich lerne ja auch gerne dazu, wenn es z.B. eine Sprache mit solchen Möglichkeiten gibt.
Hab ich auch nicht so aufgefasst!

7H3 N4C3R schrieb:
Die Sache mit der Polymorphie und dynamic_cast kann nicht funktionieren, weil (...).

*hust* das weiß ich doch alles. Ich sagte doch, es ist nicht relevant für dieses explizite Problem mit der Erklärung von weiter oben :)
 
Zurück
Oben