The C Programming Language 示例 1.9 的难点
Difficulties with an example 1.9 of The C Programming Language
我正在完成 C 程序设计语言 第一章的练习,虽然我理解大部分所说和显示的内容,但有一个例子我不明白。
在 1.9 中,有一个函数显示 return 行的长度,同时将作为参数传递的 char 数组设置为内容。
int get_line(char s[], int lim)
{
int c, i, l;
for (i = 0, l = 0; (c = getchar()) != EOF && c != '\n'; ++i) {
if (i < lim - 1)
s[l++] = c;
}
if (c == '\n')
if (l < lim - 1)
s[l++] = c;
s[l] = '[=10=]';
return l;
}
我不明白的是为什么我们需要这个:if (c == '\n') {...}
。这不能在for循环中组合吗?我们在哪里明确检查 c
不等于 '\n'
?我无法理解为什么这需要是一个外部条件。
任何灯罩都会有所帮助!
谢谢!
如果 c
等于 EOF
或 c
等于 '\n'
,则退出 for
循环。因此,在 for
循环之后,如果想知道 c
有哪个值,则必须测试
如果你想把它放在循环中,你必须这样做:
int get_line(char s[], int lim)
{
int c, i, l;
for (i = 0, l = 0; (c = getchar()) != EOF; ++i) {
if ((i < lim - 1) && (c != '\n'))
s[l++] = c;
else if (c == '\n') {
if (l < lim - 1)
s[l++] = c;
break;
}
}
s[l] = '[=10=]';
return l;
}
因此,如您所见,将条件包装在循环内,导致更多条件检查和 break
语句。
is why we need this: if (c == '\n') {...}
.
get_line()
在结构上是:
get_line() {
initialize
while get, A not true and B not true
perform X
if B
perform X
finalize
循环在两种情况下退出。对于其中之一 (c == '\n'
),我们仍然希望在某处执行 X
,因为这是函数目标的一部分。
Could this not be combined in the for-loop?
它可以合并,但我们有 2 个位置退出循环。
典型的编码准则提倡在单个位置退出循环。如果我们搁置那个目标,那么:
get_line() {
initialize
while get, A not true
perform X
if B quit the loop
finalize
如下所示,使用 相同数量的 条件检查,但有 2 个循环出口点。
int get_line(char s[], int lim) {
int c, i, l;
for (i = 0, l = 0; (c = getchar()) != EOF; ++i) {
if (i < lim - 1)
s[l++] = c;
if (c == '\n')
break;
}
s[l] = '[=12=]';
return l;
}
我们可以扭曲代码,让 2 个检查回到同一行,而不是在循环后 if (c == '\n')
。从风格上讲,这可能更难理解。
int get_line(char s[], int lim) {
int c, i, l;
for (i = 0, l = 0, c = 0; c != '\n' && (c = getchar()) != EOF; ++i) {
if (i < lim - 1)
s[l++] = c;
}
s[l] = '[=13=]';
return l;
}
最后,代码可以使用改进:
不需要 i
和 l
索引计数器。一个就够了。
数组大小和索引最好使用 size_t
类型。警告:size_t
是一些 unsigned 类型。
使用前导大小参数可以更好地进行静态代码分析和自文档化代码:lim
与 s[]
.
相关
避免对输入参数进行数学计算以免导致溢出。我们对本地对象有更多的范围控制。
当 lim
处于极值或零时要小心。
而不是在声明后赋值,在可行的情况下进行初始化。例如。 int i = 0;
get_line() {
initialize
while B not true, get, A not true
perform X
finalize
或
#include <stdio.h>
#include <stdlib.h>
size_t get_line(size_t size, char s[size]) {
int ch = 0;
size_t i = 0;
while (ch != '\n' && (ch = getchar()) != EOF) {
if (i + 1 < size)
s[i++] = (char) ch;
}
// size might have been pathologically 0, so no room for [=15=]
if (i < size) {
s[i] = '[=15=]';
}
return i;
}
我正在完成 C 程序设计语言 第一章的练习,虽然我理解大部分所说和显示的内容,但有一个例子我不明白。
在 1.9 中,有一个函数显示 return 行的长度,同时将作为参数传递的 char 数组设置为内容。
int get_line(char s[], int lim)
{
int c, i, l;
for (i = 0, l = 0; (c = getchar()) != EOF && c != '\n'; ++i) {
if (i < lim - 1)
s[l++] = c;
}
if (c == '\n')
if (l < lim - 1)
s[l++] = c;
s[l] = '[=10=]';
return l;
}
我不明白的是为什么我们需要这个:if (c == '\n') {...}
。这不能在for循环中组合吗?我们在哪里明确检查 c
不等于 '\n'
?我无法理解为什么这需要是一个外部条件。
任何灯罩都会有所帮助! 谢谢!
如果 c
等于 EOF
或 c
等于 '\n'
,则退出 for
循环。因此,在 for
循环之后,如果想知道 c
有哪个值,则必须测试
如果你想把它放在循环中,你必须这样做:
int get_line(char s[], int lim)
{
int c, i, l;
for (i = 0, l = 0; (c = getchar()) != EOF; ++i) {
if ((i < lim - 1) && (c != '\n'))
s[l++] = c;
else if (c == '\n') {
if (l < lim - 1)
s[l++] = c;
break;
}
}
s[l] = '[=10=]';
return l;
}
因此,如您所见,将条件包装在循环内,导致更多条件检查和 break
语句。
is why we need this:
if (c == '\n') {...}
.
get_line()
在结构上是:
get_line() {
initialize
while get, A not true and B not true
perform X
if B
perform X
finalize
循环在两种情况下退出。对于其中之一 (c == '\n'
),我们仍然希望在某处执行 X
,因为这是函数目标的一部分。
Could this not be combined in the for-loop?
它可以合并,但我们有 2 个位置退出循环。
典型的编码准则提倡在单个位置退出循环。如果我们搁置那个目标,那么:
get_line() {
initialize
while get, A not true
perform X
if B quit the loop
finalize
如下所示,使用 相同数量的 条件检查,但有 2 个循环出口点。
int get_line(char s[], int lim) {
int c, i, l;
for (i = 0, l = 0; (c = getchar()) != EOF; ++i) {
if (i < lim - 1)
s[l++] = c;
if (c == '\n')
break;
}
s[l] = '[=12=]';
return l;
}
我们可以扭曲代码,让 2 个检查回到同一行,而不是在循环后 if (c == '\n')
。从风格上讲,这可能更难理解。
int get_line(char s[], int lim) {
int c, i, l;
for (i = 0, l = 0, c = 0; c != '\n' && (c = getchar()) != EOF; ++i) {
if (i < lim - 1)
s[l++] = c;
}
s[l] = '[=13=]';
return l;
}
最后,代码可以使用改进:
不需要
i
和l
索引计数器。一个就够了。数组大小和索引最好使用
size_t
类型。警告:size_t
是一些 unsigned 类型。使用前导大小参数可以更好地进行静态代码分析和自文档化代码:
相关lim
与s[]
.避免对输入参数进行数学计算以免导致溢出。我们对本地对象有更多的范围控制。
当
lim
处于极值或零时要小心。而不是在声明后赋值,在可行的情况下进行初始化。例如。
int i = 0;
get_line() {
initialize
while B not true, get, A not true
perform X
finalize
或
#include <stdio.h>
#include <stdlib.h>
size_t get_line(size_t size, char s[size]) {
int ch = 0;
size_t i = 0;
while (ch != '\n' && (ch = getchar()) != EOF) {
if (i + 1 < size)
s[i++] = (char) ch;
}
// size might have been pathologically 0, so no room for [=15=]
if (i < size) {
s[i] = '[=15=]';
}
return i;
}