簡體   English   中英

Kernighan 和 Ritchie C 練習 1-22(折疊長輸入行)

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM