0

这是一个 C 作业。我不是要求任何人为我做这件事,我只是碰壁了。明天就要交了,不知道怎么办。我是初学者,我的头开始受伤

编写一个 ANSI C 程序,该程序对文本进行格式化,以便它很好地适合给定数量的列。文本格式化程序必须右对齐输入文本文件,以便右边距对齐在一条直线上,但有一个例外。最后一行没有正确对齐。此外,段落不会合并在一起。输出线之间的间距应均匀分布。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define IN 1
#define OUT 0

/*
   This is the start of the main pgoram which originated from the K & R word  counter...
   we comment to understand each part...
 */
int main()
{
    /*
     * This is the pointer to the file object we will be readin in
     * from...
     */
    FILE           *ptr_file;
    char           *outputbuf;

    /*
     * This variable will hold the maximum width of the line we are to
     * output
     */
    int width;
    char eatspace;
    char  c;    /* We read each character invidually */

    int   state = OUT;

    int   nc = 0;   /* This is the total count of all words in the document */
    int   nl = 0;   /* This is the total count of newlines in the document  */
    int   nw = 0;  
    int   lw = 0;   /* Count the total whitespaces spaces per line */
    int   buff_offset = 0; /* Keep track of how many letters we are into the current output line */

    /* Opens a file stream for the .txt file to be read in */
    ptr_file = fopen("hollo_man.txt", "r");
    if ((fopen("hollo_man.txt", "r")) != NULL) {
        /*
         * This loop reads in one character at a time until the end
         * of file
         */

        /* Read the first line to get the width of the output */
        fscanf (ptr_file, "%i", &width); 
        outputbuf = (char*) malloc(width + 1);
        //fscanf(ptr_file, "%c", &eatspace);

        int prev_char_was_space = 0;

        while ((c = fgetc(ptr_file)) != EOF)
        {
            ++nc;
            if (c == '\n' || strlen(outputbuf) == width) 
            {
                outputbuf[buff_offset] = '\0';      
                ++nl;
                //              printf("Saw a newline, newline count is now: %i\n", nl);
                /* Our buffer needs to be ended since we saw a newline */

                for(int i = 0; i < (width - buff_offset); i++)
                {
                    printf(" ");

                }
                printf("%s\n", outputbuf);

                memset(outputbuf, width, '\0');

                buff_offset = 0; 
                prev_char_was_space = 0;

            }

            /* This more verbose check is to see if there is other whitespace */
            else if (isspace(c)) 
            {


                /* We only store one space between words in the output, this allows us to easily and evenly pad with white space later */
                if (!prev_char_was_space)
                {

                    outputbuf[buff_offset] = c;
                    outputbuf[buff_offset + 1] = '\0';                  
                    buff_offset++;                  

                    lw++;
                    prev_char_was_space = 1;
                }   
            }
            else /* This was not a whitespace character so store it in the current line buffer */
            {

                prev_char_was_space = 0; /* Keep track that we didnt have a whitespace for the next iteration */
                outputbuf[buff_offset] = c;
                buff_offset++;
                ++nw;


            }

        } /* End reading each character */

        /* This line should indeed print output to console for now */
        //fprintf(stderr, "ORIG LINE COUNT: %d\nORIG WORD COUNT: %d\nORIG CHAR COUNT: %d\n", nl, lw, nc);
        /* Close our file and clean up */
        fclose(ptr_file);
    }

    return 0;
}

它所做的只是打印出一个空白行。我想我需要另一个缓冲区,但我真的不知道。我将如何打印它,然后用填充空格均匀地间隔单词?我也不确定如何将每一行打印到指定的宽度。任何帮助将不胜感激!

4

2 回答 2

2

双fopen的小问题,应该减少到一个。

您的文件可能具有如下格式:

15
The quick
brown

问题是您的逻辑类似于以下内容:

