How to properly look for a string in a file? - c

In this function, I am displaying a .txt document to the screen, which works, however, I am trying to read the file document and scan the document for the word EMPTY as I have it saved as a string variable. It should be noted that I am counting the time EMPTY is in the file and later printing the times it was would in the file along with on another thing. My first question is am I doing this correct?
void allSeats(void)
{
int position = 0;
int count = 0;
char gone[6] = "EMPTY";
system("cls");
retry:
fseatArrangement = fopen("airlineSeatingArrangment.txt", "r");
while (fgets(econoAirSeatArrangement, 1000, fseatArrangement) != NULL)
printf(econoAirSeatArrangement);
fclose(fseatArrangement);
while (count < FULL)
{
fgets(econoAirSeatArrangement, 1000, fseatArrangement);
fscanf(fseatArrangement,"%s", &gone);
count++;
}
printf("There are %d seats vacant at the moment\nThere are %d seats with no vacancy at the moment \n",count, FULL-count);
printf("Enter Zero(0) Key to return to menu at anytime.");
scanf("%d", &position);
if (position == 0)
{
system("cls");
menu();
}
else
{
system("cls");
printf("INVALID INPUT! Please try again.\n");
goto retry;
}
system("pause");
return;
}

The main problem is here
fgets(econoAirSeatArrangement, 1000, fseatArrangement);
you have already closed the file pointer using fclose(), and yet, you try to use it. It causes undefined behavior.
That said,
printf(econoAirSeatArrangement); appears wrong. If you do not wish to have any format conversion specification you can stick to puts().
You must check the return value of fopen(), fgets(), fscanf() etc. for success before using the returned value / scanned value.

Related

Is there a way for me to change the color of specific text in a C program in DevC++?

Basically, I'm working on this text editor program for a school project that uses simple filing and string functions to create, append, delete, display, duplicate, or search from text files. I've managed to put all the functions together, and my question pertains to my Search() function, which I'll attach at the end of this for reference. If the search keyword is found, the function prints which line it was found in, and it prints the line itself. What I'd like to do is, if possible, change the color of the search keyword when the line gets printed so that it stands out and the user can immediately tell where his keyword is located within the line. I'm not asking this without doing ANY research on the matter; I did some digging and it seems I can make use of ANSI escape sequences or the Windows Console Virtual Terminal Sequences to achieve what I'm trying to do, and I did go through the documentation on the Microsoft website, but unfortunately I'm not yet comfortable with calling windows APIs and I could really use some help figuring out exactly how to go about doing this. Also, apologies in advance if the code I'm attaching seems inefficient or unncessary at times, only started learning C a couple months ago. I am using the gcc compiler with DevC++ on Windows 10.
TIA.
void Search(void) {
FILE *fptr;
char name[20], key[30], line[100];
int linenum=1, found=0;
printf("Enter name of text file to search from, or enter 'exit' to cancel and return to menu: ");
gets(name);
if(strcmp(name,"exit") == 0)
return;
strcat(name,".txt");
fptr = fopen(name,"r");
while(!fptr) { // just some input validation
printf("Error. Text file not found. Make sure it exists and is placed in the same folder as the .exe file for this program.");
fclose(fptr);
printf("\n\nEnter name of text file to search from, or enter 'exit' to cancel and return to menu: ");
gets(name);
if(strcmp(name,"exit") == 0)
return;
strcat(name,".txt");
fptr = fopen(name,"r");
}
printf("Enter your search keyword (remember, it is case sensitive): "); //searching staarts here
gets(key);
while(!feof(fptr)) {
fgets(line,100,fptr);
if(strstr(line,key)) {
printf("Keyword found in line %d:\n", linenum);
printf("----------------------------------------------------------------------------------------------\n");
printf("%s",line);
printf("----------------------------------------------------------------------------------------------\n\n");
found=1;
}
linenum++;
}
if(!found)
printf("Keyword not found in file.");
printf("\nPress any key to return to main menu: ");
getch();
}
The reason I used the long ------------ separators is that I want to differentiate the contents of a text file from the contents of what's written in the console window.
Basically, you can rely on string class to complete this task, use string :: find to extract the location of the key, and then use string:: substr to print the value of the key.
Refer to the code below:
void Search(void) {
...
printf("Enter your search keyword (remember, it is case sensitive): "); //searching staarts here
gets_s(key);
while (!feof(fptr)) {
fgets(line, 100, fptr);
if (strstr(line, key)) {
std::string str(line);
printf("Keyword found in line %d:\n", linenum);
printf("----------------------------------------------------------------------------------------------\n");
int pos = str.find(key);
int len = strlen(key);
int len_t = strlen(line);
if (pos != 0)
{
printf("%s", str.substr(0, pos).c_str());
printf("\x1b[31m%s", str.substr(pos, len).c_str());
printf("\x1b[0m%s\r\n", str.substr(len+pos, len_t).c_str());
}
else
{
printf("\x1b[31m%s", str.substr(pos, len).c_str());
printf("\x1b[0m%s\r\n", str.substr(pos+len, len_t).c_str());
}
printf("\x1b[0m----------------------------------------------------------------------------------------------\n\n");
found = 1;
}
linenum++;
}
if (!found)
printf("Keyword not found in file.");
printf("\nPress any key to return to main menu: ");
getch();
}
Debug:
Alternatively you could simply use the Windows API console functions:
#include <stdio.h>
#include <windows.h>
int main()
{
HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hstdout, FOREGROUND_RED|FOREGROUND_INTENSITY);
printf("hello ");
SetConsoleTextAttribute(hstdout, FOREGROUND_GREEN|FOREGROUND_INTENSITY);
printf("world");
return 0;
}

