C语言:从文本文件中读取时如何忽略回车和换行?

时间:2015-12-11 15:28:20

标签: c carriage-return linefeed

我有两个关于C语言的问题。假设我有一个带有这些前缀值的文本文件:

apple
orange
pear
grapes
#

我可以按字符打印出这个字符,这是我想要的,但打印输出包括回车和换行,但我希望打印输出为     applepearorangegrapes#

第二个问题我试图让我的程序以一种读取#的方式停止阅读。这是我的代码示例:

#include <stdio.h>
#include <string.h>
#define size 210

int main()
{
    int i;
    char info[size];

    char stop;
    stop = '#';

    for (i = 0; i<size; i++)
    {
        scanf ("%c", &info[i]);
        while (info[i] != stop);
        {
            printf ("%c", info[i]);
        }
    }
    return 0;
}

此代码似乎无限运行。如果我尝试使用解除引用info[i] while (* info[i] != stop); 我明白了

error: invalid type argument of unary ‘*’ (have ‘int’)
 while (*info[i] != stop);

有没有人可以帮我解决这两个问题?

6 个答案:

答案 0 :(得分:2)

无限问题是你的循环:

while (info[i] != stop);

请注意,分号是循环的主体。一旦开始循环,每次执行循环时都没有任何变化来停止它。您应该将while更改为if并丢失分号。

然后你的问题是你没有从scanf()检测到EOF;始终检查scanf()的返回值。通常,您使用:

if (scanf("%c", &info[i]) != 1)
    break;

但是,除非在EOF中%c将返回1,否则您可以将此1替换为EOF,但最好是学习安全(正确)方式并使用1

关于不打印CR和LF,请在打印前进行测试:

if (info[i] != '\n' && info[i] != '\r')

考虑使用getchar()putchar()代替scanf()printf()。并在最后输出换行符。

#include <stdio.h>
#define size 210

int main(void)
{
    int i;                     
    char info[size];
    char stop = '#';

    for (i = 0; i < size; i++)
    {
        if (scanf("%c", &info[i]) != 1 || info[i] == stop)
            break;
        if (info[i] != '\n' && info[i] != '\r')
            printf("%c", info[i]);
    }
    putchar('\n');
    return 0; 
}

请注意,这不会终止info字符串;你必须循环到size - 1并在结尾处添加空值。即使文件较长,使用该字符串也是安全的。另请注意,即使输出没有,info字符串也包含换行符和回车符。你必须重新编码循环来处理它。读取输入字符,如果它不是换行符或回车符,则只将其添加到info

如果要在停止前打印停止字符,可以使用:

#include <stdio.h>
#define size 210

int main(void)
{
    int i;                     
    char info[size];
    char stop = '#';

    for (i = 0; i < size; i++)
    {
        if (scanf("%c", &info[i]) != 1)
            break;
        if (info[i] != '\n' && info[i] != '\r')
            printf("%c", info[i]);
        if (info[i] == stop)
            break;
    }
    putchar('\n');
    return 0; 
}

或者,因为你在循环之后没有使用info,你可以简化它(省略输出中的停止字符):

#include <stdio.h>

int main(void)
{
    int i;                     
    int c;
    char stop = '#';

    while ((c = getchar()) != EOF && c != stop)
    {
        if (c != '\n' && c != '\r')
            putchar(c);
    }
    if (c == stop)
        putchar(c);
    putchar('\n');
    return 0; 
}

答案 1 :(得分:1)

使用getchar()isalpha()分别从标准输入读取字符并测试它是否为字母。

不要只使用for循环大小,因为你的输入可能小于。

