Leslie Soon
Leslie Soon

Reputation: 11

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

I have 2 questions with regards to C language. Let's say I have a text file with these prefixed values:

apple
orange
pear
grapes
#

I am able to print this out character by character which is what I wanted, but the printout includes carriage return and line feed, but I wanted the printout to be applepearorangegrapes#

Second question I'm trying to make my program in such a way that I can stop reading once it reads #. Here's an example of my code:

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

This code seems to run infinitely. And if I try dereferencing info[i] by using while (* info[i] != stop); I get this

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

Are there anyone out there who can help me with these 2 questions?

Upvotes: 1

Views: 5709

Answers (6)

Mofi
Mofi

Reputation: 49167

See this commented C code for a complete small console application for this task.

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

Upvotes: 0

Jonathan Leffler
Jonathan Leffler

Reputation: 754920

The infinity problem is your loop:

while (info[i] != stop);

Note that the semicolon is the body of the loop. There's nothing changing on each execution of the loop to stop it once it starts looping. You should change while to if and lose the semicolon.

Then your problem is that you don't detect EOF from scanf(); always check the return value from scanf(). Normally, you'd use:

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

but given that %c will return 1 except at EOF, you could, this time, replace 1 with EOF, but it would be better to learn the safe (correct) way and use 1.

As to not printing CR and LF, test before printing:

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

Consider using getchar() and putchar() instead of scanf() and printf(). And output a newline at the end.

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

Note that this does not null terminate the info string; you'd have to loop to size - 1 and add the null at the end. It would then be safe to use the string even if the file was longer. Also note that the info string contains newlines and carriage returns even if the output does not. You have to recode the loop a bit to handle that. Read the input character and only add it to info if it is not newline or carriage return.

If you want to print the stop character before stopping, you can use:

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

Or, since you don't use info after the loop, you could simplify that (omitting the stop character from the output):

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

Upvotes: 2

R Sahu
R Sahu

Reputation: 206717

Based on the description, your program can be simplified a lot.

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

Upvotes: 0

A.S.H
A.S.H

Reputation: 29352

Your nested loop logic is not correct. You dont need nested loops here.

First, to read all the characters in your array until the stop character, and if you insist on using fgetc,

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

Now to filter out line-feeds, add an additional test:

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
}

Upvotes: 0

John Bollinger
John Bollinger

Reputation: 181499

the printout includes carriage return and line feed, but I wanted the printout to be applepearorangegrapes#

If you want to ignore all "whitespace" characters (spaces, tabs, carriage returns, line feed, and more), including before, within, between, and after your words, then you can do this:

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

Unlike most scanf() field descriptors, %c does not ignore leading whitespace, but putting explicit whitespace in the format string will cause any run of zero or more whitespace characters to be skipped.

You should also be sure to check the function's return value, which tells you how many fields were matched and assigned, and which indicates whether the end of the file was reached or an I/O error occurred. In this particular case, if scanf() does not return 1 then that signals either EOF or an I/O error. In either case you cannot rely on reading anything further from stdin, so you should break out of the loop.

I'm trying to make my program in such a way that i can stop reading once it reads #

Then after you detect and print the #, you must break out of the outer loop. Your inner while loop does not do this, and in fact will always perform either zero or an unbounded number of iterations, because truth of the loop condition is not altered by anything in the body of that loop. Perhaps instead of the while loop you want

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

Upvotes: 0

mcleod_ideafix
mcleod_ideafix

Reputation: 11438

Use getchar() and isalpha() to respectively read a character from standard input and test if it is a letter.

Don't use just a for loop up to size, because your input could be less than that.

The code runs endesly because of the while loop you have inside the for loop, which never ends, as info[i] doesn't change between loops.

For example:

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

Upvotes: 1

Related Questions