C Program - How to deny any non-numerical input

I've just started learning the language of C, and would love your help in cleaning up / simplifying my code if you know a better way to reach the following.
I want a program to ask for a number, and if that is found then proceed to print and end, however if anything else is put in (e.g. a letter key), then I want the program to loop asking for a number until one is given.
I started off by using a simple scanf input command, but this seemed to go into an infinite loop when I tried to check if a valid number (as we define them) was put in.
So instead I have ended up with this, from playing around / looking online, but I would love to know if there is any more efficient way!
//
// Name & Age Program
// Created by Ben Warren on 1/3/18.
//
#include <stdio.h>
int main (void)
{
//Setting up variables
int num;
char line[10]; /* this is for input */
//Collecting input
printf("Please enter any number? \t");
scanf("%d", &num);
//If Invalid input
while (num==0)
{
printf("\nTry again:\t");
fgets(line, 10, stdin); //turning input into line array
sscanf(line, "%d",&num); //scaning for number inside line and storing it as 'num'
if (num==0) printf("\nThat's not an number!");
}
//If Valid input
{
printf("\n%d is nice number, thank you! \n\n", num);
*}*
return 0;
}
Instead of checking if the value is different to 0, check the return value of
sscanf. It returns the number of conversions it made. In your case it should be 1. Unless the return value is 1, keep asking for a number.
#include <stdio.h>
int main(void)
{
int ret, num;
char line[1024];
do {
printf("Enter a number: ");
fflush(stdout);
if(fgets(line, sizeof line, stdin) == NULL)
{
fprintf(stderr, "Cannot read from stdin anymore\n");
return 1;
}
ret = sscanf(line, "%d", &num);
if(ret != 1)
fprintf(stderr, "That was not a number! Try again.\n");
} while(ret != 1);
printf("The number you entered is: %d\n", num);
return 0;
}
That is not a bad approach for someone new to C. One small improvement would be to actually check the return value of scanf(), since it returns the number of arguments successfully retrieved. Then you could get away from relying on num being 0 to indicate the input was valid. Unless you do want to specifically flag 0 as invalid input.
int ret = scanf("%d", &num);
ret == 1 would mean an integer was succesffully read into num, ret == 0 would mean it was not.
Consider using strtol to parse a string for a long int. This also allows you to detect trailing characters. In this example if the trailing character is not a newline, the input can be rejected. strtol can also detect overflow values. Read the documentation to see how that works.
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
//Setting up variables
long int num = 0;
char line[40] = ""; /* this is for input */
char *parsed = NULL;
printf("Please enter any number? \t");
fflush ( stdout);
while ( fgets(line, 40, stdin))
{
parsed = line;//set parsed to point to start of line
num = strtol ( line, &parsed, 10);
if ( parsed == line) {//if parsed equals start of line there was no integer
printf("Please enter a number? \t");
printf("\nTry again:\t");
fflush ( stdout);
continue;
}
if ( '\n' != *parsed) {//if the last character is not a newline reject the input
printf("Please enter only a number? \t");
printf("\nTry again:\t");
fflush ( stdout);
}
else {
break;
}
}
if ( !parsed || '\n' != *parsed) {
fprintf ( stderr, "problem fgets\n");
return 0;
}
printf("\n%ld is nice number, thank you! \n\n", num);
return 0;
}
0 (zero) is a number...
But I see what you want to do...
You can check for a valid number, using isdigit or a combination of similar functions
I think its also important to follow the advice of other answers to use the return value from scanf using code such as:
int ret = scanf("%d", &num);
and examining ret for success or failure of scanf.