由于{for循环中存在while循环,代码会运行,因为info[i]在循环之间不会发生变化,因此永远不会结束。

例如:

#include <stdio.h>
#include <ctype.h>
#define SIZE 210

int main()
{
    int i;                     
    char info[SIZE];           

    char stop, dataread;
    stop = '#';

    dataread = getchar();
    while (i<SIZE && dataread != EOF)
    {
        if (isalpha(dataread) || dataread == '#')
        {
           info[i++] = dataread;
           putchar(dataread);
        }
        if (dataread == '#')
          break;
        dataread = getchar();
    }
    return 0; 
}

答案 2 :(得分:0)

  

打印输出包括回车和换行,但我希望打印输出为applepearorangegrapes#

如果要忽略所有“空格”字符(空格,制表符,回车符,换行符等),包括单词之前,之内,之间和之后,则可以执行以下操作:

int result = scanf (" %c", &info[i]);

与大多数scanf()字段描述符不同,%c不会忽略前导空格,但在格式字符串中放置显式空格会导致跳过任何零个或多个空白字符的运行。

您还应该确保检查函数的返回值,该值告诉您匹配和分配了多少字段,并指示是否已到达文件末尾或发生I / O错误。在这种特殊情况下,如果scanf()没有返回1,则表示EOF或I / O错误。在任何一种情况下,你都不能依赖于从stdin读取任何东西,所以你应该摆脱循环。

  

我正试图以这样的方式制作我的节目,一旦它读到#

就可以停止阅读

然后在检测并打印#之后,必须突破外部循环。你的内部while循环不会这样做,并且实际上将始终执行零或无限次迭代,因为循环条件的真实性不会被该循环体中的任何东西改变。也许不是你想要的while循环

    printf ("%c", info[i]);
    if (info[i] == stop) {
        break;  /* break out of the outer (now only) loop */
    }

答案 3 :(得分:0)

您的嵌套循环逻辑不正确。你不需要嵌套循环。

首先,要读取数组中的所有字符,直到stop字符为止,如果您坚持使用fgetc

for (i = 0; i<size; i++)
{   scanf ("%c", &info[i]);
    if(info[i] == stop)
    {   info[i] = '\0'; // Null-terminate the string
        break;
    }
}

现在要过滤掉换行符,请添加其他测试:

for (i = 0; i<size; i++)
{   scanf ("%c", &info[i]);
    if(info[i] == stop)
    {   info[i] = '\0'; // Null-terminate your string
        break;
    }
    else if(info[i] == '\r' || info[i] == '\n')
        i--; // rollback one character
}

答案 4 :(得分:0)

根据描述,您的程序可以简化很多。

#include <stdio.h>

int main()
{
   int c;
   char stop = '#';

   while ( (c = getchar()) != EOF )
   {
      if ( c != '\r' && c != '\n' )
      {
         putchar(c);
      }
      if ( c == stop )
      {
         break;
      }
   }

   return 0; 
}

答案 5 :(得分:0)

请参阅此注释的C代码,以获取此任务的完整小型控制台应用程序。

#include <stdio.h>

#define SIZE 210

int main (int argc, char* argv[])
{
    int   iCharacter;
    FILE* pTextFile;
    char  msInfo[SIZE+1];
    unsigned int uInfoIndex;

    if(argc < 2)
    {
        puts("\nPlease specify a file name as parameter.\n");
        return 3;
    }

    /* Open the file with name specified on command line for reading in binary mode. */
    pTextFile = fopen(argv[1],"rb");

    /* Was this successful? */
    if(pTextFile == NULL)
    {
        printf("Can't open file \"%s\" for reading.\n",argv[1]);
        return 1;
    }

    /* Read from file character by character until character # read or
       end of file reached or an error occurred while reading from file. */
    uInfoIndex = 0;
    do
    {
        iCharacter = fgetc(pTextFile);

        /* Has an error occurred while reading data from file? */
        if(ferror(pTextFile))
        {
            printf("\n\nError on reading data from file \"%s\"\n",argv[1]);
            fclose(pTextFile);
            return 2;
        }

        /* Is end of file reached? */
        if(feof(pTextFile))
        {
            break;
        }

        /* Copy the character into buffer if not being a carriage return or line-feed. */
        if((iCharacter != '\r') && (iCharacter != '\n'))
        {
            msInfo[uInfoIndex] = (char)iCharacter;
            uInfoIndex++;
        }
    }
    while((iCharacter != '#') && (uInfoIndex < SIZE));
    (void)fclose(pTextFile);

    msInfo[uInfoIndex] = '\0';
    printf("Data read from file %s:\n\n%s\n",argv[1],msInfo);

    return 0;
}