我遇到了这个C程序:
int main() {
printf("Enter your address, (e.g. 51 Anzac Road) ");
gets(address);
number = 0;
i = 0;
while (address[i] != ' ') {
number = number * 10 + (address[i] - 48);
i++;
}
}
我理解number = number * 10 + (address[i] - 48);
是从输入中获取数字,但有人可以向我解释这是如何工作的吗?这是如何从输入中产生数字的?
答案 0 :(得分:4)
在ASCII中,数字字符 '0'
到'9'
占用代码点48到57(我是十六进制,0x30
到0x39
)所以,要将数字字符转换为值,您只需减去48。
顺便说一下,你应该真的减去
'0'
,因为标准不保证ASCII,尽管它确保保证数字字符是连续和有序的。例如,z / OS下的C使用EBCDIC,它将数字放在代码点0xf0
到0xf9
。
循环本身是一种简单的移位和添加类型,用于从多个数字字符创建数字。假设你有字符串"123"
,而number
最初为零。
你将number
(零)乘以10得到零,然后加上数字字符'1'
(49)并减去48.这给你一个。
然后你将number
(一)乘以10得到十并加上数字'2'
(50),再减去48.这给你十二。
最后,你将number
(十二)乘以10得到一百二十,然后加上数字字符'3'
(51)并减去48.这给你一百二十三。
有更好的方法可以在C标准库atoi
或更强大的strtol
- 类型函数中执行此操作,所有这些都可以在stdlib.h
中找到。后者可以让你更好地检测是否有垃圾"在数字的末尾,有关验证的帮助(atoi
无法区分123
和123xyzzy
)。
而且,除了另一个之外,你应该像瘟疫一样避免gets()
。它就像"裸体" scanf("%s")
,不适合用户输入,并打开代码来缓冲溢出问题。实际上,与scanf()
不同,没有使用gets()
的安全方式,这无疑是它从最新标准C11中删除的原因。可以找到更健壮的用户输入函数here。
还有一大类地址,其代码将失败,例如:
3/28 Tivoli Rd
57a Smith Street
Flat 2, 12 Xyzzy Lane
答案 1 :(得分:4)
C要求数字0
到9
按顺序连续存储在执行字符集中。 48
是'0'
的ASCII值,例如:
'3' - 48 == 3
任何数字。
C不需要ASCII,因此更好:
'3' - '0'
因为虽然48
适用于ASCII,但根据定义,'0'
适用于任何字符集。
如果address
包含"456 "
,则:
i == 0
和number == 0
,number * 10 + (address[0] - 48)
等于0 * 10 + 4
或4
。i == 1
,number * 10 + (address[1] - 48)
为4 * 10 + 5
或45
。i == 2
,number * 10 + (address[2] - 48)
为45 * 10 + 6
或456
你已经完成了。
永远不要使用gets()
,这很危险,甚至不再是C的一部分。