我想以mm / dd的形式扫描日期,所以我写了这段代码:
#include <stdio.h>
int main (void)
{
int start_date[4];
scanf("%d%d/%d%d", &start_date[0], &start_date[1], &start_date[2], &start_date[3]);
printf("%d%d%d%d\n", start_date[0], start_date[1], start_date[2], start_date[3]);
return 0;
}
但是当我输入以下代码时:
04/20
scanf()
读取此内容
4-419644000
如何制作它以便当我打印出start_date
中的每个元素时,我明白了:
0420
当我输入之前的输入时?
答案 0 :(得分:5)
使用%1d
:
int n = scanf("%1d%1d/%1d%1d", &start_date[0], &start_date[1], &start_date[2], &start_date[3]);
if (n != 4) { …handle error… }
请注意,这将同时接受:
19/96
和
1 9/
9
6
作为有效输入。如果你需要数字是连续的,你必须更加努力。一般来说,通常最好使用fgets()
(或POSIX's)读取一行
getline()
)然后使用sscanf()
解析该行。您还可以考虑检查字符串的长度等。
顺便说一下,你说:
但是当我输入以下代码时:
04/20
scanf()
读取此内容4-419644000
这里发生的事情是第一个04
读取%d
;第二个%d
失败,因为/
与数字不匹配,因此没有任何内容写入&start_date[1]
(或其他两个项目),scanf()
返回1.自此没有检查返回值,你没有意识到这个问题。请注意,检查应如我所示(n != 4
,其中4是您希望转换的项目数)。检查EOF无法正常工作;文件上没有EOF,但转换失败。既然你打印了一个未初始化的变量,你获得的值是不确定的(行话中的'未定义的行为');一个较大的负数是合理的(任何其他任何值,或崩溃,或......)。事实上,你有三个不确定的数字在一起,其中只有第一个是负数。避免未定义的行为;始终检查输入操作是否成功 - 如果失败则不要使用结果。 (或者,至少在使用结果失败时要非常谨慎;你需要确定你知道发生了什么。)
答案 1 :(得分:3)
%d
将消耗字符串&#34; 04&#34;,如果您想真正逐位输入,请尝试%c
,然后将其调整为数字:
char start_data[4];
scanf("%c%c/%c%c", &start_date[0], &start_date[1], &start_date[2], &start_date[3]);
start_data[0] -= '0';
start_data[1] -= '0';
start_data[2] -= '0';
start_data[3] -= '0';
另一种方法,你可以输入mm和dd并对其进行算术运算:
int mm, dd;
scanf("%d/%d", &mm, &dd);
int m0 = mm % 10;
int m1 = mm / 10;
int d0 = dd % 10;
int d1 = dd / 10;
答案 2 :(得分:1)
我认为您应该使用strptime()
代替。它专门用于解析标准日期格式,例如你的。只需将整个“单词”作为字符串阅读并将其提供给strptime()
。
答案 3 :(得分:1)
将数据类型更改为char [],因此您的代码如下所示
JButton continueButton = new JButton("Continue");
continueButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent a) {
if(continueButton.isEnabled()){
Student studentScreen = new Student();
studentScreen.dispose();
AddGrades addGradesScreen = new AddGrades(studentNameTextField.getText());
addGradesScreen.setVisible(true);
}
}
});
如果要将每个字符的数据类型更改为整数,可以通过查看ASCII代码进行更改,然后使用ASCII&#39; 0&#39;
减去字符数。答案 4 :(得分:1)
评论太长了,但你可以看到为什么会发生这种情况:
0x080484a7 <+58>: call 0x8048360 <__isoc99_scanf@plt>
0x080484ac <+63>: mov 0x2c(%esp),%ebx
0x080484b0 <+67>: mov 0x28(%esp),%ecx
0x080484b4 <+71>: mov 0x24(%esp),%edx
0x080484b8 <+75>: mov 0x20(%esp),%eax
0x080484bc <+79>: mov %ebx,0x10(%esp)
...
End of assembler dump.
(gdb) break *main+79
Breakpoint 4 at 0x80484bc
(gdb) r
Starting program: /root/test/testcode
04/21
Breakpoint 4, 0x080484bc in main ()
(gdb) i r
eax 0x4 4
ecx 0x80484fb 134513915
edx 0xb7fff000 -1207963648
ebx 0xb7fcc000 -1208172544
esp 0xbffff720 0xbffff720
ebp 0xbffff758 0xbffff758
esi 0x0 0
edi 0x0 0
eip 0x80484bc 0x80484bc <main+79>
eflags 0x286 [ PF SF IF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) c
Continuing.
4-1207963648134513915-1208172544
以下是发生的事情:
mov 0x2c(%esp),%ebx
mov 0x28(%esp),%ecx
mov 0x24(%esp),%edx
mov 0x20(%esp),%eax
这四个mov
语句是printf()
调用的准备。每个%d
对应一个寄存器:eax ebx ecx edx
您可以看到它将四个字节移动到每个寄存器中。这就是你看到胡言乱语的原因。打印的每个%d
都需要一个4字节的整数。
我在所有四个mov
语句之后设置了一个断点,所以让我们看一下它们包含的内容:
eax 0x4 4
ecx 0x80484fb 134513915
edx 0xb7fff000 -1207963648
ebx 0xb7fcc000 -1208172544
这看起来并不正确,但它确实对应于堆栈中的内容:
0xbffff740: 0x00000004 0xb7fff000 0x080484fb 0xb7fcc000
这些是寄存器中的四个值
第一个实际上是你的04
组合。它将04
解释为在%d
的范围内,这是我机器上的4字节整数。
由于你试图抓住四个%d
,程序会继续,并打印出四个%d
。换句话说,它打印出四个4字节整数。
发生这种情况的原因是Jonathan Leffler解释的内容:scanf将04
吞噬到第一个%d
,然后打破/
你仍然有一个%d%d%d%d
的printf(),所以程序尽职地打印出剩余的4字节十进制值。由于scanf
失败,剩余的3 %d
包含堆栈中发生的任何事情。