2

在 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] = '\0';

  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]) != '\0')
    ++i;
}

我的困惑是:我们正在使用该函数get1line,并假设在for-loop的末尾i设置为lim -1. 然后以下if-statement 将更新iat lim,导致下一条指令(将NULL字符放在字符串末尾的指令)破坏堆栈(因为s[lim]在这种情况下未分配)。

代码被破坏了吗?

4

2 回答 2

4

摘要: 不可能同时使用i == lim-1and退出循环c == '\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,因此实际上在循环中存在先前的时间。该程序只调用equal to get1line,所以总是这样。**limMAXLINE

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

于 2013-09-29T14:56:54.430 回答
1

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

如果lim > 1那么功能正常

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

循环退出 ifi == lim-1或 ifc == EOF或 if c == '\n'

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

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

于 2013-09-29T14:55:17.313 回答