繁体   English   中英

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

[英]C language: How do I ignore carriage return and line feed when reading from text file?

我有两个关于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;
}

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

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

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

无限问题是你的循环:

while (info[i] != stop);

请注意,分号是循环的主体。 一旦开始循环,循环的每次执行都没有任何变化来阻止它。 你应该改变whileif和失去了分号。

那你的问题是你没有从scanf()检测到EOF; 总是检查scanf()的返回值。 通常,你会使用:

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

但鉴于除了EOF之外%c将返回1,这次你可以用EOF替换1 ,但是学习安全(正确)方法并使用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; 
}

请注意,这不会使null终止info字符串; 你必须循环到size - 1并在结尾添加null。 即使文件较长,使用该字符串也是安全的。 另请注意,即使输出没有, 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; 
}

使用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; 
}

打印输出包括回车和换行,但我希望打印输出为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 */
    }

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

首先,要读取数组中的所有字符,直到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
}

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

#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; 
}

有关此任务的完整小型控制台应用程序,请参阅此注释的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;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM