fmt.Scanln malfunctions when user enters an input containing space

Hello guys first-timer here and newbie to golang (actually now learning).

I have a simple issue. My code asks for a name, age and then runs a loop. When I enter a name like John Doe (ie: a name containing a space), the program malfunctions and skips the age input. I tried solving by adding \n to fmt.Scanln() but it still didnt help. Why is this so?

package main

import "fmt"

func main() {
	var (
		age  int
		name string
	)

	fmt.Println("Hello there!")
	fmt.Println("Welcome to Universe DB!\n")

	fmt.Printf("Please input your name: ")
	fmt.Scanln("%s\n", &name)
	fmt.Println("Your name is:", name)

	fmt.Printf("\nPlease input your age: ")
	fmt.Scanln("%v\n", &age)

	for i := 0; i < age; i++ {
		fmt.Println("For the", i+1, "time, your name is:", name)
	}

	fmt.Println()

	i := 0
	for i < age {
		if i > 0 {
			break
		}
		fmt.Printf("Complementary print #%d\n", i+1)
		i++
	}

	numbers := [5]int{1, 2, 3, 4, 5}
	for i, num := range numbers {
		fmt.Printf("Range print #%d: %d\n", i+1, num)
	}

	for i, num := range [5]int{32, 54, 343, 2} {
		fmt.Printf("Range print (type 2) #%d: %d\n", i+1, num)
	}

	for i, num := range make([]int, 3) {
		fmt.Printf("Range print (type 3) #%d: %d\n", i+1, num)
	}

	fmt.Println()

}```

You don’t check for errors.

//fmt.Scanln("%s\n", &name)
n, err := fmt.Scanln("%s", &name)
if err != nil {
	fmt.Println(n, err)
}

Please input your name: 0 type not a pointer: string

You don’t check documentation: package fmt.

func Scanln(a ...interface{}) (n int, err error)

does not have a format string.

It is not

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

Write:

n, err := fmt.Scanln(&name)
if err != nil {
	fmt.Println(n, err)
    return
}
fmt.Println("Your name is:", name)

Thanks for the feedback but I’m still facing same issue

package main

import "fmt"

func main() {
	var (
		age  int
		name string
	)

	fmt.Println("Hello there!")
	fmt.Println("Welcome to Universe DB!\n")

	fmt.Printf("Please input your name: ")
	n, err := fmt.Scanln(&name)
	if err != nil {
		fmt.Println(n, err)
	}
	fmt.Println("Your name is:", name)

	fmt.Printf("\nPlease input your age: ")
	n, err = fmt.Scanln(&age)
	if err != nil {
		fmt.Println(n, err)
	}

	for i := 0; i < age; i++ {
		fmt.Println("For the", i+1, "time, your name is:", name)
	}

	fmt.Println()

	i := 0
	for i < age {
		if i > 0 {
			break
		}
		fmt.Printf("Complementary print #%d\n", i+1)
		i++
	}

	numbers := [5]int{1, 2, 3, 4, 5}
	for i, num := range numbers {
		fmt.Printf("Range print #%d: %d\n", i+1, num)
	}

	for i, num := range [5]int{32, 54, 343, 2} {
		fmt.Printf("Range print (type 2) #%d: %d\n", i+1, num)
	}

	for i, num := range make([]int, 3) {
		fmt.Printf("Range print (type 3) #%d: %d\n", i+1, num)
	}

	fmt.Println()

}

Program output:

Hello there!
Welcome to Universe DB!

Please input your name: Aceis Asm
1 expected newline
Your name is: Aceis

Please input your age: 0 expected integer

Range print #1: 1
Range print #2: 2
Range print #3: 3
Range print #4: 4
Range print #5: 5
Range print (type 2) #1: 32
Range print (type 2) #2: 54
Range print (type 2) #3: 343
Range print (type 2) #4: 2
Range print (type 2) #5: 0
Range print (type 3) #1: 0
Range print (type 3) #2: 0
Range print (type 3) #3: 0

node09@node09:~/proj/learn/hello-go$ m
m: command not found
node09@node09:~/proj/learn/hello-go$ 

From the documentation:

Package fmt

Scanning

Input processed by verbs is implicitly space-delimited: the implementation of every verb except %c starts by discarding leading spaces from the remaining input, and the %s verb (and %v reading into a string) stops consuming input at the first space or newline character.


In any case, your use of package fmt scanning is inappropriate. It’s too fragile. What if the age in not a number or is negative?

Here is a more robust solution:

package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strconv"
	"strings"
)

func scanString(s *bufio.Scanner) (string, error) {
	if s.Scan() {
		return s.Text(), nil
	}
	err := s.Err()
	if err == nil {
		err = io.EOF
	}
	return "", err
}

func scanInt(s *bufio.Scanner) (int, error) {
	if s.Scan() {
		text := strings.TrimSpace(s.Text())
		i, err := strconv.Atoi(text)
		if err != nil {
			return 0, err
		}
		return i, nil
	}
	err := s.Err()
	if err == nil {
		err = io.EOF
	}
	return 0, err
}

func main() {
	fmt.Println("Hello there!")
	fmt.Println("Welcome to Universe DB!\n")

	s := bufio.NewScanner(os.Stdin)

	var name string
	for {
		fmt.Print("Please input your name: ")
		var err error
		name, err = scanString(s)
		if err == nil {
			name := strings.TrimSpace(name)
			min := 1
			if len(name) >= min {
				break
			}
			err = fmt.Errorf(
				"name must be at least %d characters",
				min,
			)
		}
		fmt.Println("input error:", err)
	}

	var age int
	for {
		fmt.Print("Please input your age: ")
		var err error
		age, err = scanInt(s)
		if err == nil {
			min, max := 0, 120
			if age >= min && age <= max {
				break
			}
			err = fmt.Errorf(
				"age not in range %d to %d",
				min, max,
			)
		}
		fmt.Println("input error:", err)
	}

	for i := 0; i < age; i++ {
		fmt.Println("For the", i+1, "time, your name is:", name)
	}
}

.

Hello there!
Welcome to Universe DB!

Please input your name: Aceis Asm
Please input your age: 3
For the 1 time, your name is: Aceis Asm
For the 2 time, your name is: Aceis Asm
For the 3 time, your name is: Aceis Asm
1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.