/* Opens a file stream for the .txt file to be read in */
ptr_file = fopen("hollo_man.txt", "r");
if (/*the file was opened correctly */) {

        Read 'width' from the first word of the file;
        Create a buffer exactly 'width'+1 in size;

        while(get_a_character != EOF) {
            increment_total_character_count;
            if(character_is_newline)
                increment_newline_count;
                insert a '\0' in the output buffer;
                reset the index we're inserting into the output buffer
                prevCharacterIsSpace = false;
            if(character_is_space)
                if(previous_character_NOT_a_space)
                    put_character_in_output_buffer;
                    increment_word_counter;
                    prevCharacterIsSpace = true;
            else
                prevCharacterIsSpace = true;
                put_character_in_output_buffer;
                increment_nw (never used)
        }


        needed_spaces = (width - nc) % lw;
        printf(" %s", outputbuf);

如果输入文件具有上述格式,并且宽度出现在它自己的行上,那么您正在阅读的字符流如下所示:

'15' (read as a unit with the %i)
'\n'
'T'
'h'
...
'w'
'n'
'\n'

您的字符阅读循环将换行符视为第一个字符。它将 null 插入输出缓冲区,将 prevCharacterIsSpace 设置为 false,然后继续。如果你的文件格式与我上面的匹配,你可能想通过在读入 'width' 后立即“吃掉”'\n' 来解决这个问题。

请注意,isspace函数对换行返回 true,所以现在换行被放入输出缓冲区的下一个槽中,并且字计数器递增(如果您在程序底部取消注释 printf,您应该会看到该效果) . if (isspace(c))修复可能只是为了使else if (isspace(c))

另一个问题是您将文件中的每一行都复制到同一个缓冲区中。因此,除了输入的最后一行之外,您无法显示任何内容。您可能需要将打印代码放在if (c == '\n') {块内。这将允许您在阅读时打印每一行。

这里的代码都没有处理打印右对齐文本,但一个简单的解决方案是一个小循环:

for (i = 0; i < (width - buff_offset); i++)
    printf(" ");

在打印输出之前直接插入。

于 2013-02-06T18:06:41.083 回答
2

首先不要调用fopen("hollo_man.txt", "r")两次,检查你的指针if

那么你应该逐字阅读文件:

char words[1024];
char * next_word = words;
while(fscanf(ptr_file, "%s", next_word) {

数一数他们的长度

size_t word_length = strlen(next_word);
next_word += word_length + 1;

当你达到必要的宽度时打印它们:

total_length +=  word_length;
if (total_length > maxColumns) {
     size_t extra_spaces = total_length - word_length - 2;

这有帮助吗?

这是一个完整的解决方案:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void justify(FILE* in, FILE * out, int columns) {
    char words[1024];
    char * next_word = words;

    ssize_t total_length = 0;
    size_t num_words = 0;

    while (fscanf(in, "%s", next_word) == 1) {
        size_t word_length = strlen(next_word);
        next_word += word_length + 1;
        num_words++;
        total_length += word_length;

        if (total_length + num_words > columns) {

            size_t spaces_needed = columns - (total_length - word_length);

            int minspoaces = 1;
            if (num_words > 2) // avoids nasty floating point exception if no two words fit on a line
                minspoaces = spaces_needed / (num_words - 2);


            char * word_print = words;

            size_t chars_printed = fprintf(out, "%s",word_print);
            word_print += strlen(word_print) + 1;
            size_t spaces_printed = 0;
            ssize_t words_to_print = num_words - 2;

            fflush(out);

            while (words_to_print > 0) {
                int spaces_to_print = minspoaces;
                if (((spaces_needed - spaces_printed) % words_to_print) * 2 >= words_to_print) // spreads spaces out along the line
                    spaces_to_print++;
                spaces_printed += spaces_to_print;
                words_to_print--;
                chars_printed += fprintf(out, "%*c%s", spaces_to_print, ' ', word_print);
                word_print += strlen(word_print) + 1;
                fflush(out);
            }
            fprintf(out, "\n");

            memmove(words, word_print, (total_length = strlen(word_print)) + 1);
            num_words = 1;
            next_word = words + total_length + 1;
        }

    }

    char * word_print = words;
    while (word_print != next_word) {
        word_print += fprintf(out, "%s ", word_print);
    }

    fprintf(out, "\n");
}

int main(int argc, char ** argv) {

    int columns = atoi(argv[1]);

    FILE * in = stdin;

    if (argc >= 3 && argv[2]) {
        in = fopen(argv[2], "r");
        if (!in) {
            perror("fopen");
            return -1;
        }
    }

    justify(in, stdout, columns);

}
于 2013-02-06T17:42:54.060 回答