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;
}
我正在按照 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;
}