8

我正在努力提高我对 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然后执行操作。这句话对我说了两件事:

  1. 字符可以在逻辑上与其他字符进行比较(但返回值是什么?)。

在我研究这个之前,我想我下意识地知道它,但我从来没有真正想过它,但是“5”字符比“6”字符“小”,就像 5 小于 6,所以你可以比较字符作为整数,本质上(为此目的)。

  1. 不知何故,虽然 (*sPtr) 和 *SPtr != 0 是不同的。这对我来说似乎很明显,但我发现我无法用语言表达,这意味着我知道这是真的,但我不明白为什么。

编辑:我不知道*pStr - '0'部分会做什么。

理解这些观察结果的任何帮助都会非常...有帮助!谢谢!

4

8 回答 8

4

当角色存在时

不,不是。它说“虽然字符不是 0(或'\0')。基本上,ASCII 字符'\0'表示“C”字符串的结尾。因为您不想超过字符数组的结尾(并且确切的长度未知) ,每个字符都经过测试'\0'

字符可以在逻辑上与其他字符进行比较

这是正确的。字符只不过是一个数字,至少在 ASCII 编码中是这样。例如,在 ASCII 中,'0'对应的十进制值是 49,48是90(您可以在此处查看 ASCII 表)。所以是的,你可以像比较整数一样比较字符。'1''Z'

不知何故while (*sPtr)*sPtr != 0是不同的。

一点也不不同。十进制 0 是一个特殊的 ASCII 符号(nul),用于指示“C”字符串的结尾,正如我在开头提到的那样。您看不到或打印(nul),但它就在那里。

于 2013-01-30T22:40:56.260 回答
3

*pStr - '0' 将字符转换为其数值 '1' - '0' = 1 while 循环检查我们是否不在字符串的末尾并且我们有一个有效的数字。

于 2013-01-30T22:37:56.523 回答
2

C 中的字符简单地表示为 ASCII 值。由于所有数字在 ASCII 中都是连续的(即 0x30 == '0' 和 0x39 == '9' 以及介于两者之间的所有其他数字),您可以通过简单地进行范围检查来确定字符是否为数字,并且您可以通过减法得到数字的值'0'

于 2013-01-30T22:38:00.537 回答
0

C 风格的字符串是以null 结尾的

所以:

while ( *pStr && *pStr <= '9' && *pStr >= '0' ) 

这测试:

  • *pStr我们还没有到达字符串的末尾,相当于写*pStr != 0(注意没有单引号,ASCII值0,或NUL)。
  • *pStr >= '0' && *pStr <= '9'(也许更合乎逻辑)字符在(ASCII value ) 到(ASCII value )*pStr的范围内,即digit'0'48'9'57
于 2013-01-30T22:43:56.743 回答
0

请注意,已发布的 atoi 实现并不完整。真正的 atoi 可以处理负值。

不知何故,虽然 (*sPtr) 和 *sPtr != 0 是不同的。

这两种表达方式是一样的。当用作条件时,*sPtr当存储在地址 sPtr 的值不为零时被认为是真,并且*sPtr != 0当存储在地址 sPtr 的值不为零时被认为是真。区别在于在其他地方使用时,第二个表达式的计算结果为真或假,但第一个表达式的计算结果为存储值。

于 2013-01-30T22:45:13.950 回答
0

'0'in memory os的表示0x30'9'is的表示0x39。这就是计算机所看到的,当它将它们与逻辑运算符进行比较时,它会使用这些值。nul 终止字符表示为0x00, (又名零)。这里的关键是它chars就像int机器的任何其他东西一样。

因此,while声明说:

虽然我们正在检查的 char 是有效的(也不是零,因此不是 nul 终止符),并且它的值(如机器所见)小于 0x39 并且其值大于 0x30,但继续。

然后循环体while根据整数在字符串中的位置计算适当的值以添加到累加器中。然后它增加指针并再次前进。完成后,它将返回累积值。

于 2013-01-30T22:51:51.860 回答
0

这段代码使用 ascii 值来累积它的 alpha 等效值的整数。

关于您的第一个编号项目符号,在比较任何结果时,结果都是布尔值似乎很简单。虽然我觉得你想问编译器是否真的理解“字符”。据我了解,虽然这种比较是使用字符的 ascii 值完成的。即 a < b 被解释为 (97 < 98)。(请注意,当您比较 'a' 和 'A' 时,也很容易看到使用了 ascii 值,因为 'A' 小于 'a')

关于您的第二个项目符号,似乎 while 循环正在检查实际上是否存在一个不是 NULL 的分配值(ascii 值为 0)。一旦遇到错误语句,and 运算符就会产生 FALSE,这样您就不会对 NULL 字符进行比较。至于 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

干杯,我希望这能解释一下

于 2013-01-30T23:04:27.787 回答
0

让我们分解一下:

if ( pStr )

如果你传递 atoi 一个空指针,pStr将会是0x00- 这将是错误的。否则,我们有一些东西要解析。

while ( *pStr && *pStr <= '9' && *pStr >= '0' )

好的,这里发生了很多事情。*pStr意味着我们检查 pStr 指向的值是否是0x00。如果您查看 ASCII 表,则 ASCII 为0x00“null”,而在 C/C++ 中,约定是字符串以 null 结尾(与 Pascal 和 Java 样式的字符串相反,后者告诉您它们的长度然后有那么多字符)。所以,当*pStr计算结果为假时,我们的字符串已经结束,我们应该停止。

*pStr <= '9' && *pStr >= '0'有效,因为 ASCII 字符 '0' '1' '2' '3' '4' '5' '6' '7' '8' '9' 的值都是连续的 - '0'0x30和 '9'是0x39,例如。所以,如果pStr' 指向的值超出了这个范围,那么我们就没有解析一个整数,我们应该停止。

iRetVal = (iRetVal * 10) + (*pStr - '0');

由于 ASCII 数字的属性在内存中是连续的,因此如果我们知道我们有一个数字,就会*pStr - '0'计算出它的数值 - 0 代表 '0' ( 0x30 - 0x30),1 代表 '1' ( 0x31 - 0x30)... 9 代表'9'。因此,我们将号码向上移动并滑入新的位置。

pStr++;

通过给指针加一,指针指向内存中的下一个地址——我们正在转换为整数的字符串中的下一个字符。

请注意,如果字符串不是以 null 结尾的,它有任何非数字(例如'-'),或者它以任何方式不是 ASCII,则此函数将搞砸。这不是魔术,它只是依赖于这些事情是真实的。

于 2013-01-30T23:27:11.913 回答