Gå til innhold

"Tvinge" brukeren til å angi tall


Anbefalte innlegg

Videoannonse
Annonse
Header File

stdlib.h 

Category

Conversion Routines, Math Routines

Prototype

int atoi(const char *s);

int _wtoi(const wchar_t *s);

Description

Converts a string to an integer.

atoi converts a string pointed to by s to int; atoi recognizes (in the following order)
An optional string of tabs and spaces
An optional sign
A string of digits

The characters must match this generic format:

 [ws] [sn] [ddd]

In this function, the first unrecognized character ends the conversion. There are no provisions for overflow in atoi (results are undefined).

Return Value

atoi returns the converted value of the input string. If the string cannot be converted to a number of the corresponding type (int), atoi returns 0.

Lenke til kommentar
  • 1 måned senere...

#include <iostream>

using namespace std;

template<typename T>
void readStdin(T& t, std::string msg, std::string on_wrong_input)
{	
 std::cout << msg << std::flush;
 while(!(std::cin >> t)) {
   std::cout << on_wrong_input;
   std::cin.clear();
   std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
   std::cout << msg << std::flush;
 }
} // readStdin



int main()
{
 int tall;
 readStdin(tall, "tast inn et tall: ", "du tastet ikke inn et heltall, fors0k igjen!\n");
 cout << "2 * " << tall << " = " << 2 * tall << endl;
   
 return 0;
}

 

tast inn et tall: u

du tastet ikke inn et heltall, fors0k igjen!

tast inn et tall: o

du tastet ikke inn et heltall, fors0k igjen!

tast inn et tall: x

du tastet ikke inn et heltall, fors0k igjen!

tast inn et tall: 3

2 * 3 = 6

 

edit:

den skal håndtere andre typer på riktig måte også, f.eks. flytetall .. og også brukerdefinerte typer med operator>> definert for seg .......

 

edit2:

tilsvarende i Common Lisp:

(defun ensureRead (type)
 (do ((res (read) (read)))
     ((typep res type) res)))

> (ensureRead 'number)
u
x
54523
=>54523
> 

Endret av dayslepr
Lenke til kommentar

Kanskje dette er det du er på jakt etter

 

int tall;
char c
lesTall:
c = fgetc;
if(!((c > 47) && (c < 58))) 
 goto lesTall;
tall = atoi(c);

 

EDIT:

 

Må bare si Coq Roque sin metode er mye bedre enn min, da jeg ikke tok høyde for at tallet kunne ha flere siffer. Jeg skylder på La Vieille Ferm ;)

Endret av Mr.Garibaldi
Lenke til kommentar

Problemet ditt kan løses på mange måter. Den enkleste er buskmann sin

do {
cin >> inntall;
}
while (atoi(inntall) == 0);

 

Det denne koden gjør er å først lese inn en tekst til inntall (intall må være definert som et char array). Deretter sjekker den om det er et tall eller ikke med kallet atoi(inntall). Det dette kallet returnerer er tallet som ble funnet, evt 0 hvis inputten ikke ble gjenkjent som et tall (evt hvis tallet er 0).

 

Alternative (og i mine øyne mye morsommere måten å gjøre det på) er å lage en egen variant av atoi. Det kan ganske kjapt gjøres slikt:

 

char * inntall = new char[10];
int tall = 0;
bool lovlig_input = false;

// Så lenge du ikke har fått lovlig input, kjør en gang til
while (! lovlig_input)
{
  cout << "Skriv inn et tall: ";
  cin >> inntall;
  bool fortsett = true;
  for (int i = 0; i < 10 && fortsett; i++)
  {
      // Sjekk om symbolet er et tall mellom 0 og 9 (inklusivt)
      if (inntall[i] - '0' >= 0 && inntall[i] - '0' <= 9)
      {
          // Legg til gamle tallet (forsyv eksisterende med en titallsplass
          tall = tall * 10 + (inntall[i] - '0');
          // Si at du har en lovlig input
          lovlig_input = true;
      }
      else
      {
          // Du har støtt på et tegn som ikke er tall, avslutt sjekkinga av strengen
          fortsett = false;
      }
  }
} 

 

Coq Rouge (ikke testet koden, så vil ikke garantere for den, men prinsippet stemmer i det minste [tror jeg i alle fall ;) ])

Lenke til kommentar

Siden det fortsatt er reklame på TvNorge..

 

Skrevet om til c og kuttet litt ned, men ellers likt.

char inntall[10];
double tall = -1;
int convert = 0, i, negativ = 0;

printf("Skriv inn et tall:");

