Scanf() 第一种情况
package main
import "fmt"
func main() {
var a int
for {
fmt.Println("请输入一个整数:")
fmt.Scanf("%d", &a)
fmt.Println("----------------", a)
}
}
运行结果:
解释:
出现这种现象是因为程序执行的逻辑顺序所致。具体过程如下:
1.第一次循环输入 :
- 当输入 1 并按下 Enter 键时,实际输入的数据是 1\n。
- fmt.Scanf(“%d”, &a) 会读取 1 这个整数,赋值给变量 a。此时,换行符 \n 还留在输入缓冲区中。
- 然后程序执行 fmt.Println(a),输出 1 到控制台。
2.进入下一次循环:
- 控制台打印 “请输入一个整数:”,这是 fmt.Print(“请输入一个整数:”) 的输出。
- 此时,缓冲区中仍然有上一次输入残留的 \n。当 fmt.Scanf(“%d”, &a) 尝试读取时,发现缓冲区中的字符 \n 不是整数格式,导致读取失败。
- 由于 Scanf 的读取失败,并没有为 a 赋新值,a 保持了之前的值 1。但是读取失败之后,程序继续循环,再次打印 “请输入一个整数:”,使控制台显示了两次 “请输入一个整数:”。
3.第二次输入:
- 由于上一次的换行符造成了读取失败,程序这一次没有等待新的输入,就直接进入下一次循环,提示 “请输入一个整数:”。
解决方法
可以在读取失败后手动清除缓冲区中的换行符,避免这种情况。之前提到的使用 bufio.Reader 来清空输入缓冲区的方式可以解决这个问题。
修改后的代码如下:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
var a int
reader := bufio.NewReader(os.Stdin) // 创建一个 bufio.Reader
for {
fmt.Print("请输入一个整数:")
_, err := fmt.Scanf("%d", &a)
if err != nil {
fmt.Println("输入无效,请输入一个整数")
// 清除缓冲区中的剩余内容
reader.ReadString('\n')
continue
}
fmt.Println(a)
// 清除缓冲区中的换行符,防止干扰下次输入
reader.ReadString('\n')
}
}
这样处理后,可以确保每次输入都能正确读取,避免因换行符残留导致的错误。
Scanf() 第二种情况
package main
import "fmt"
func main() {
var a int
var b string
fmt.Println("请输入一个整数和一个字符串(如:123 hello):")
fmt.Scanf("%d %s", &a, &b) // 如果输入 "123\nhello",换行符会被忽略
fmt.Println("----------------", a, b)
}
运行结果:
解释:
出现这个问题的原因是,在执行 fmt.Scanf(“%d %s”, &a, &b) 时,输入了 123 并按下 Enter 键,程序只读取到了一个整数,而未能读取第二个字符串。这是因为 fmt.Scanf 解析输入时遇到了换行符,而 %s 格式要求必须在同一行读取字符串。
具体原因
当你输入 123 并按下 Enter 键时,Scanf 会按照格式化字符串 %d %s 的顺序尝试读取数据:
1.%d 读取到整数 123,这一步成功。
2.紧接着,Scanf 尝试读取一个字符串(由 %s 表示),但遇到了换行符(Enter 键输入的 \n),导致读取字符串失败。
3.因为未能读取到符合 %s 格式的字符串,程序结束了输入处理,只输出了整数的值。
解决方法
可以采用以下几种方式解决这个问题:
方法 1:使用 fmt.Scanln
fmt.Scanln 可以处理换行符,并在读取到换行符时结束输入。修改代码如下:
var a int
var b string
fmt.Print("请输入一个整数和一个字符串(如:123 hello):")
fmt.Scanln(&a, &b) // 使用 Scanln 来读取整数和字符串
fmt.Println("整数:", a)
fmt.Println("字符串:", b)
这种方式下,输入 123 然后按 Enter 键,程序会等待输入第二个字符串。
方法 2:使用 bufio.Reader 读取整行输入
可以使用 bufio.Reader 读取整行输入,然后使用 fmt.Sscanf 来解析输入的数据:
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
var a int
var b string
fmt.Print("请输入一个整数和一个字符串(如:123 hello):")
reader := bufio.NewReader(os.Stdin)
input, _ := reader.ReadString('\n')
input = strings.TrimSpace(input) // 去除输入的换行符和空白
fmt.Sscanf(input, "%d %s", &a, &b)
fmt.Println("整数:", a)
fmt.Println("字符串:", b)
}
在这个版本中,bufio.NewReader 读取整行输入,然后通过 fmt.Sscanf 解析输入数据。
总结
- fmt.Scanf 在读取数据时,换行符会导致输入解析中断,从而无法继续读取剩余的数据。
- fmt.Scanln 和 bufio.Reader 可以更好地处理换行符,以读取用户的完整输入。
Scanf() 键盘录入时,要注意的问题
一定要严格按照格式化字符串的格式输入,比如
1.fmt.Scanf(“%d %s”, &a, &b),%d %s,两者之间是用空格分隔的
正确示例:
失败示例:
之所以没有将123hello作为一个整体读取,是因为程序在读取完123后,在读取h时,发现h不符合%d的格式,所以只读取了123,而没有读取hello
2.fmt.Scanf(“%d,%s”, &a, &b),%d,%s,两者之间是用逗号分隔的
正确示例:
3.fmt.Scanf(“%d%s”, &a, &b),%d%s,两者之间是紧挨着的
正确示例:
当要输入两个字符串时,应注意的问题:
package main
import "fmt"
func main() {
var a string
var b string
fmt.Println("请输入两个字符串(如:123 hello):")
fmt.Scanf("%s%s", &a, &b)
fmt.Println("----------------", a)
fmt.Println("++++++++++++++++", b)
}
1.当fmt.Scanf(“%s%s”, &a, &b)中的%s%s之间没有任何间隔时,有如下两种情况: