C K&;R atoi通用内存泄漏

C K&;R atoi通用内存泄漏,c,atoi,kernighan-and-ritchie,C,Atoi,Kernighan And Ritchie,我按照K&R第二版的例子学习C和编码,因为我认为这是正确的方法。无论如何,当我在编译后运行这个程序时,程序被卡住了。我使用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]

我按照K&R第二版的例子学习C和编码,因为我认为这是正确的方法。无论如何,当我在编译后运行这个程序时,程序被卡住了。我使用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==
#包括
int atoi(字符s[]
{
int i,n,符号;
对于(i=0;isspace(s[i]);i++)
;
符号=(s[i]='-')?-1:1;
如果(s[i]='+'| | s[i]=='-')
i++;
对于(int n=0;isdigit(s[i]);n++)
n=10*n+(s[i]-'0');
返回符号*n;
}
int main()
{
字符输入[]=“-12345”;
atoi(输入);
}
#vaibhavchauhan在git上的~/Documents/Projects/K-R中的startup001上:master x[0:43:36]
$valgrind./atoi general
==8075==Memcheck,内存错误检测器
==8075==2002-2015年版权(C)和GNU GPL'd,朱利安·苏厄德等人。
==8075==使用Valgrind-3.11.0和LibVEX;使用-h重新运行以获取版权信息
==8075==命令:./atoi常规
==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\u t
,而不是
int
,因为后者可能不够大,无法索引每个数组。为此,类型为
int
的索引是可以的。

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

for(int n = 0; isdigit(s[i]); n++)
    n = 10 * n + (s[i]-'0');
这应该是-注意,您不应该重新初始化第二个循环中的索引
i
,因为它应该是第一个循环的剩余值(因为您已经跳过了空格和符号)


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

  • 不允许将自己的函数命名为与标准库函数相同的函数<代码>原子存在于stdlib.h中
  • 对传递的参数使用const correction
  • 多个循环和迭代器很难读取和维护,这导致了问题中的错误。理想情况下,应该只有一个迭代器。可以说,这个bug是由原始程序员造成的,因为他们编写了无法维护的、草率的代码
  • 迭代器应使用类型
    size\u t
    ,而不是
    int
  • 如果迭代器有一个有意义的名称,也不会有什么坏处
    n
    对于迭代器来说是一个非常糟糕的名字!在C编程中,
    n
    有一个特殊的含义,即描述容器中项目的数量
  • 为了可读性,也可能为了性能,指针参数可以用作迭代器。那么我们就不需要首先发明所有这些局部迭代器变量
  • 为符号使用bool变量以增加可读性
  • 无需检查当前字符是否为
    -
    两次
  • 每次声明后都要使用大括号,以防止致命的错误,如Apple goto fail

#包括
#包括
int my_atoi(常量字符*str)
{
while(isspace(*str))
{
str++;
}
布尔符号=假;
如果(*str=='-')
{
符号=真;
str++;
}
如果(*str=='+'),则为else
{
str++;
}
int结果=0;
while(isdigit(*str))
{
结果=10*result+*str-'0';
str++;
}
如果(签名)
{
结果=-结果;
} 
返回结果;
}

除非我大错特错,否则这既不是“K&R”(或者这是书中的复制粘贴?),也不是“内存泄漏”(valgrind没有这样的消息)。这是您试图实现陷入无休止循环的
atoi()
函数的尝试。您可能想编辑问题的标题。@DevSolar您弄错了,这段代码几乎是p54.Valgrind一书的复制/粘贴?我很惊讶,在使用调试器时,您没有检测到“n/I”无限循环。我也同意,你可能会比K&R差很多,但有很多好的选择。我的主要目标是让自己学习与今天相关的基本编程技术。我喜欢K&R,因为它解释并教您可以应用其他编程语言的编程结构。索引
I
不应该在第二个循环中重新初始化。for语句是无限循环的,因为检查条件始终为真?@VaibhavChauhan是的。删除
n=0
会导致未定义的行为因为
n
未初始化。循环应以
n=0
和增量
i
开始(注意
n
属于功能范围)。这很让人困惑,但这是故意的。声明时,应该初始化“n”,而不是在循环内部,这会导致更多的混乱。我必须说,我从未在C中使用bool类型,我仍然依赖于0,1。也许是时候升级了。你的例子非常干净,我喜欢它,我看到你把声明放在函数的中间。您不认为最好在开始时移动它们吗?@terencehill声明变量的位置其实并不重要,这是原始代码中最次要的问题。我将声明放在使用变量的位置附近,以清楚地显示变量已初始化以及使用了什么值。这类代码intx=something;/*一百行无关代码*/x+=y很难阅读。但是对于
result
变量的特定情况,最好将其放在函数定义的最上面,因为它是函数返回的值。
for( ; isdigit(s[i]); i++ )
    n = 10 * n + (s[i]-'0');
#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;
}