Reputation: 11
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
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
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
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
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
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
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