我正在努力提高对C ++的理解,尤其是指针运算。我经常使用atoi,但我很少考虑它是如何工作的。看看它是如何完成的,我主要理解它,但有一件事我很困惑。
以下是我在网上找到的解决方案示例:
int atoi( char* pStr )
{
int iRetVal = 0;
if ( pStr )
{
while ( *pStr && *pStr <= '9' && *pStr >= '0' )
{
iRetVal = (iRetVal * 10) + (*pStr - '0');
pStr++;
}
}
return iRetVal;
}
我认为我很难掌握atoi过去的主要原因是角色的比较方式。 “while”语句表示,而字符存在,和字符小于或等于9,和大于 - 或等于0 然后做东西。这句话对我说了两件事:
在我调查之前,我想我下意识地知道它,但我从来没有想过它,但是'5'字符比'6'字符“小”,就像5小于6一样,所以您可以将字符作为整数进行比较,基本上(对于此意图)。
编辑:我不知道 * pStr - '0'部分会做什么。
任何有助于理解这些观察结果的帮助都会非常有帮助!谢谢!
答案 0 :(得分:4)
虽然角色存在
不,不是真的。它说“虽然字符不是0(或'\0'
)。基本上,ASCII字符'\0'
表示”C“字符串的结尾。因为你不想超过字符的结尾数组(并且确切的长度未知),每个字符都经过'\0'
测试。
可以在逻辑上将字符与其他字符进行比较
没错。字符只不过是一个数字,至少在ASCII编码中是这样。例如,在ASCII中,'0'
对应的小数值为48
,'1'
为49,'Z'
为90(您可以查看ASCII Table here )。所以,是的,你可以像比较整数来比较字符。
不知何故
while (*sPtr)
和*sPtr != 0
是不同的。
完全不同。十进制0是一个特殊的ASCII符号(nul)
,用于表示“C”字符串的结尾,正如我在开头所提到的那样。您无法查看或打印(nul)
,但它就在那里。
答案 1 :(得分:3)
* pStr - '0'将字符转换为数字值'1' - '0'= 1 while循环检查我们是否不在字符串的末尾,并且我们有一个有效的数字。
答案 2 :(得分:2)
C中的字符仅表示为ASCII值。由于所有数字在ASCII中都是连续的(即0x30 =='0'和0x39 =='9',其间包含所有其他数字),您可以通过简单地进行范围检查来确定字符是否为数字,并且您可以通过减去'0'
得到数字的值。
答案 3 :(得分:0)
C-style strings are null-terminated
因此:
while ( *pStr && *pStr <= '9' && *pStr >= '0' )
这个测试:
*pStr
我们还没有到达字符串的末尾,相当于写*pStr != 0
(注意没有单引号,ASCII值0
或NUL
)。*pStr >= '0' && *pStr <= '9'
(可能更逻辑地)*pStr
处的字符在'0'
(ASCII值48
)到'9'
的范围内(ASCII值{ {1}}),即数字。答案 4 :(得分:0)
请注意,atoi的已发布实现尚未完成。 Real atoi可以处理负值。
虽然(* sPtr)和* sPtr!= 0不同。
这两个表达方式是相同的。当用作条件时,当存储在地址sPtr处的值不为零时,*sPtr
被认为是真,而当存储在地址sPtr处的值不为零时,*sPtr != 0
为真。区别是在其他地方使用时,第二个表达式的计算结果为true或false,但第一个表达式计算为存储值。
答案 5 :(得分:0)
'0'
在内存中的表示0x30
以及'9'
的表示形式为0x39
。这是计算机看到的,当它与逻辑运算符进行比较时,它使用这些值。 nul-termination字符表示为0x00
,(也称为零)。这里的关键是chars
就像机器的任何其他int
一样。
因此,while
声明说:
虽然我们正在检查的char是有效的(也就是非零,因此不是nul-terminator),并且它的值(当机器看到它)小于0x39且其值大于0x30时,继续。
然后while
循环的主体根据整数在字符串中的位置计算要添加到累加器的适当值。然后它递增指针并再次移动。一旦完成,它将返回累计值。
答案 6 :(得分:0)
这段代码使用ascii值来累积它的alpha等价的整数计数。
关于你的第一个编号的子弹,当比较任何结果是布尔值时,似乎是微不足道的。虽然我觉得你试图询问编译器是否真正理解“字符”。据我所知,这个比较是使用字符的ascii值完成的。即a <&lt; b被解释为(97 <98)。 (请注意,当您比较'a'和'A'时,也很容易看到使用ascii值,因为'A'小于'a')
关于你的第二个项目符号,似乎while循环正在检查实际上是否有一个非NULL的赋值(ascii值为0)。一旦遇到false语句,和运算符就会生成FALSE,这样就不会对NULL char进行比较。对于while循环的其余部分,它正在进行ascii比较,就像我提到的关于项目符号1.它只是检查给定字符是否对应于与数字相关的ascii值。即在'0'和'9'之间(或ascii:在48和57之间)
最后 在我看来,(* ptr-'0')是最有趣的部分。此语句返回0到9之间的整数(包括0和9)。如果你看一下ascii图表,你会发现数字0到9是彼此相邻的。所以想象'3' - '0'是51 - 48并产生3! :D所以简单来说,它是做ascii减法并返回相应的整数值。 :d
干杯,我希望这能解释一下
答案 7 :(得分:0)
让我们分解一下:
if ( pStr )
如果你传递atoi一个空指针,pStr
将是0x00
- 这将是错误的。否则,我们需要解析一些东西。
while ( *pStr && *pStr <= '9' && *pStr >= '0' )
好的,这里发生了很多事情。 *pStr
表示我们检查pStr指向的值是否为0x00
。如果你看一个ASCII表,0x00
的ASCII是&#39; null&#39;在C / C ++中,惯例是字符串是空终止的(与Pascal和Java样式字符串相反,它告诉你它们的长度然后有那么多字符)。因此,当*pStr
求值为false时,我们的字符串已经结束,我们应该停止。
*pStr <= '9' && *pStr >= '0'
有效,因为ASCII字符的值为&#39; 0&#39; &#39; 1&#39; &#39; 2&#39; &#39; 3&#39; &#39; 4&#39; &#39; 5&#39; &#39; 6&#39; &#39; 7&#39; &#39; 8&#39; &#39; 9&#39;都是连续的 - &#39; 0&#39;是0x30
和&#39; 9&#39;例如,0x39
。因此,如果pStr
指向的值超出此范围,那么我们就不会解析整数,我们应该停止。
iRetVal = (iRetVal * 10) + (*pStr - '0');
由于ASCII数字的特性在内存中是连续的,所以如果我们知道我们有一个数字,*pStr - '0'
计算其数值 - 0为0&#39; 0&#39; (0x30 - 0x30
),1表示&#39; 1&#39; (0x31 - 0x30
)... 9适用于&#39; 9&#39;。因此,我们将数量向上移动并在新的位置滑动。
pStr++;
通过向指针添加一个指针,指针指向内存中的下一个地址 - 字符串中的下一个字符,我们将转换为整数。
请注意,如果字符串不是空终止,它有任何非数字(例如&#39; - &#39;)或者它是非ASCII的任何方式,此函数将搞砸。它不是魔术,只是依赖于这些事情。