Repeating an Input till it is answered Correct

The concept if very simple. The computer must repeat the question till it recieves a valid response. Here is my current code:
#include <stdio.h>
int main(int argc, const char * argv[]) {
int age;
do{
printf("How old are you?\n");
scanf("%d", &age);
if (age == 32767)
{
printf("Error, retry: \n");
}
else
{
printf("Cool.");
break;
}
}
while(age!=3267);
return (0);
}
The if else statement is to catch the exception incase the user types something that is not an integer.
I tried using a do-while loop but it ended up as an infinite loop
I used the do-while loop because I needed to go through that procedure until I get a valid age value.
My output with the current code is:
How old are you?
g
Error, retry:
How old are you?
Error, retry:
How old are you?
Error, retry:
How old are you?
Error, retry:
It goes like this indefinitely.
It would be great if you could help me out.
The computer must repeat the question till it recieves a valid response.
It (output) goes like this indefinitely.
Reason :
The problem is that you are receiving input only once in your code and then entering into loop to check for the age.
since age value is not re-assigned after every iteration, if the first intput is !=32767 it's always wrong and enters into an infinite loop or also known as the odd loop.
scanf("%d", &age); //scans only once
do //enters loop
{
if (age == 32767)
{
printf("Error, retry: \n");
}
else
{
printf("Cool.");
}
} while(age!=32767);
The if else statement is to catch the exception incase the user types something that is not an integer.
No, if (age == 32767) would only check if the entered response was equal to 32767 or not.
From #davmac 's comment , you can never check for an input value greater than the maximum value of the int variable.
Instead it'd be better if you would assign a range this way
`if (age > 100 || age <0 )`
Solution :
to avoid this scan age for every iteration and also see the changes I've done :
do{
printf("How old are you?\n");
if(scanf("%d", &age)==1) //checking if scanf is successful or not
{
if (age > 100 || age <0 )
{
printf("Error, retry: \n");
}
else
{
printf("Cool.");
break; //break loop when correct value is entered
}
}
else //if scanf is unsuccessful
{
char c;
printf("enter only integers\n");
do
{
scanf("%c",&c);
}while( c !='\n' && c!= EOF ); //consuming characters
}
}while(1); //always true
Some important points:
First, Using scanf to read an int from user input usually allows for whitespace to be entered first:
scanf(" %d", &age);
In particular this skips over previous new line characters that were input previously and are still buffered.
Second, scanf returns a value indicating whether it succeeded or failed, and how many items it matched. You need to check this return value:
int r = scanf(" %d", &age);
if (r == EOF) {
break;
}
if (r == 0) {
printf("Error, retry: \n");
}
Third, if scanf can't match input it is left in the input buffer. If you don't retrieve it from the buffer, it will simply fail to match again the next time you call scanf, ad infinitum. For this reason, scanf is not great for handling user input at all. It is better, if possible, to read a single line of input into a buffer (you can use fgets for this, if you are careful), and then process the buffer. As a weak alternative, you can force some of the input buffer to be consumed by scanning for a string before you try to read the input value again:
int r = scanf(" %d", &age);
if (r == EOF) {
break;
}
if (r == 0) {
printf("Error, retry: \n");
scanf("%*s"); // match string but suppress assignment
}
else {
printf("Cool.\n");
break;
}
This modification gets your code to at least halfway-working state.
Use do while Loop. Like:
Do{
// your code
Age = // asign value
}while(age>100 && age < 1);
So it will repeat until age is entered between 100 and 1. It will stop if it will get age b/w 1 - 100.
Thanks. Hope it will help.

Comparing user input with text file and looping in C

