如何在C中遇到空行之前输入新行

时间:2017-07-22 22:54:34

标签: c

这是我的代码,我试图创建一个使用函数计算字符数的程序,然后在遇到空行时确定字符的平均值。该程序假设允许用户输入多行,直到遇到空行,但我似乎无法。

#include <stdio.h>
#include <Windows.h>

int main()
{
    char str[1000];
    int Digits, Char, SpecialChar, linecount = 0;
    int counter;
    int total;
    int average;

    Digits = Char = SpecialChar = 0;

    printf("Please type in your words here: ");
    gets(str);

    for (counter = 0; str[counter] != NULL; counter++)
    {

        if (str[counter] >= '0' && str[counter] <= '9')
            Digits++;
        else if ((str[counter] >= 'A' && str[counter] <= 'Z') || (str[counter] >= 'a' && str[counter] <= 'z'))
            Char++;
        else
            SpecialChar++;    
    }

    while (str[counter] != '\n')
    {
        if (str[counter] = '\n')
        {
            linecount ++;
        }
    }

    total = Digits + Char + SpecialChar;
    average = total / linecount;

    printf("\nDigits: %d \nCharacters: %d \nSpecial Characters: %d \nLine: %d", Digits, Char, SpecialChar, linecount);
    printf("\nTotal no. of characters = %d", total);
    printf("\nAverage no. of characters = %d", average);

    Sleep(5000000);
    return 0;
}

3 个答案:

答案 0 :(得分:0)

据我所知,函数get在“\ n”后被中断。另外,使用fgets你必须注意字符串上的'\ 0'加法。这意味着

  

该程序假设允许用户输入多行,直到遇到空行但我似乎无法。

使用这种方式永远无法完成

。因为gets不是推荐的函数,所以我以你可能正在搜索的方式编辑了一些代码。

在您阅读此代码

之前,我发现它可能是一个逻辑错误
  

for(counter = 0; str [counter]!= NULL; counter ++)

这看起来很奇怪,因为fgets将始终记录“\ n”字符。那么,下一个条件

  

if(str [counter] ='\ n')

永远不会成真

我在代码中看到了其他一些错误,但不是主要错误。所以,我认为这个建议足以指定他们

while (fgets(str, 1000, stdin) && str[0] != '\n'){ //I dont know if checking the first element of the string is redundancy, 
//because, the I think the fgets function will return NULL if you just press enter, as the first character

    for (counter = 0; str[counter] != '\n'; counter++{

        if (str[counter] >= '0' && str[counter] <= '9')
            Digits++;
        else if ((str[counter] >= 'A' && str[counter] <= 'Z') || (str[counter] >= 'a' && str[counter] <= 'z'))
            Char++;
        else
            SpecialChar++;    
    }

    linecount ++;  //new line is someting that you will always reach, so, 
                  //there is no reason for any condition

}

答案 1 :(得分:0)

解决方案如下:

#include <stdio.h>
#include <Windows.h>

int main()
{
    char str[1000];
    int Digits, Char, SpecialChar, linecount = 0;
    int counter;
    int total;
    int average;
    int flag = 1;

    Digits = Char = SpecialChar = 0;

    printf("Please type in your words here: ");

    while(flag == 1)
    {
        gets(str);
        if (str[0] == NULL || str[0] == '\n') 
            {
                flag = 0;
                break;
            }
        for (counter = 0; str[counter] != NULL; counter++)
        {

            if (str[counter] >= '0' && str[counter] <= '9')
                Digits++;
            else if ((str[counter] >= 'A' && str[counter] <= 'Z') || (str[counter] >= 'a' && str[counter] <= 'z'))
                Char++;
            else
                SpecialChar++;   
        }
        linecount ++;
    }




    total = Digits + Char + SpecialChar;
    average = total / linecount;

    printf("\nDigits: %d \nCharacters: %d \nSpecial Characters: %d \nLine: %d", Digits, Char, SpecialChar, linecount);
    printf("\nTotal no. of characters = %d", total);
    printf("\nAverage no. of characters = %d", average);

    Sleep(5000000);
    return 0;
}

答案 2 :(得分:0)

gets()函数不安全,极易受缓冲区溢出的影响。切勿使用此功能。更好的选择是fgets(),尽管非标准(但广泛可用)的POSIX getline()函数也是一个不错的选择。

fgets()gets()都会获取一行输入,但gets()会丢弃换行符,而fgets()会保留它并将其存储在输入缓冲区中(如果有的话)是房间)。这意味着您可能需要在使用fgets()获取输入行后删除换行符。这也意味着当用户只需按 ENTER 时,输入缓冲区只包含一个\n字符,后跟一个\0 null终止符; fgets()始终为null - 终止输入缓冲区。

