K&R上的代码损坏?

  • 本文关键字:代码 损坏 c
  • 更新时间 :
  • 英文 :


在K&R的"C编程语言"(第二版(的第29页,我读到了一个我认为被破坏的过程。因为我是初学者,我希望我错了,尽管我无法解释为什么。

代码如下:

#include <stdio.h>
#define MAXLINE 1000 // Maximum input line size
int get1line(char line[], int maxline);
void copy(char to[], char from[]);
// Print longest input line
int
main()
{
  int len;                // Current line lenght
  int max;                // Maximum lenght seen so far
  char line[MAXLINE];     // Current input line
  char longest[MAXLINE];  // Longest line saved here
  max = 0;
  while ((len = get1line(line, MAXLINE)) > 0)
    if (len > max) {
      max = len;
      copy(longest, line);
    }
  if (max > 0)            // There was a line to read
    printf("Longest string read is: %s", longest);
  return 0;
}
// `get1line()` : save a line from stdin into `s`, return `lenght`
int
get1line(char s[], int lim)
{
  int c, i;
  for (i = 0; i < lim -1 && (c = getchar()) != EOF && c != 'n'; ++i)
    s[i] = c;
  if (c == 'n') {
    s[i] = c;
    ++i;
  }
  s[i] = '';
  return i;
}

// `copy()` : copy `from` into `to`; assuming
// `to` is big enough.
void
copy(char to[], char from[])
{
  int i;
  i = 0;
  while ((to[i] = from[i]) != '')
    ++i;
}

我的困惑是:我们正在使用函数get1line,并假设在for循环结束时i设置为 lim -1 。然后下面的 if -语句将在 lim 更新i,导致下一条指令(将NULL字符放在字符串末尾的指令(损坏堆栈(因为在这种情况下没有分配s[lim](。

代码坏了吗?

总结:不可能同时使用 i == lim-1c == 'n' 退出循环,因此您担心的情况永远不会出现。

详细:我们可以重写 for 循环(同时保留其含义(以使事件的顺序清晰。

i = 0;
for (;;) {
    if (i >= lim-1) break;      /* (1) */
    c = getchar();
    if (c == EOF) break;        /* (2) */
    if (c == 'n') break;       /* (3) */
    s[i] = c;
    ++i;
}

在循环出口 (1( 处,不可能是这样c == 'n'因为如果是这种情况,那么循环将在上一次在 (3( 处退出。

在循环出口 (2( 和 (3( 处,不可能是i == lim-1的情况,因为如果是这种情况,那么循环将在 (1( 处退出。

* 这取决于lim至少为 2,因此实际上有以前的循环时间。该程序只调用lim等于 MAXLINEget1line,所以情况总是如此。

** 您可以通过在循环开始之前将c初始化为 'n' 以外的值,使函数在小于 2 时lim安全。但是如果你担心这种可能性,那么你可能还需要关注lim INT_MIN的可能性,这样lim-1由于整数溢出而导致未定义的行为。

如果lim == 0代码是错误的,因为它使用未初始化c并添加了\0。如果lim == 1也是错误的,因为它使用未初始化c。使用 lim < 2 调用函数不是很有用,但它不应该像这样失败。

如果lim > 1则函数正常

for (i = 0; i < lim -1 && (c = getchar()) != EOF && c != 'n'; ++i)
   s[i] = c;

如果i == lim-1,或者如果c == EOFc == 'n',循环将退出。

  • 如果第一个条件为真(i == lim-1(,则最后一个条件肯定不为真(除非lim < 2,如上所述(。

  • 如果第一个条件为假(i < lim-1(,那么即使循环以c == n退出,我们也知道缓冲区中有空间,因为我们知道i < lim-1

最新更新