I'm creating a program that asks the user to input a word. The word is then compared with a word in a text file. If correct, I want the user to input another word which should correspond with the next word in the text file and this should loop until the end of the file. I'm having trouble with the loop to the end of the file. Could someone please review my code and give me a few pointers? thanks so much
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
//Step 1: open file and declare variables//
FILE *fp;
fp = fopen("secretwords.txt","r");
char guess[20];
char secret[20];
int i, count;
//Step 2: Check that file opened correctly, terminate if not//
if (fp == NULL)
{
printf("Error reading file\n");
exit (0);
fclose(fp);
}
//Step 3: Create loop to run for each word to run to end of file//
fscanf(fp,"%s", secret);
//Need to create a loop here that will read the text file 20 times,
// each time reading the next word//
for (i=0; i < 3; i++)
{
printf("Please guess the word: \n");
scanf("%s", guess);
if (strcmp(secret,guess)==0)
{
printf("Your guess was correct\n");
return 0; //This return will terminate the program.
// I need to restart loop from here
}
else
{
printf("Your guess was incorrect. Please try again\n");
}
}
return 0;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
FILE *fp = fopen("secretwords.txt", "r");
if (fp == NULL)
{
printf("Error reading file\n");
return 1;
}
char guess[20] = {0};
char secret[20] = {0};
while(fscanf(fp, "%s", secret) != EOF) // i would suggest you use 'fscanf_s("%s", guess);' instead if available
{
printf("Please guess the word: \n");
scanf("%s", guess); // i would suggest you use 'scanf_s("%s", guess);' instead if available
if (!strncmp(secret, guess, sizeof(guess)))
{
printf("Your guess was correct. Continue ...\n");
}
else
{
printf("Your guess was incorrect. Good bye.\n");
break;
}
}
fclose(fp);
return 0;
}
i made some suggestions about scanf_s and fscanf_s, if they are available, use them. But still, i am wondering why they are still teaching bad code in schools? I would not suggest to use *scanf* functions at all. Further reading: uncontrolled format string
Move the fscanf call that reads from the file to a function that returns the next word
loop for user input, only calling the function outlined above when you need to advance to the next word in the file (when the user inputs the correct thing)

Compare user input with text file in C

I need to have a user input a word then compare the word with a text file to see if it is correct. The user has 3 attempts to enter the word before the program terminates. My issue is reading the word from the file I know it's something simple that I have wrong. I should also clarify that the error I'm getting is in the compiler I haven't gotten to the point of being able to compare the strings yet!
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
fp = fopen("secret.txt","r");
char guess[10];
const char secret[10];
int i, c;
c = getc(fp);
fgets(secret, sizeof(secret), fp);
for (i=0; i < 3; i++)
{
printf("Please guess the word: \n");
scanf("%s", guess);
while (c !=EOF)
{
if (strcmp(secret,guess)==0)
{
printf("Your guess was correct");
return 0;
}
else
{
printf("Your guess was incorrect. Please try again\n");
}
}
fclose (fp);
}
return 0;
}
Here are some pointers:
c = getc(fp) consumes the first character of the file, so it never becomes part of the secret variable.
If secret.txt contains a newline, the newline is read into the secret variable.
The while (c != EOF) loop seems pointless, since c isn't modified inside the loop. Furthermore, the infinite nature of the loop prevents the outer for loop from functioning correctly.
If I were you, I'd fix the while loop and would make sure that secret is read correctly, for example by printing it out or examining it in a debugger.
What is
c = getc(fp);
needed for? My "guess" would be that you read the first character of the word into c and then secret misses the first character.
EDIT: Instead of using getc for EOF checking, which as said corrupts the read word (and this while loop is rubbish anyway), just check the return value of fgets:
if(fgets(secret, sizeof(secret), fp) == NULL)
//file is empty or other error occurred
and remove this infinite while(c != EOF) loop.
So it should rather look something like:
FILE *fp = fopen("secret.txt","r");
char guess[10];
const char secret[10];
int i;
if(fgets(secret, sizeof(secret), fp) == NULL)
{
printf("Error while reading file\n");
return -1;
}
fclose(fp);
for (i=0; i < 3; i++)
{
printf("Please guess the word: \n");
scanf("%s", guess);
if (strcmp(secret,guess) == 0)
{
printf("Your guess was correct");
return 0;
}
else
printf("Your guess was incorrect. Please try again\n");
}
return 0;
Your code is grossly off: you do not alter 'c' inside a loop, making it spin indefinitely. It's a good idea to sketch your algorithm on a piece of paper before you start coding. In your case, pseudocode should look like this:
Open file
Read the secret
Close file
Repeat three times:
--- Display the prompt
--- Read user input
--- If user input matches the secret, congratulate the user and exit.
Tell the user his guess was incorrect.
At this point, converting it to C should be more or less mechanical. Good luck!
while (c !=EOF)
{
if (strcmp(secret,guess)==0)
{
printf("Your guess was correct");
return 0;
}
else
{
printf("Your guess was incorrect. Please try again\n");
}
}
looks like an infinite loop to me

Resources