K&R atoi-一般内存泄漏

K&R atoi-general memory leak

我正在按照 K&R 第二版示例学习 C 和编码,因为我认为这是正确的做事方式。无论如何,当我 运行 这个程序 post 编译时程序卡住了。我使用 valgrind 来执行编译后的脚本。

#include <ctype.h>

int atoi(char s[])
{
    int i, n, sign;
    for(i = 0; isspace(s[i]); i++)
        ;
    sign = (s[i] == '-')? -1 : 1;
    if (s[i] == '+'|| s[i] == '-')
        i++;
    for (int n = 0; isdigit(s[i]); n++)
        n = 10 * n + (s[i]-'0');
    return sign * n;
}

int main()
{
    char input[] = "       -12345";
    atoi(input);
}
# vaibhavchauhan at startup001 in ~/Documents/Projects/K-R on git:master x [0:43:36]
$ valgrind ./atoi-general
==8075== Memcheck, a memory error detector
==8075== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==8075== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==8075== Command: ./atoi-general
==8075==
^C==8075==

在您的第二个循环中,您正在迭代 n 但您使用 i 进行计算和计算。这导致您观察到无限循环。要解决此问题,请始终使用 i 作为索引:

int atoi(char s[])
{
    int i, sign, n;
    for(i = 0; isspace(s[i]); i++)
        ;
    sign = (s[i] == '-')? -1 : 1;
    if (s[i] == '+'|| s[i] == '-')
        i++;
    for (n = 0; isdigit(s[i]); i++)
        n = 10 * n + (s[i]-'0');
    return sign * n;
}

请注意,索引的类型应为 size_t,而不是 int,因为后者可能不足以索引每个数组。为此,int 类型的索引就可以了。

注意到,第二个循环中的索引不正确。

for(int n = 0; isdigit(s[i]); n++)
    n = 10 * n + (s[i]-'0');

这应该是 - 请注意您应该 不重新初始化 第二个循环中的索引 i 因为它应该是第一个循环的剩余值(因为你已经跳过了空格和符号)。

for( ; isdigit(s[i]); i++ )
    n = 10 * n + (s[i]-'0');

可以改进 K&R 示例的可读性和性能。存在以下问题:

  • 您不能将自己的函数命名为与标准库函数相同的名称。 atoi 存在于 stdlib.h。
  • 对传递的参数使用 const 正确性。
  • 多重循环和迭代器难以阅读和维护,这导致了问题中的错误。理想情况下应该只有一个迭代器。可以说,这个错误是由 原始程序员 引起的,因为他们编写了无法维护的草率代码。
  • 类型 size_t 应该用于迭代器,而不是 int
  • 如果迭代器有一个有意义的名字也没有坏处。 n 对于迭代器来说是一个非常糟糕的名字!在C编程中,n有一个特殊的含义,就是描述容器中物品的数量。
  • 为了可读性,也可能为了性能,指针参数可以用作迭代器。然后我们不需要首先发明所有这些局部迭代器变量。
  • 为符号使用 bool 变量以提高可读性。
  • 不需要检查当前字符是否为-两次
  • 始终在每个语句后使用大括号,以防止致命错误,例如 Apple goto 失败。

#include <ctype.h>
#include <stdbool.h>


int my_atoi (const char* str)
{
  while(isspace(*str))
  {
    str++;
  }

  bool sign = false;
  if(*str == '-')
  {
    sign = true;
    str++;
  }
  else if(*str == '+')
  {
    str++;
  }

  int result = 0;
  while(isdigit(*str))
  {
    result = 10*result + *str - '0';
    str++;
  }

  if(sign)
  {
    result = -result;
  } 

  return result;
}