I'm trying to count the number of characters the user has as an input using a while loop, but for some reason the output counts always one more than the expected value. ( I'm a newbie so please don't hate me for it.)
Here's my code:
#include <stdio.h>
#include <string.h>
int main() {
int len,i;
char sttr[29];
fgets(sttr,29,stdin);
len = 0;
i=0;
while(sttr[i] != '\0'){
if (sttr[i] != ' '){
len++;
}
i++;
}
printf("%d\n",len);
}
The fgets function reads in a line of text and stores that text, including the newline if there's room for it.
So the output is one more because of the newline.
I'm a newbie so
it should be worth mentioning that your while loop finishing is completely relying upon the fact that the null character \0 is found in sttr[].
Because you use the function fgets() it will automatically append a \0 character after the input is stored in sttr[] so it is likely to never be a problem, but...
realize under different circumstances if you were to parse a string like that there is likely to be a much greater chance that the while loop could become an infinite loop because it never found a \0 character to terminate.
so something like this for example would be more robust:
don't assume a null character will always be present in your string
# include <stdio.h>
# include <string.h>
# define MAX 29
int main ( void )
{
int len, i;
char sttr[MAX];
fgets( sttr, MAX, stdin );
len = 0;
i = 0;
/* make sure i does not index past sttr[MAX] */
while ( ( sttr[i] != '\0') && ( i < MAX ) )
{
if ( sttr[i] != ' ' )
{
len++;
}
i++;
}
printf("%d\n",len);
return 0;
}
Related
I am trying to do the exercise about the line folding in the K&R C-book, but I can't go much forward.
In particular, I do not knwo how to handle blank spaces inside the line i have to cut. The exercise is the following:
"Write a program to ''fold'' long input lines into two or more shorter lines after the last non-blank character that occurs before the n-th column of input. Make sure your program does something intelligent with very long lines, and if there are no blanks or tabs before the specified column."
The code i have implemented is the following:
#include <stdio.h>
#define CUT 6
int main()
{
int c, i = 0;
while ((c = getchar()) != EOF) {
if (i == CUT) {
printf(",");
putchar(c);
i = 1;
} else {
putchar(c);
i++;
}
if (c == '\n')
i = 0;
}
}
The code check the character in input while using a counter to check once it arrives to the line it needs to cut. For instance, for the line LoremIpsumissimplydummytex it will give LoremI,psumis,simply,dummyt,ext.
The condition if (c=='\n'{ i=0;} at the end of the main is used to reinitialize the counter i, used for the CUT, at every newline.
The problem is with the blank space handling: for instance i think that for the line
Lorem Ipsum (with many blank spaces), the progam should be implemented in order to print Lorem,Ipsum. But I do not understand how to write the necessary code to implement this solution.
Sorry for the length of the post and thanks in advance.
EDIT:______________________________________________________
I added some conditions to the code in order to handle the multiple blank spaces. Wanted to ask if this could be considered the right solution:
#include <stdio.h>
#define CUT 6
int main()
{
int c,i=0;
while ((c=getchar()) !=EOF){
if (i==CUT){
if (c!=' '){
putchar(c);
} else {
printf("\n");
i=1;}
} else{
putchar(c);
i++;
}
}
}
With this code, once reached the treshold CUT, if a normal character [non blank] is encounterd it is simply added to the new line to print, otherwise "\n" is printed and the counter is re-initialized to 1.
If you to split long lines into several lines, as stated in the task description, then you must print '\n' instead of ',' when encountering the cut treshold.
You should not print the character on the output stream until you know whether it should be printed on the current line or the next line. Therefore, you must store all characters until you know which line it must be printed on.
You may want to use the function isblank to determine whether a character is a space or a tab character.
In accordance with the community guidelines on homework questions, I will not provide a full solution to the problem at this time. However, if required, I will provide further hints.
UPDATE 1:
The code in your most recend edit is not correct. According to the task description, you are supposed to split the line at the last blank before the treshold, not at the first blank after the threshold.
Most of the time when you encounter a new character, you cannot know whether it belongs in the current line or in a new line. Therefore, as already stated in my answer, you must remember all characters until you know which line they belong on. You should not print a character before you know whether it belongs on the current line or the next line.
You may find it easier to solve this problem if you use fgets instead of getchar. However, the problem can also be solved with getchar.
UPDATE 2:
Since you appear to be struggling with the problem for several days, I am now providing my solutions to the problem:
Here is my solution which uses getchar:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <assert.h>
#define CUT 10
int main( void )
{
//this memory buffer will hold the remembered
//line contents
char line[CUT+1];
//current index
int i = 0;
//whether a blank character has been encountered in
//the current line
bool found_blank = false;
//index of the last encountered blank character
int blank_index;
//this will store the current character
int c;
//this loop will read one character per loop iteration
while ( (c=getchar()) != EOF )
{
//if we encounter the end of the line, flush the
//buffer and start a new line
if ( c == '\n' )
{
line[i] = '\0';
puts( line );
i = 0;
found_blank = false;
continue;
}
//check if new character is blank and, if it is, then
//remember the index
if ( isblank(c) )
{
blank_index = i;
found_blank = true;
}
//write new character into array
line[i] = c;
if ( i == CUT - 1 )
{
if ( !found_blank )
{
//flush buffer
line[CUT] = '\0';
puts( line );
//reset line
i = 0;
found_blank = false;
continue;
}
else // found_blank == true
{
//remember character that is going to be overwritten
char temp = line[blank_index+1];
//output everything up to and including the last blank
line[blank_index+1] = '\0';
puts( line );
//move unwritten characters to start of next line
i = CUT - 1 - blank_index;
line[0] = temp;
memmove( line + 1, line+blank_index+2, i );
found_blank = false;
continue;
}
}
i++;
}
//check stream for error
if ( ferror(stdin) )
{
fprintf( stderr, "error reading input!\n" );
exit( EXIT_FAILURE );
}
//if we reach this, then we must have encountered
//end-of-file
assert( feof( stdin ) );
//flush buffer
line[i] = '\0';
puts( line );
}
Here is my solution which uses fgets:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <assert.h>
#define CUT 10
int main( void )
{
char line[CUT+2];
size_t leftovers = 0;
//in every iteration of the loop, we write one line of output
for (;;)
{
size_t blank_index;
bool found_blank = false;
if ( fgets( line + leftovers, sizeof line - leftovers, stdin ) == NULL )
{
//print all leftovers
line[leftovers] = '\0';
printf( "%s\n", line );
break;
}
size_t len = strlen( line );
//this check is probably not necessary
assert( len != 0 );
if ( line[len-1] == '\n' )
{
//we read a complete line, so print it
printf( "%s", line );
leftovers = 0;
continue;
}
//if we reach this, then input line was not read in
//completely, or we are dealing with the last line before
//end-of-file or input failure
//find last blank
for ( size_t i = 0; line[i] != '\0'; i++ )
{
if ( isblank( (unsigned char)line[i] ) )
{
found_blank = true;
blank_index = i;
}
}
if ( !found_blank )
{
if ( len <= CUT )
{
if ( ferror(stdin) )
{
fprintf( stderr, "error reading input!\n" );
exit( EXIT_FAILURE );
}
//we should only reach this if end-of-file was
//encountered in the middle of a line
assert( feof(stdin) );
printf( "%s\n", line );
break;
}
//remember last character
char temp = line[len-1];
line[len-1] = '\n';
printf( "%s", line );
line[0] = temp;
leftovers = 1;
}
else
{
//remember character after last blank
char temp = line[blank_index+1];
//replace character after last blank with terminator
line[blank_index+1] = '\0';
//print line up to and including last blank
printf( "%s\n", line );
if ( temp != '\0' )
{
//move unprinted characters to start of next line
line[0] = temp;
leftovers = len - blank_index - 1;
memmove( line + 1, line + blank_index + 2, leftovers - 1);
}
else
{
leftovers = 0;
}
}
}
}
It appears that my initial advice of using fgets instead of getchar was not very good, as the fgets solution turned out to be slightly more complicated than the getchar solution.
Here is some sample input and output of both programs (both programs behave the same way):
Sample input:
This is a line with several words.
Thisisalinewithonelongword.
Sample output:
This is a
line with
several
words.
Thisisalin
ewithonelo
ngword.
I am writing a program to read a user input statement and extract all integers from the input. For example, if I enter "h3ll0", the program will output "30". I have used the fgets function to read the user input.
However, I am currently reading about getchar() and would like to know what would be the best way to use getchar() in my program to read user input instead of fgets. I am not really clear on how getchar() works and what situations it can be useful in.
This question is related to a project that specifically asks for getchar() as the method of reading user input. As I was unclear on how getchar() works, I built the rest of the program using fgets to ensure it was working.
#include <stdio.h>
int main()
{
char user_input[100];
int i;
int j = 0;
printf("Please enter your string: ");
fgets(user_input ,100, stdin);
for(i = 0; user_input[i] ; i++)
{
if(user_input[i] >= '0' && user_input[i] <= '9')
{
user_input[j] = user_input[i];
j++;
}
}
user_input[j] = '\0';
printf("Your output of only integers is: ");
printf("%s\n", user_input);
return 0;
}
OP: unclear on how getchar() works
int fgetc(FILE *stream) typically returns 1 of 257 different values.
"If ... a next character is present, the fgetc function obtains that character as an unsigned char converted to an int C11 §7.21.7.1 2
On end-of-file or input error (rare), EOF, is returned.
OP: to use getchar() in my program to read user input instead of fgets.
Create your own my_fgets() with the same function signature and same function as fgets() and then replace.
char *fgets(char * restrict s, int n, FILE * restrict stream);
The fgets function reads at most one less than the number of characters specified by n from the stream pointed to by stream into the array pointed to by s. No additional characters are read after a new-line character (which is retained) or after end-of-file. A null character is written immediately after the last character read into the array. C11 §7.21.7.2 2
Return the same value
The fgets function returns s if successful. If end-of-file is encountered and no characters have been read into the array, the contents of the array remain unchanged and a null pointer is returned. If a read error occurs during the operation, the array contents are indeterminate and a null pointer is returned. §7.21.7.2 3
Sample untested code
#include <stdbool.h>
#include <stdio.h>
char *my_fgets(char * restrict s, int n, FILE * restrict stream) {
bool something_read = false;
int ch = 0;
char *dest = s;
// Room ("reads at most one less") and EOF not returned?
while (n > 1 && (ch = fgetc(stream)) != EOF) {
n--;
something_read = true;
*dest++ = (char) ch;
if (ch == '\n') {
break; // "No additional characters are read after a new-line character"
}
}
// Did code end the while loop due to EOF?
if (ch == EOF) {
// Was EOF due to end-of-file or rare input error?
if (feof(stream)) {
// "If end-of-file is encountered and no characters ... read into the array ..."
if (!something_read) {
return NULL;
}
} else {
// "If a read error ..."
return NULL; // ** Note 1
}
}
// room for \0?
if (n > 0) {
*dest = '\0'; //" A null character is written immediately after the last character"
}
return s;
}
Perhaps improve fgets() and use size_t for n.
char *my_fgets(char * restrict s, size_t n, FILE * restrict stream);
fgets() with n <= 0 is not clearly defined. Using size_t, an unsigned type, at least eliminates n < 0 concerns.
Note 1: or use s = NULL; instead of return NULL; and let the remaining code null terminate the buffer. We have that option as "array contents are indeterminate".
Something like this should work as a clunky replacement to fgets using only getchar. I don't guarantee the accuracy of the error handling.
I don't think you would ever want to use getchar over fgets in an application. Getchar is more limited and less secure.
#include <stdint.h>
void your_fgets(char *buffer, size_t buffer_size)
{
int i;
size_t j;
if (buffer_size == 0)
return ;
else if (buffer_size == 1)
{
buffer[0] = '\0';
return ;
}
j = 0;
while ((i = getchar()) != EOF)
{
buffer[j++] = i;
if (j == buffer_size - 1 || i == '\n')
{
buffer[j] = '\0';
return ;
}
}
buffer[j] = '\0';
}
I am baffled by the comments on this post suggesting that fgets is easier to use. Using fgets unnecessarily complicates the issue. Just do:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
int
main(int argc, char **argv)
{
int c;
while( ( c = getchar() ) != EOF ) {
if(isdigit(c) && (putchar(c) == EOF)) {
perror("stdout");
return EXIT_FAILURE;
}
}
return ferror(stdin);
}
There is absolutely no reason to use any additional buffering, or read the input one line at a time. Maybe you'll want to output newlines as they come in, but that would be an implementation detail that is left unspecified in the question. Either way, it's utterly trivial (if(( c == '\n' || isdigit(c)) && (putchar(c) == EOF))). Just read a character and decide if you want to output it. The logic is much easier if you don't think about the input as being more complicated than it is. (It's not line-oriented...it's just a stream of bytes.)
If, for some unknown reason you want to make this tool usable only in an interactive setting and load up your output with excess verbosity, you can easily do something like:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
int
main(int argc, char **argv)
{
int c;
do {
int want_header = 1;
printf("Please enter your string: ");
while( ( c = getchar() ) != EOF && c != '\n' ) {
if(! isdigit(c)) {
continue;
}
if(want_header) {
want_header=0;
printf("Your output of only integers is: ");
}
if(putchar(c) == EOF) {
perror("stdout");
return EXIT_FAILURE;
}
}
if( c == '\n')
putchar(c);
want_header = 0;
} while(c == '\n');
return ferror(stdin);
}
but, please, don't do that. (Imagine if grep started by emitting a prompt that said "please enter the regex you would like to search for"!)
I was trying an exercise in K&R which asks to write a program which reads a set of text line and prints the longest line.
I writing along the lines of something like this;
define a string of characters
write a function that marks the length of line until there's a newline
when encountered newline, the function again repeats
keep copying length to a variable if the length of newline is greater
copy the string (if of greater length) to another string
print the last copied string
I tried writing the function this mark the length which is certainly wrong
int getlength(char str[],int lim)
{
int length ,c;
c = getchar();
while((c=getchar())!= '\n')
{
for (length=0; length < lim -1; length++)
c = str[length];
}
return length;
}
Can anyone suggest me how to write the getlength function. I am not asking for the code but instead the psuedocode would be very helpful.
Here's what I think you're looking for from reading the post and your comments:
int getlength(char str[],int lim)
{
int length = 0;
int c;
while((c=getchar())!= '\n') //Get a character. If it's a newline, quit. Otherwise, keep going.
{
str[length] = c; //Add it to the string
length++; //Move to the next character
}
str[length] = '\0'; //Add the terminating null to the end of the string
return length;
}
This function will find the length of the first line you give it on stdin.
Here's why your original function did not work:
You had:
int getlength(char str[],int lim)
{
int length ,c;
c = getchar();
while((c=getchar())!= '\n')
{
for (length=0; length < lim -1; length++)
c = str[length];
}
return length;
}
First, the character you read with c = getchar(); never gets processed because the while statement overwrites it while checking its condition. Remember, while loops will check the condition at the start of every loop. I think you wanted to use do {...} while(condition);, but if you do that you'll run into bugs because if the user types nothing the first getchar() call will return '\n' and the loop will run anyway and add it to the string.
Second, the inner loop loops over every character in the string you pass it and sets it to the most recently character read. I tried your code with a 100 character string and typed in "abcdef." I got 99 f's - it looped through each character in "abcdef" and set the whole string to the current character, and since 'f' was the last character, it was put in last.
Third, you didn't add a terminating null to the end of the string.
With strlen() you can get the length of the string. (I think that it is what you are asking)
https://www.tutorialspoint.com/c_standard_library/c_function_strlen.htm
Okay i understood. You want to print the longest line from a text file. Here is your code.
#include<stdio.h>
#include<stdlib.h>
#define LINEMAX 200
int main(){
FILE * fp = fopen("longestline.in","r");
char temp1[LINEMAX]={'\0'},temp2[LINEMAX]={'\0'},*selected,*longest,c;
int longestLength=0,length=0;
selected = temp1;
while((c=fgetc(fp))!=EOF){
while(c!='\n'&&c!=EOF){
selected[length] =c;
length++;
c=fgetc(fp);
}
if(length>longestLength){
longestLength = length;
selected[length+1] = '\0';
longest = selected;
selected = selected == temp1 ?temp2:temp1;
}
length =0;
}
puts(longest);
return 0;
}
I am having the absolute craziest time getting full line input to work. I will explain my problem. I need to get a full line of input, including a space, from the user entered at the keyboard. Simple right? Wrong!
MY GOAL
Store multiple strings, with spaces, into variables. If it makes a difference, I want to make the variables equal to a char pointer. So once I get the input from tempString, I want to set it to a char pointer. Like so:
char *variable1, *variable2;
//get user input
variable1 = tempString;
//get more user input
variable 2 = tempString;
//etc etc etc
Here's what I've tried.
First try
char tempString[100];
scanf("%s", &tempString);
printf("%s", tempString);
Invalid: scanf will stop reading at a white space, so "Example String" would just end up being "Example".
Second try
So I do more research. I thought I found the magic fix.
char tempSTring[100];
fgets(tempString, 100, stdin);
printf("%s", tempString);
Originally this works. However there is a massive problem. I need to get the user to enter about 8 inputs. Meaning I have to use a command like this 8 times. The problem is the program often skips over the fgets command. If I use a scanf previously, somehow the \n character is stuck in the input stream, and automatically feeds into fgets, satisfying its stdin input, and then does not prompt the user for input.
Third try
After thinking fgets was maybe my solution with a work around, I tried some tricks.
char tempSTring[100];
getc(stdin);
fgets(tempString, 100, stdin);
printf("%s", tempString);
I tried adding this getc(stdin) line. It worked for much of my program. It absorbs the \n character left behind in the stream. When it does so, great, it works. But sometimes, for some reason, the \n is NOT left in the stream, and when debugging, it looks like getc(stdin) is requesting input from the user, so it pauses my program to ask for input.
Question
These don't work for me.
How should I be doing this easy task?
To read (up to) 8 lines from a file, you can use either of these solutions. I decline to use variables char *variable1, *variable2, …; — that is an array seeking to escape.
POSIX getline()
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
enum { MAX_LINES = 8 };
char *lines[MAX_LINES];
int index = 0;
char *buffer = 0;
size_t buflen = 0;
while (index < MAX_LINES && getline(&buffer, &buflen, stdin) != -1)
{
lines[index++] = buffer;
buffer = 0;
buflen = 0;
}
free(buffer); // Space may be allocated before EOF is detected
for (int i = 0; i < index; i++)
printf("%d: %s", i, lines[i]);
return 0;
}
If getline() fails to allocate memory, it will report an error, so there is no need to do an explicit error check.
Standard C fgets()
Code using strdup(), another POSIX function. It isn't a part of standard C (though it is widely available). It is trivial to implement.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
enum { MAX_LINES = 8 };
char *lines[MAX_LINES];
int index = 0;
char buffer[4096];
while (index < MAX_LINES && fgets(buffer, sizeof(buffer), stdin) != 0)
{
if ((lines[index] = strdup(buffer)) == 0)
break;
index++;
}
for (int i = 0; i < index; i++)
printf("%d: %s", i, lines[i]);
return 0;
}
The test in the loop allows for the possibility of strdup() failing to allocate memory.
Notes
Both the solutions above keep the newline at the end of the input string. If you don't want that, you can zap it with:
lines[i][strcspn(lines[i], "\r\n")] = '\0';
This overwrites a carriage return or newline with a null byte, transforming DOS or Unix line endings. You then need to adjust the printing which assumes the string includes a newline. Note that the expression shown works correctly even if there is no carriage return or newline in the string.
The fgets() solution will break lines at 4095 characters, leaving the rest to be read as 'the next line'. If that's not acceptable, you have a variety of strategies open to you.
You can detect whether there is a newline and arrange to allocate more memory and read the next section of the line into the extra memory, repeating until you come across a newline or EOF.
You can read the remaining characters up to the newline or EOF:
int c;
while ((c = getchar()) != EOF && c != '\n')
;
Implementing strdup()
If for some reason your system doesn't have an implementation of strdup(), you can create a surrogate with:
#include <assert.h>
#include <stdlib.h>
#include <string.h>
char *strdup(const char *old_str)
{
assert(old_str != 0);
size_t old_len = strlen(old_str) + 1;
char *new_str = malloc(old_len);
if (new_str != 0)
memmove(new_str, old_str, old_len);
return new_str;
}
Here's how we old fart C programmers would do it:
#include <stdio.h>
#define MAX_LEN 100
int main( )
{
int c;
char input[MAX_LEN+1];
int i = 0;
while ( (c=getchar()) != '\n' && c != EOF && i < MAX_LEN)
input[i++] = c;
if (c == EOF || c =='\n') {
/* received input that terminated within buffer limit */
input[i] = '\0';
printf("read in your input string of: %s\n", input);
}
else {
printf("don't buffer overflow me dude!\n");
return -1;
}
return 0;
}
But nowadays people will tell you to use one of the library functions. I'm still an old fart though.
EDIT: Fixed my embarrassing mistakes pointed out by the helpful comments below.
You can take care of '\n' left by previous scanf by writing it like this -
scanf("%d%*c", &x); //<-- example to take int input
%*c will read from stdin and then discard it, thus '\n' would be removed from stdin.
You can achieve with scanf like this (a way for your previous attempt)-
char tempString[100];
/* As suggested by chqrile it is essential to check return of scanf */
if(scanf("%99[^\n]", tempString)!=1){
// ^^ & not required
tempString[0]='\0';
}
%99[^\n] this will read 99 characters and will stop only after encountering '\n' , thus would read input with spaces.
I am trying to create a c program that read a file and count specific words.
I tried this code but I don't get any result:
#include<stdio.h>
#include<stdlib.h>
void main
{
File *fp = fopen("file.txt","r+");
int count =0;
char ch[10];
while((fgetc(fp)!=NULL)
{
while((fgetc(fp)!=NULL)
{
if((fgets(ch,3,fp))=="the" || (fgets(ch,3,fp))=="and")
count++;
}
}
printf("%d",count);
}
As you're acquiring data in blocks of 3 at a time, you're assuming that the two words "the" and "and" are aligned on 3 character boundaries. That will not, in general, be the case.
You also need to use strncmp to compare the strings.
As a first review, I'd read line by line and search each line for the words you want.
I'm also unsure as your intention behind having two nested while loops.
You can't compare string pointers with the equality operator, you have to use the strcmp function.
There are also other problems with the code you have. For once, the fgetc calls does not return NULL on errors or problems, but EOF. Otherwise it returns a character read from the file.
Also, your two fgets in the condition will cause reading of two "lines" (though each "line" you read will only be two characters) from the file.
fgets(ch, 3, fp) makes you read 2 characters plus the null-terminator, if you want to read 3 characters and the null-terminator you want fgets(ch, 4, fp) instead. Also, you need to use strcmp to compare strings.
Also, what are all those while loops for ?
if((fgets(ch,3,fp))=="the" || (fgets(ch,3,fp))=="and")
The above line is completely useless.
fgets(ch,3,fp) gets your word from the file to ch[10] . But you cannot compare that using == .
What I would do is use strcmp and give size 4 in fgets (never forget the \o)
You gotta use strcmp() to compare two strings. Not relational operators.
Just out of my head (perhaps not the optimal way, but should be pretty easy to read and understand):
#define WHITE_SPACE(c) ((c)==' ' || (c)=='\r' || (c)=='\n' || (c)=='\t'))
int CountWords(const char* fileName,int numOfWords,const char words[])
{
int count = 0;
FILE* fp = fopen(fileName,"rt");
fseek(fp,0,SEEK_END);
int size = ftell(fp);
fseek(fp,0,SEEK_SET);
char* buf = new char[size];
fread(buf,size,1,fp);
fclose(fp);
for (int i=0,j; i<size; i=j+1)
{
for (j=i; j<size; j++)
{
if (WHITE_SPACE(buf[j]))
break;
}
for (int n=0; n<numOfWords; n++)
{
int len = strlen(words[n]);
if (len == j-i && !memcmp(buf+i,words[n],len))
count++;
}
}
delete[] buf;
return count;
}
Please note, however, that I have not compiled nor tested it (as I said above, "out of my head")...
Take a look at String matching algorithms.
You can also find implementation examples of Boyer-Moore in github
The line
if((fgets(ch,3,fp))=="the" || (fgets(ch,3,fp))=="and")
has a couple of problems:
You can't compare string values with the == operator; you need to use the strcmp library function;
You're not comparing the same input to "the" and "and"; when the first comparison fails, you're reading the next 3 characters from input;
Life will be easier if you abstract out the input and comparison operations; at a high level, it would look something like this:
#define MAX_WORD_LENGTH 10 // or however big it needs to be
...
char word[MAX_WORD_LENGTH + 1];
...
while ( getNextWord( word, sizeof word, fp )) // will loop until getNextWord
{ // returns false (error or EOF)
if ( match( word ) )
count++;
}
The getNextWord function handles all the input; it will read characters from the input stream until it recognizes a "word" or until there's no room left in the input buffer. In this particular case, we'll assume that a "word" is simply any sequence of non-whitespace characters (meaning punctuation will be counted as part of a word). If you want to be able to recognize punctuation as well, this gets a bit harder; for example, a ' may be quoting character ('hello'), in which case it should not be part of the word, or it may be part of a contraction or a posessive (it's, Joe's), in which case it should be part of the word.
#include <ctype.h>
...
int getNextWord( char *target, size_t targetSize, FILE *fp )
{
size_t i = 0;
int c;
/**
* Read the next character from the input stream, skipping
* over any leading whitespace. We'll add each non-whitespace
* character to the target buffer until we see trailing
* whitespace or EOF.
*/
while ( (c = fgetc( fp )) != EOF && i < targetSize - 1 )
{
if ( isspace( c ) )
{
if ( i == 0 )
continue;
else
break;
}
else
{
target[i++] = c;
}
}
target[i] = 0; // add 0 terminator to string
return i > 0; // if i == 0, then we did not successfully read a word
}
The match function simply compares the input word to a list of target words, and returns "true" (1) if it sees a match. In this case, we create a list of target words with a terminating NULL entry; we just walk down the list, comparing each element to our input. If we reach the NULL entry, we didn't find a match.
#include <string.h>
...
int match( const char *word )
{
const char *targets[] = {"and", "the", NULL};
const char *t = targets;
while ( t && strcmp( t, word ))
t++;
return t != NULL; // evaluates to true if we match either "the" or "and"
}
Note that this comparison is case-sensitive; "The" will not compare equal to "the". If you want a case-insensitive comparison, you'll have to make a copy of the input string and convert it all to lowercase, and compare that copy to the target:
#include <stdlib.h>
#Include <ctype.h>
#include <string.h>
...
int match( const char *word )
{
const char *targets[] = {"and", "the", NULL};
const char *t = targets;
char *wcopy = malloc( strlen( word ) + 1 );
if ( wcopy )
{
char *w = word;
char *c = wcopy;
while ( *w )
*c++ = tolower( *w++ );
}
else
{
fprintf( stderr, "malloc failure in match: fatal error, exiting\n" );
exit(0);
}
while ( t && strcmp( t, wcopy))
t++;
free( wcopy );
return t != NULL; // evaluates to true if we match either "the" or "and"
}