12

I am working through Caleb Doxsey's Go book and I have two questions about fmt.Scanf http://www.golang-book.com/4

I am wondering why the program does not stop after the second Scanf and wait for user input? And how do I test if the user entered an integer and/or did not leave blank?

package main import ( "fmt" //"math" ) // compute square roots by using Newton's method func main() { var x float64 //number to take square root var y float64 //this is the guess var q float64 //this is the quotient var a float64 //this is the average // how do check if the user entered a number fmt.Print("Enter a number to take its square root: ") var inputSquare float64 fmt.Scanf("%f", &inputSquare) // why doesn't program stop after // the Print statement and wait // for user input? fmt.Print("Enter first guess ") var inputGuess float64 fmt.Scanf("%f", &inputGuess) //x = 2 x = inputSquare y = inputGuess for i := 0; i < 10; i++ { //set up the for loop for iterations q = x/y //compute the quotient; x and y are given a = (q + y) / x //compute the average y = a //set the guess to the average } //for the next loop fmt.Println("y --> ", y) //fmt.Println("Sqrt(2)", math.Sqrt(2)) } 
4
  • 2
    It works properly for me. I'm going to guess that it's a line ending issue. If you're running on Windows, line endings are conventionally denoted by '\r\n', whereas on Mac OS X and Linux (where I tested this), it's just '\n'. My guess is that maybe Go is reading the '\r' , treating it as a line ending, and leaving the '\n' on the stream. So when you call fmt.Scanf again, there's already something in the buffer and no need to block. This is just a wild guess though. Commented Jul 1, 2013 at 10:28
  • ok. Any suggestions how to fix it? This is what I get running in Windows command line: c:\Go\src\play\exercise>go run loop_exercise.go Enter a number to take its square root: 2 Enter first guess y --> +Inf Commented Jul 1, 2013 at 11:11
  • 1
    What happens if you explicitly read a newline character with the Scanf call? Like "fmt.Scanf("%f\n", &inputGuess)"? Alternately, you could flush stdin after each read. I don't know go well enough to know where to tell you to look for a Flush function. Commented Jul 1, 2013 at 11:36
  • Yes, adding \n fixed the issue. Commented Jul 1, 2013 at 22:40

1 Answer 1

17

Update: was fixed almost a decade ago. The docs for fmt now read

In all the scanning functions, a carriage return followed immediately by a newline is treated as a plain newline (\r\n means the same as \n).

If you continue to have scanning errors, mind that it isn't your IDE's fault.


It's Issue 5391: fmt: Scanf rejects \r\n at end of line on Windows.

As a workaround and to check for valid input, write,

var inputSquare float64 n, err := fmt.Scanf("%f\n", &inputSquare) if err != nil || n != 1 { // handle invalid input fmt.Println(n, err) } 

and

var inputGuess float64 n, err = fmt.Scanf("%f\n", &inputGuess) if err != nil || n != 1 { // handle invalid input fmt.Println(n, err) } 

The workaround is the newline in the "%f\n" format strings.

Package fmt

func Scanf

func Scanf(format string, a ...interface{}) (n int, err error) 

Scanf scans text read from standard input, storing successive space-separated values into successive arguments as determined by the format. It returns the number of items successfully scanned.

Here's a complete working program:

package main import ( "fmt" ) // compute square roots by using Newton's method func main() { var x float64 //number to take square root var y float64 //this is the guess var q float64 //this is the quotient var a float64 //this is the average fmt.Print("Enter a number to take its square root: ") var inputSquare float64 n, err := fmt.Scanf("%f\n", &inputSquare) if err != nil || n != 1 { // handle invalid input fmt.Println(n, err) return } fmt.Print("Enter first guess ") var inputGuess float64 n, err = fmt.Scanf("%f\n", &inputGuess) if err != nil || n != 1 { // handle invalid input fmt.Println(n, err) return } x = inputSquare y = inputGuess for i := 0; i < 10; i++ { q = x / y // compute the quotient; x and y are given a = (q + y) / x // compute the average y = a // set the guess to the average } fmt.Printf("sqrt(%g) = %g\n", x, y) } 

Output:

Enter a number to take its square root: 2.0 Enter first guess 1.0 sqrt(2) = 1.414213562373095 

I used Go 1.1.1 on Windows 7:

C:\>go version go version go1.1.1 windows/amd64 
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks. Does fmt.Scanf() return an error? I assume, n is the input and err is the possible error message in n, err := fmt.Scanf("%f\n", &inputSquare)Is this correct?
See my revised answer. n is the number of items successfully scanned and err reports any errors encountered during the scan. Therefore, if there was an error or the number of items scanned isn't what you expect (err != nil || n != 1), do something to handle the error. However, if all goes well (err == nil && n == 1), the valid input, as a floating-point number (float64), can be read from *inputSquare. In your code, you discarded n and err, that's why you didn't notice errors.
I must be doing something wrong. If I run the program with the error handling part n, err := fmt.Scanf("f\n", &inputSquare) // pick up the error if err != nil || n != 1 { fmt.Println(n, err) I get "0 input does not match format" (I enter, for instance, 2.0 for inputSquare) If I comment out the error handling it all works fine! What am I doing wrong?
I've revised my answer to provide a complete working program. What output do you get when you run the program?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.