要读取多行用户输入,仅在用户按 ENTER 时停止,应在循环中调用fgets()。一种方法是使用for(;;) {}循环结构,它永远不会终止(相当于while(1) {})。如果输入行中的第一个字符是\n字符,则break;语句退出循环。

已发布代码的注释

发布的代码将输入字符与字符常量进行比较,以确定输入是数字,字母还是其他。通过使用ctype.h中的标准库函数,可以实现更好,更便携。在这里使用库函数意味着代码不需要显式考虑当前的语言环境或字符编码(可能不是ASCII或UTF-8)。

发布的代码包含以下行:

for (counter = 0; str[counter] != NULL; counter++) {}

请注意,NULL是空指针常量,相当于(void *) 0,但不等同于0。此循环的目标似乎是迭代字符串,在到达空终止符(\0)时终止。因此,控制表达式应该改变:

for (counter = 0; str[counter] != '\0'; counter++) {}

此外,发布代码中此循环的目的还不清楚:

while (str[counter] != '\n')
{
    if (str[counter] = '\n')
    {
        linecount ++;
    }
}

如果str[counter]是换行符,则不输入循环;否则循环体中的if语句会将'\n'分配给str[counter],评估为true并递增linecount。在下一次迭代str[counter] == '\n'中,循环终止。在上一个循环之后(控制表达式中NULL更改为'\0'),counter\0str个字符的索引,因此此循环用换行符替换null终止符,使str不再是一个字符串。如果代码稍后尝试将str视为字符串,则会导致未定义的行为。

如果第if (str[counter] = '\n')行是拼写错误,意为if (str[counter] == '\n'),则输入后这是一个无限循环。

示例程序

以下是使用fgets()获取用户输入的已发布代码的大量修改,以及用于对输入字符进行分类的标准库函数。

fgets()函数在发生错误时返回空指针,因此会以最简单的方式检查和处理。输入存储在str[]缓冲区数组中后,检查第一个字符;如果它是\n,则用户输入一个空行(可能:见下一段),然后终止循环。否则,下一步是查看输入行是否包含换行符。此处使用strchr()(来自string.h)函数。如果未找到\n,则返回空指针,否则返回指向\n字符的指针。这用于在\n上覆盖\0,有效删除换行符。然后linecount递增。因此,只有在输入中遇到换行符时,行计数器才会递增。

请注意,当输入对输入缓冲区而言太大时,至少换行符将保留在输入流中,等待下一个I / O函数调用。可能只有换行符保留在输入流中,因此在下一个循环迭代中,缓冲区中的第一个字符为\n,由此程序将其解释为空行。如果输入可能大于缓冲区分配,则需要更精细的处理这种情况。一种解决方案是使用标志来指示是否正在读取行的开始。此处,line_start初始化为1,每当1递增时设置为linecount,并且每当换行符不<时,设置为0 / em>在输入缓冲区中找到。为了使换行指示空行输入,line_start必须设置为1,并且输入缓冲区中的第一个字符必须是\n个字符。通过此修改,程序将可靠地读取输入行,甚至比分配的1000个字符更长。你可以通过缩小str[]的分配来测试它;试试char str[2];

这是完整的程序:

#include <stdio.h>
#include <ctype.h>            // for isdigit(), isalpha()
#include <string.h>           // for strchr()

int main(void)
{
    char str[1000];
    int Digits = 0;
    int Char = 0;
    int SpecialChar = 0;
    int linecount = 0;
    int counter;
    int total;
    int average;

    puts("Please type in your words here:");

    int line_start = 1;
    for (;;) {
        if (fgets(str, sizeof str, stdin) == NULL) {
            /* Handle error */
            fprintf(stdin, "I/O error\n");
            return 1;
        }

        /* Terminate loop on empty line */
        if (line_start && str[0] == '\n') {
            break;
        }

        /* If newline present, remove and increment linecount */
        char *cptr = strchr(str, '\n');
        if (cptr != NULL) {
            *cptr = '\0';
            ++linecount;
            line_start = 1;
        } else {
            line_start = 0;         // complete line not read
        }

        /* update character counters */
        for (counter = 0; str[counter] != '\0'; counter++) {
            unsigned char uc = str[counter];
            if (isdigit(uc)) {
                Digits++;
            } else if (isalpha(uc)) {
                Char++;
            } else {
                SpecialChar++;
            }
        }
    }

    total = Digits + Char + SpecialChar;
    average = total / linecount;  // integer division

    printf("Digits: %d \nCharacters: %d \nSpecial Characters: %d \nLine: %d\n",
           Digits, Char, SpecialChar, linecount);
    printf("Total no. of characters = %d\n", total);
    printf("Average no. of characters = %d\n", average);

    return 0;
}