while (tall < 0)
{

  fgets(inntall, 10, stdout);
  /* sjekker om tallet er negativt */
  if(inntall[0] == '-')
  {
    negativt = 1;
    inntall[i] = 0;
  }  
  for (i = 0; inntall[i]; i++)
  {
      /* Sjekk om symbolet er et tall eller om det . */
      if ((isdigit(inntall[i]) || (inntall[i] == '.'))
      {
         convert = 1;          
      }
      else       
      {
        convert = 0;
        negativ = 0;
      }
  }
   if(convert)
      tall = atof(inntall);
} 
  if(negativ)
     tall *= -1;

 

Heller ikke testet, men skulle funke....

 

 

EDIT: Endret så den nå tar høyde for negative tall og flyttall. Ikke helt elegant, men men...

Endret av Mr.Garibaldi
Lenke til kommentar
Kanskje dette er det du er på jakt etter

 

int tall;
char c
lesTall:
c = fgetc;
if(!((c > 47) && (c < 58))) 
 goto lesTall;
tall = atoi(c);

 

EDIT:

 

Må bare si Coq Roque sin metode er mye bedre enn min, da jeg ikke tok høyde for at tallet kunne ha flere siffer. Jeg skylder på La Vieille Ferm ;)

5041088[/snapback]

 

 

Takker for positiv tilbakemelding ;) . Men vil påpeke et par små ting i koden din her.

 

1) Bruk av goto. Dette er generelt sett ansett som en dum ting å gjøre. I Wikipedia står det noe om dette, blandt annet om Dijkstra sine argumenter mot dette allerede i 1968 (og Dijkstra er en person det som regel lønner seg å høre på. Noen av argumentene mot goto er blandt annet det at det er umulig å bevise noe rundt koden (er kanskje ikke så veldig stort problem i dette tilfellet, men i store systemer så kan det fort bli det); det er også veldig mye vanskligere å lese goto, særlig da en ofte hopper i scope og ofte mange linjer med kode.

 

2)Bruken av de 'magiske' tallene 47 og 58 for '0' og '9'. Det er faktisk ikke alle tegnsett som har 0 og 9 på disse tallverdiene. Dessuten er det mye enklere å skjønne '0' og '9' i koden.

 

Coq Rouge (Foretrekker 10 ekstra linjer med kode som er lett å lese enn 2 linjer som du bruker en dag på å skjønne)

Lenke til kommentar
Foretrekker 10 ekstra linjer med kode som er lett å lese enn 2 linjer som du bruker en dag på å skjønne

 

koden min du sikter til? om du lurer på noe er det jo forsåvidt bare å spørre, det er ikke noe galt med koden (eller idéen) i det hele tatt; det er standard C++ ..

 

det er i det minste gjort et forsøk på å gjøre den en smule mer fleksibel enn de andre eksemplene ... :roll: .. . forsøkt med flytetall, eller negative tall for den saks skyld? .. hva med komplekse tall? (std::complex?)

 

her er den igjen, og litt mer fleksibel -- man kan bruke den mot andre streamer, f.eks. en netverksstream for kommunikasjon over Internet:

 

#include <iostream>

using namespace std;


template<typename T>
void readToType(T& t, string msg = "", string on_wrong_input = "", 
               unsigned int tries = 10,
               istream& istr = cin, 
               ostream& ostr = cout)
{	
 unsigned int i = 0;
 if(msg != "")
   ostr << msg << flush;
 while(!(istr >> t) && i < tries) {
   i++;
   if(on_wrong_input != "")
     ostr << on_wrong_input;
   istr.clear();
   istr.ignore(numeric_limits<streamsize>::max(), '\n');
   if(msg != "")
     ostr << msg << flush;
 }
} // readToType



template<typename T>
class Point {
public:
 T x, y;
}; // Point


template<typename T>
ostream& operator<<(ostream& o, Point<T>& point)
{
 o << point.x << ',' << point.y << endl;
 return o;
} // operator<<


template<typename T>
istream& operator>>(istream& i, Point<T>& point)
{
 i >> point.x;
 char comma;
 readToType(comma, "", "", 1, i, clog);
 i >> point.y;
 return i;
} // operator>>


int main()
{
 double flytetall;
 readToType(flytetall, "tast inn et flytetall: ", "du tastet ikke inn et flytetall, fors0k igjen!\n");
 cout << "kvadratet av " << flytetall << " er " << flytetall * flytetall << endl;

 Point<double> point;
 readToType(point, "tast inn et koordinat; to tall med komma i mellom, f.eks. `3.14, 100.2' : ", "feil format paa inntasting, fors0k igjen!\n");
 cout << point;
 cout << "x er `" << point.x << "' y er `" << point.y << "'" << endl;
   
 return 0;
}

 

