[英]Kernighan and Ritchie C exercise 1-22 (fold long input lines)
我正在嘗試在 K&R C-book 中進行有關折線的練習,但我無法繼續前進。
特別是,我不知道如何處理必須剪切的行內的空格。 練習如下:
“編寫一個程序,在輸入的第 n 列之前出現的最后一個非空白字符之后,將長輸入行''折疊'' 成兩個或更多個較短的行。確保您的程序對很長的行執行一些智能操作,並且如果指定列之前沒有空格或制表符。”
我已經實現的代碼如下:
#include <stdio.h>
#define CUT 6
int main()
{
int c, i = 0;
while ((c = getchar()) != EOF) {
if (i == CUT) {
printf(",");
putchar(c);
i = 1;
} else {
putchar(c);
i++;
}
if (c == '\n')
i = 0;
}
}
代碼檢查輸入中的字符,同時使用計數器檢查它是否到達需要剪切的行。 例如,對於LoremIpsumissimplydummytex
行,它將給出LoremI,psumis,simply,dummyt,ext
。
main 末尾的條件 if (c=='\\n'{ i=0;} 用於在每個換行符處重新初始化用於 CUT 的計數器 i。
問題在於空格處理:例如,我認為對於Lorem Ipsum
(有許多空格)這一行,應該實施程序以打印Lorem,Ipsum
。 但我不明白如何編寫必要的代碼來實現這個解決方案。
對不起,帖子的長度,並提前致謝。
編輯:______________________________________________________
我在代碼中添加了一些條件以處理多個空格。 想問一下這是否可以被認為是正確的解決方案:
#include <stdio.h>
#define CUT 6
int main()
{
int c,i=0;
while ((c=getchar()) !=EOF){
if (i==CUT){
if (c!=' '){
putchar(c);
} else {
printf("\n");
i=1;}
} else{
putchar(c);
i++;
}
}
}
使用此代碼,一旦到達閾值 CUT,如果遇到正常字符 [非空白],則只需將其添加到新行進行打印,否則將打印“\\n”並將計數器重新初始化為 1。
如果要將長行拆分為多行,如任務描述中所述,則在遇到剪切閾值時必須打印'\\n'
而不是','
。
您不應該在輸出流上打印字符,直到您知道它應該打印在當前行還是下一行。 因此,您必須存儲所有字符,直到您知道它必須打印在哪一行為止。
您可能希望使用函數isblank
來確定字符是空格還是制表符。
根據社區關於作業問題的指導方針,我目前不會提供問題的完整解決方案。 但是,如果需要,我會提供進一步的提示。
更新1:
您最近編輯的代碼不正確。 根據任務描述,您應該在閾值之前的最后一個空白處拆分行,而不是在閾值之后的第一個空白處。
大多數情況下,當您遇到一個新字符時,您無法知道它是屬於當前行還是新行。 因此,正如我在回答中所述,您必須記住所有字符,直到您知道它們屬於哪一行。 在知道字符屬於當前行還是下一行之前,不應打印該字符。
如果您使用fgets
而不是getchar
您可能會發現更容易解決這個問題。 但是,這個問題也可以用getchar
解決。
更新 2:
由於您似乎已經為這個問題苦苦掙扎了好幾天,我現在提供我對問題的解決方案:
這是我使用getchar
解決方案:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <assert.h>
#define CUT 10
int main( void )
{
//this memory buffer will hold the remembered
//line contents
char line[CUT+1];
//current index
int i = 0;
//whether a blank character has been encountered in
//the current line
bool found_blank = false;
//index of the last encountered blank character
int blank_index;
//this will store the current character
int c;
//this loop will read one character per loop iteration
while ( (c=getchar()) != EOF )
{
//if we encounter the end of the line, flush the
//buffer and start a new line
if ( c == '\n' )
{
line[i] = '\0';
puts( line );
i = 0;
found_blank = false;
continue;
}
//check if new character is blank and, if it is, then
//remember the index
if ( isblank(c) )
{
blank_index = i;
found_blank = true;
}
//write new character into array
line[i] = c;
if ( i == CUT - 1 )
{
if ( !found_blank )
{
//flush buffer
line[CUT] = '\0';
puts( line );
//reset line
i = 0;
found_blank = false;
continue;
}
else // found_blank == true
{
//remember character that is going to be overwritten
char temp = line[blank_index+1];
//output everything up to and including the last blank
line[blank_index+1] = '\0';
puts( line );
//move unwritten characters to start of next line
i = CUT - 1 - blank_index;
line[0] = temp;
memmove( line + 1, line+blank_index+2, i );
found_blank = false;
continue;
}
}
i++;
}
//check stream for error
if ( ferror(stdin) )
{
fprintf( stderr, "error reading input!\n" );
exit( EXIT_FAILURE );
}
//if we reach this, then we must have encountered
//end-of-file
assert( feof( stdin ) );
//flush buffer
line[i] = '\0';
puts( line );
}
這是我使用fgets
解決方案:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <assert.h>
#define CUT 10
int main( void )
{
char line[CUT+2];
size_t leftovers = 0;
//in every iteration of the loop, we write one line of output
for (;;)
{
size_t blank_index;
bool found_blank = false;
if ( fgets( line + leftovers, sizeof line - leftovers, stdin ) == NULL )
{
//print all leftovers
line[leftovers] = '\0';
printf( "%s\n", line );
break;
}
size_t len = strlen( line );
//this check is probably not necessary
assert( len != 0 );
if ( line[len-1] == '\n' )
{
//we read a complete line, so print it
printf( "%s", line );
leftovers = 0;
continue;
}
//if we reach this, then input line was not read in
//completely, or we are dealing with the last line before
//end-of-file or input failure
//find last blank
for ( size_t i = 0; line[i] != '\0'; i++ )
{
if ( isblank( (unsigned char)line[i] ) )
{
found_blank = true;
blank_index = i;
}
}
if ( !found_blank )
{
if ( len <= CUT )
{
if ( ferror(stdin) )
{
fprintf( stderr, "error reading input!\n" );
exit( EXIT_FAILURE );
}
//we should only reach this if end-of-file was
//encountered in the middle of a line
assert( feof(stdin) );
printf( "%s\n", line );
break;
}
//remember last character
char temp = line[len-1];
line[len-1] = '\n';
printf( "%s", line );
line[0] = temp;
leftovers = 1;
}
else
{
//remember character after last blank
char temp = line[blank_index+1];
//replace character after last blank with terminator
line[blank_index+1] = '\0';
//print line up to and including last blank
printf( "%s\n", line );
if ( temp != '\0' )
{
//move unprinted characters to start of next line
line[0] = temp;
leftovers = len - blank_index - 1;
memmove( line + 1, line + blank_index + 2, leftovers - 1);
}
else
{
leftovers = 0;
}
}
}
}
看來我最初使用fgets
而不是getchar
建議並不是很好,因為結果證明fgets
解決方案比getchar
解決方案稍微復雜一些。
這是兩個程序的一些示例輸入和輸出(兩個程序的行為方式相同):
樣本輸入:
This is a line with several words.
Thisisalinewithonelongword.
示例輸出:
This is a
line with
several
words.
Thisisalin
ewithonelo
ngword.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.