Write a program to "fold" long input lines into two or more shorter lines after the last non-blank character that occurs before the n-th column of input. Make sure your program does something intelligent with very long lines, and if there are no blanks or tabs before the specified column.
我决定遵循的算法如下:
- 如果输入行的长度 < maxcol(必须折叠的列),则按原样打印该行。
- 如果没有,从 maxcol 中,我检查它的左边,右边找到最接近的非空格字符,并将它们保存为“第一个”和“最后一个”。然后,我打印从 line[0] 到 line[first] 的字符数组,然后打印数组的其余部分,从 line[last] 到 line[len] 成为新的行数组。
这是我的代码:
#include <stdio.h>
#define MAXCOL 5
int getline1(char line[]);
int main()
{
char line[1000];
int len, i, j, first, last;
len = getline1(line);
while (len > 0) {
if (len < MAXCOL) {
printf("%s\n", line);
break;
}
else {
for (i = MAXCOL - 1; i >= 0; i--) {
if (line[i] != ' ') {
first = i;
break;
}
}
for (j = MAXCOL - 1; j <= len; j++) {
if (line[j] != ' ') {
last = j;
break;
}
}
//printf("first %d last %d\n", first, last);
for (i = 0; i <= first; i++)
putchar(line[i]);
putchar('\n');
for (i = 0; i < len - last; i++) {
line[i] = line[last + i];
}
len -= last;
first = last = 0;
}
}
return 0;
}
int getline1(char line[])
{
int c, i = 0;
while ((c = getchar()) != EOF && c != '\n')
line[i++] = c;
if (c == '\n')
line[i++] = '\n';
line[i] = '\0';
return i;
}
问题如下:
- 它不会对很长的行执行智能操作(这很好,因为我可以将其添加为边缘情况)。
- 它不会对选项卡执行任何操作。
- 我无法理解部分输出。
例如,输入:
asd de def deffff
我得到输出:
asd
de
def
defff //Expected until here
//Unexpected lines below
ff
fff
deffff
deffff
deffff
问题 1 - 为什么会打印出意外的行?如何使我的程序/算法更好?
最终,在花了相当长的时间解决这个问题后,我放弃了并决定检查 clc-wiki寻求解决方案。这里的每个程序都不工作,除了一个(其他程序没有工作,因为它们没有涵盖某些边缘情况)。有效的是最大的一个,它对我来说没有任何意义。它没有任何注释,我也无法正确理解变量名称及其代表的含义。但这是 wiki 中唯一有效的程序。
#include <stdio.h>
#define YES 1
#define NO 0
int main(void)
{
int TCOL = 8, ch, co[3], i, COL = 19, tabs[COL - 1];
char bls[COL - 1], bonly = YES;
co[0] = co[1] = co[2] = 0;
while ((ch = getchar()) != EOF)
{
if (ch != '\t') {
++co[0];
++co[2];
}
else {
co[0] = co[0] + (TCOL * (1 + (co[2] / TCOL)) - co[2]);
i = co[2];
co[2] = TCOL + (co[2] / TCOL) * TCOL;
}
if (ch != '\n' && ch != ' ' && ch != '\t')
{
if (co[0] >= COL) {
putchar('\n');
co[0] = 1;
co[1] = 0;
}
else
for (i = co[1]; co[1] > 0; --co[1])
{
if (bls[i - co[1]] == ' ')
putchar(bls[i - co[1]]);
else
for (; tabs[i - co[1]] != 0;)
if (tabs[i - co[1]] > 0) {
putchar(' ');
--tabs[i - co[1]];
}
else {
tabs[i - co[1]] = 0;
putchar(bls[i - co[1]]);
}
}
putchar(ch);
if (bonly == YES)
bonly = NO;
}
else if (ch != '\n')
{
if (co[0] >= COL)
{
if (bonly == NO) {
putchar('\n');
bonly = YES;
}
co[0] = co[1] = 0;
}
else if (bonly == NO) {
bls[co[1]] = ch;
if (ch == '\t') {
if (TCOL * (1 + ((co[0] - (co[2] - i)) / TCOL)) -
(co[0] - (co[2] - i)) == co[2] - i)
tabs[co[1]] = -1;
else
tabs[co[1]] = co[2] - i;
}
++co[1];
}
else
co[0] = co[1] = 0;
}
else {
putchar(ch);
if (bonly == NO)
bonly = YES;
co[0] = co[1] = co[2] = 0;
}
}
return 0;
}
问题 2 - 您能帮我理解这段代码及其工作原理吗?
它解决了我的解决方案的所有问题,并且还通过逐个字符读取来工作,因此看起来更有效。
最佳答案
Question 1 - Why do the unexpected lines print? How do I make my program/algorithm better?
您在输出中得到了意外的行,因为在打印数组后,您没有以空字符 \0
终止新的 line
数组 -
在这里,您将从 last
开始复制字符,直到 len - last
,创建一个新的 line
数组:
for (i = 0; i < len - last; i++) {
line[i] = line[last + i];
}
您已复制字符,但空终止字符仍位于其原始位置。假设输入字符串是:
asd de def deffff
因此,最初 line
数组的内容将是:
"asd de def deffff\n"
^
|
null character is here
现在打印 asd
后,您将从 line
的 last
索引复制字符到 len - last
索引到从 0
索引开始的 line
数组本身。因此,复制 line
数组的内容后将是:
"de def deffff\n deffff\n"
|____ _____|
\/
This is causing the unexpected output
(null character is still at the previous location)
因此,在 for
循环之后,您应该在复制的最后一个字符之后添加空字符,如下所示:
line [len - last] = '\0';
这样,将在 while
循环的下一次迭代中处理的 line
数组的内容将是:
"de def deffff\n"
还有一件事,在 line
数组中,您可以在末尾看到 \n
(换行符)字符。也许你想在处理输入之前删除它,你可以这样做:
line[strcspn(line, "\n")] = 0;
您可以在程序中进行的改进:
1. 您可以做的一项非常明显的改进是在处理输入字符串时使用指向输入字符串的指针。在指针的帮助下,您不需要将数组的其余部分(除了已处理的部分)再次复制到同一个数组,直到程序处理整个输入。将指针初始化为输入字符串的开头,并且在每次迭代中只需将指针移动到适当的位置并从指针指向的位置开始处理。
2. 由于您首先将整个输入放入缓冲区,然后对其进行处理。您可以考虑使用 fgets()
来获取输入。它将更好地控制用户的输入。
3. 添加对 line
数组溢出的检查,以防输入很长。使用fgets()
,您可以指定要从输入流复制到line
数组的最大字符数。
Question 2 - Can you help me make sense of this code and how it works?
该程序非常简单,尝试至少自己理解一次。使用调试器或拿笔和纸,针对小尺寸输入试运行一次并检查输出。增加输入大小并添加一些变体,例如多个空格字符,并检查程序代码路径和输出。这样你就很容易理解了。
关于c - C 中每第 n 列(K&R 1-22)折叠输入行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51435943/