lars@blackbox ~/tests $ ./a

tast inn et flytetall: 100.2

kvadratet av 100.2 er 10040

tast inn et koordinat; to tall med komma i mellom, f.eks. `3.14, 100.2' : 3.14, 100.2

3.14,100.2

x er `3.14' y er `100.2'

lars@blackbox ~/tests $ ./a

tast inn et flytetall: 21

kvadratet av 21 er 441

tast inn et koordinat; to tall med komma i mellom, f.eks. `3.14, 100.2' : 3.14, 100.2

3.14,100.2

x er `3.14' y er `100.2'

lars@blackbox ~/tests $ ./a

tast inn et flytetall: -123

kvadratet av -123 er 15129

tast inn et koordinat; to tall med komma i mellom, f.eks. `3.14, 100.2' : -3.14, 100.65

-3.14,100.65

x er `-3.14' y er `100.65'

lars@blackbox ~/tests $ ./a

tast inn et flytetall: 32

kvadratet av 32 er 1024

tast inn et koordinat; to tall med komma i mellom, f.eks. `3.14, 100.2' :  3.14,  32

3.14,32

x er `3.14' y er `32'

lars@blackbox ~/tests $ ./a

tast inn et flytetall: 123

kvadratet av 123 er 15129

tast inn et koordinat; to tall med komma i mellom, f.eks. `3.14, 100.2' :  3.12  ,  321.12

3.12,321.12

x er `3.12' y er `321.12'

lars@blackbox ~/tests $

$ ./a

tast inn et flytetall: 231

kvadratet av 231 er 53361

tast inn et koordinat; to tall med komma i mellom, f.eks. `3.14, 100.2' : blabla

aoeu

feil format paa inntasting, fors0k igjen!

tast inn et koordinat; to tall med komma i mellom, f.eks. `3.14, 100.2' : 123 321

123,21

x er `123' y er `21'

lars@blackbox ~/tests $

 

edit: formatering

 

edit 2:

if'ene for msg og on_wrong_input trengs vel strengt tatt ikke

Endret av dayslepr
Lenke til kommentar
Takker for positiv tilbakemelding  ;) . Men vil påpeke et par små ting i koden din her.

 

For all del. Jeg hakket jo løs på din ;)

 

1) Bruk av goto. Dette er generelt sett ansett som en dum ting å gjøre. I Wikipedia står det noe om dette, blandt annet om Dijkstra sine argumenter mot dette allerede i 1968 (og Dijkstra er en person det som regel lønner seg å høre på. Noen av argumentene mot goto er blandt annet det at det er umulig å bevise noe rundt koden (er kanskje ikke så veldig stort problem i dette tilfellet, men i store systemer så kan det fort bli det); det er også veldig mye vanskligere å lese goto, særlig da en ofte hopper i scope og ofte mange linjer med kode.

 

Sant. Kunne like gjerne laget en while() løkke, men goto var det første som falt meg inn, samt at jeg nesten aldri ellers bruker det. Men siden du insisterer :p

/*
* en løkke som leser inn en char fra kommandolinjen
* hvis den ikke er et tall, leser inn et nytt tegn. 
* hvis det er et tall avsluttes løkken og char c konverteres til en int
*/
int tall;
char c
do
{
 c = fgetc(stdin);
} while ((c > 47) && (c < 58));
tall = atoi(c);

 

2)Bruken av de 'magiske' tallene 47 og 58 for '0' og '9'. Det er faktisk ikke alle tegnsett som har 0 og 9 på disse tallverdiene. Dessuten er det mye enklere å skjønne '0' og '9' i koden.

 

Tja... Så vidt meg bekjent er de første 128 tegnene like for ASCII, UTF-8/16/32 samt ISO 8859 og windows tegnsettet, noe som skulle dekke de fleste tegnsettene i bruk i dag.

 

Coq Rouge (Foretrekker 10 ekstra linjer med kode som er lett å lese enn 2 linjer som du bruker en dag på å skjønne)

5041305[/snapback]

 

Touché!

 

Skal huske å kommentere bedre neste gang...

 

 

dayslepr> Godt poeng med versatiliteten, men siden han kun var på jakt etter en metode for bruk til utregning av en andregradsligning, så er det noe begrenset hva som trengs. (Men flyt-tall og negative tall er jo noe som vi også burde tatt høyde for)

EDIT: Som det nå er tatt høyde for i min omskrivning av Coq Rouges kode

Endret av Mr.Garibaldi
Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...