理解读取一组文本行并打印K&R书中最长的程序
Understanding the program that reads a set of text lines and prints the longest in K &R's book
我正在阅读 K &R 的书,第 1.9 节。从给定的一组行中打印最长行的程序给出为
#include <stdio.h>
#define MAXLINE 1000 /* maximum input line length */
int getline(char line[], int maxline);
void copy(char to[], char from[]);
/* print the longest input line */
main()
{
int len; /* current line length */
int max; /* maximum length seen so far */
char line[MAXLINE]; /* current input line */
char longest[MAXLINE]; /* longest line saved here */
max = 0;
while ((len = getline(line, MAXLINE)) > 0)
if (len > max) {
max = len;
copy(longest, line);
}
if (max > 0) /* there was a line */
printf("%s", longest);
return 0;
}
/* getline: read a line into s, return length */
int getline(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] = '[=10=]';
return i;
}
/* copy: copy 'from' into 'to'; assume to is big enough */
void copy(char to[], char from[])
{
int i;
i = 0;
while ((to[i] = from[i]) != '[=10=]')
++i;
}
getline
函数有问题。如果输入行的第 lim-1
个字符不是换行符,则 getline
将在第 lim-1
处插入 '[=15=]'
,而第 lim
处未使用(或空的)。
我通过将 getline
修改为
来移除此限制
int getline(char s[], int lim)
{
int c, i;
for (i=0; i < lim-1 && (c=getchar())!=EOF && c!='\n'; ++i)
s[i] = c;
s[i] = c;
s[i+1] = '[=11=]';
return i;
}
我的 getline
版本正确吗?
如果是,哪个版本在 运行 时间最快,需要最少的内存,使用最少的内存?
由于这个问题还没有关闭也没有转移到其他站点...我会在这里回答。
关于允许在 C 缓冲区中写入的位置(在什么索引处)的部分已在 related question, but I see have to repeat it here: you're only allowed to write at indices from 0 to lim-1
, inclusively. You are not allowed to write to the lim
index, in the sense that the behavior is undefined; what will happen in practice depends on whatever you happen to overflow to in memory. (You may also want to look at https://security.stackexchange.com/questions/53878/how-to-explain-buffer-overflow-to-a-layman 中得到回答;尽管它在技术上不正确,但那里的最佳答案应该给你正确的直觉,为什么溢出是一个问题。)
在这个问题的 getline
的任一版本中,for
循环可以在 i==lim-1
时退出。在您的 getline
版本(您问题中的那个 lower/later )中,您然后无条件地写入 s[i+1]
,这意味着您写入 s[lim]
,这是缓冲区溢出(又名缓冲区溢出)。
K&R 的版本有点微妙,因为如果 i==lim-1
在循环结束时,那么 c
不能 是 '\n'
,所以他们的 if (c == '\n') { s[i] = c; ++i; }
块在这种情况下不会执行,所以 i
不会递增等于 lim
,这使得最后一个赋值 s[i]
安全!换句话说,忽略(为了更容易理解)关于 EOF
的部分,&&
的 postcondition for the for
loop is that (i==lim-1 && c!='\n' )||(i<lim-1 && c=='\n')
. To see why this is the case, you need to understand the short-circuit behavior:当 i==lim-1
时,[ 的旧值=19=]将通过不执行(短路)c=getchar()
来保持;此外,先前获得的 c
保证不会是 \n
,因为在相反的情况下,for
循环会提前一次退出循环,即当 i<lim-1
时。 (for
循环的完整后置条件,不忽略 EOF
是 (i==lim-1 && c!='\n' && c!=EOF)||(i<lim-1 && c==EOF)||(i<lim-1 && c=='\n')
。)
// Program to print the length and content of the longest line in a text sep by new lines
#include <stdio.h>
char strcop(char *curr, char *bigg);
main()
{
int cur=0, big=0,d, count=0;
char curr[100], bigg[100];
while((d=getchar())!=EOF)
{
// Read the line till a new line is encountered
if (d!= '\n')
{
curr[count] = d;
count++;
cur++;
}
// compare with the big line after a new line is encountered and store the new big line
else
{ // comparing the length of lines
if(cur>big)
{
big = cur;
strcop(curr, bigg);
}
cur = count = 0;
}
}
for (int k =0 ; k<big; k++)
{
printf("%c", bigg[k]);
}
printf("\n");
//for (int k =0 ; k<big; k++)
//{
//printf("%c", curr[k]);
//}
//printf("count %d", count);
//printf("big %d", big);
//printf("cur %d", cur);
}
char strcop(char *curr, char *bigg)
{
while(*curr)
{
*(bigg++) = *(curr++);
}
}
我正在阅读 K &R 的书,第 1.9 节。从给定的一组行中打印最长行的程序给出为
#include <stdio.h>
#define MAXLINE 1000 /* maximum input line length */
int getline(char line[], int maxline);
void copy(char to[], char from[]);
/* print the longest input line */
main()
{
int len; /* current line length */
int max; /* maximum length seen so far */
char line[MAXLINE]; /* current input line */
char longest[MAXLINE]; /* longest line saved here */
max = 0;
while ((len = getline(line, MAXLINE)) > 0)
if (len > max) {
max = len;
copy(longest, line);
}
if (max > 0) /* there was a line */
printf("%s", longest);
return 0;
}
/* getline: read a line into s, return length */
int getline(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] = '[=10=]';
return i;
}
/* copy: copy 'from' into 'to'; assume to is big enough */
void copy(char to[], char from[])
{
int i;
i = 0;
while ((to[i] = from[i]) != '[=10=]')
++i;
}
getline
函数有问题。如果输入行的第 lim-1
个字符不是换行符,则 getline
将在第 lim-1
处插入 '[=15=]'
,而第 lim
处未使用(或空的)。
我通过将 getline
修改为
int getline(char s[], int lim)
{
int c, i;
for (i=0; i < lim-1 && (c=getchar())!=EOF && c!='\n'; ++i)
s[i] = c;
s[i] = c;
s[i+1] = '[=11=]';
return i;
}
我的 getline
版本正确吗?
如果是,哪个版本在 运行 时间最快,需要最少的内存,使用最少的内存?
由于这个问题还没有关闭也没有转移到其他站点...我会在这里回答。
关于允许在 C 缓冲区中写入的位置(在什么索引处)的部分已在 related question, but I see have to repeat it here: you're only allowed to write at indices from 0 to lim-1
, inclusively. You are not allowed to write to the lim
index, in the sense that the behavior is undefined; what will happen in practice depends on whatever you happen to overflow to in memory. (You may also want to look at https://security.stackexchange.com/questions/53878/how-to-explain-buffer-overflow-to-a-layman 中得到回答;尽管它在技术上不正确,但那里的最佳答案应该给你正确的直觉,为什么溢出是一个问题。)
在这个问题的 getline
的任一版本中,for
循环可以在 i==lim-1
时退出。在您的 getline
版本(您问题中的那个 lower/later )中,您然后无条件地写入 s[i+1]
,这意味着您写入 s[lim]
,这是缓冲区溢出(又名缓冲区溢出)。
K&R 的版本有点微妙,因为如果 i==lim-1
在循环结束时,那么 c
不能 是 '\n'
,所以他们的 if (c == '\n') { s[i] = c; ++i; }
块在这种情况下不会执行,所以 i
不会递增等于 lim
,这使得最后一个赋值 s[i]
安全!换句话说,忽略(为了更容易理解)关于 EOF
的部分,&&
的 postcondition for the for
loop is that (i==lim-1 && c!='\n' )||(i<lim-1 && c=='\n')
. To see why this is the case, you need to understand the short-circuit behavior:当 i==lim-1
时,[ 的旧值=19=]将通过不执行(短路)c=getchar()
来保持;此外,先前获得的 c
保证不会是 \n
,因为在相反的情况下,for
循环会提前一次退出循环,即当 i<lim-1
时。 (for
循环的完整后置条件,不忽略 EOF
是 (i==lim-1 && c!='\n' && c!=EOF)||(i<lim-1 && c==EOF)||(i<lim-1 && c=='\n')
。)
// Program to print the length and content of the longest line in a text sep by new lines
#include <stdio.h>
char strcop(char *curr, char *bigg);
main()
{
int cur=0, big=0,d, count=0;
char curr[100], bigg[100];
while((d=getchar())!=EOF)
{
// Read the line till a new line is encountered
if (d!= '\n')
{
curr[count] = d;
count++;
cur++;
}
// compare with the big line after a new line is encountered and store the new big line
else
{ // comparing the length of lines
if(cur>big)
{
big = cur;
strcop(curr, bigg);
}
cur = count = 0;
}
}
for (int k =0 ; k<big; k++)
{
printf("%c", bigg[k]);
}
printf("\n");
//for (int k =0 ; k<big; k++)
//{
//printf("%c", curr[k]);
//}
//printf("count %d", count);
//printf("big %d", big);
//printf("cur %d", cur);
}
char strcop(char *curr, char *bigg)
{
while(*curr)
{
*(bigg++) = *(curr++);
}
}