I am trying to finish a homework program that compares a string with a text file, so the user can essentially search the text file for the search term (string) in the file. I'm getting there :)
However today I'm running into a very weird issue. When it asks for the term to search for I input the text, but it never ends. I could type all day long and it still asks for input. What weird issue(s) am I overlooking? Fresh pair of eyes might help :)
/*
ask the user for a word
convert user word to LOWER CASE
open output file
open input file
test to be sure input file is open
search for target word and keep count --> how??
print results to monitor
write results to file
close files
*/
#include<stdio.h>
#include<stdlib.h>
int main (void)
{
//declare
int i =0;
int count = 0;
/*************************************************************
working with arrays and strings
*************************************************************/
char mystring[50]; //what user puts in
char target[50]; //the word in the file we are looking for
printf("input your message ");
scanf("%s", mystring);
//printf("%s", mystring);
/*************************************************************
find file, write to it, output the string, end and close file
**************************************************************/
//define text file to use
FILE *cfile;
//name of file == file
cfile = fopen("./thanksgiving_proclamation.txt", "a");
//error handling if file does not exist
if(cfile == NULL) printf("Cannot open file");
/*************************************************************
parse through file and search for string
**************************************************************/
//convert string to lowercase
for(i = 0; i < /*strlen(mystring)*/ 500; i++)//convert to string length
{
if(target[i] >= 'A' && target[i] <='Z')
//convert char between a and z into lowercase
target[i] = target[i] + 32; //makes uppercase char
}
//compare our strings
do{
//scan through file
fscanf(cfile, "%s", mystring);
//convert string to lowercase
for(i = 0; i < /*strlen(mystring)*/ 300; i++)//convert to string length
{
if(mystring[i] >= 'A' && mystring[i] <='Z')
//convert char between a and z into lowercase
mystring[i] = mystring[i] + 32; //makes uppercase char
}
if(strcmp(mystring, target) == 0)
count++;
}while(!feof(cfile));
//while(strcmp(target,"quit")!=0)//end loop
//print to file
fprintf(cfile, "%s", mystring);
//close file
fclose(cfile);
//show user file has been written
printf("\nSuccess. File has been written\n");
printf("Press Enter to Continue...");
getchar();
return 0;
}
You open the file in append mode:
cfile = fopen("...", "a");
and then you try to read from it.
fscanf(cfile, "%s", mystring);
For a first attempt at solving the problem, I'd try to open the file for reading, read from it inside the loop and close the file. Then open it again, this time for appending to add the mystring there (and fclose it).
Once that works, if you want to, try to see if opening in "reading and appending mode" works ...
cfile = fopen("...", "a+");
You don't need "&mystring", "mystring" is already the address of the array.
It would be better to use gets or getline.
You are reading the search string into mystring, but then you are also reading the file contents into mystring.
I think pmg has hit on the actual problem; you've opened the file in append mode, and according to my copy of H&S reading from an append stream is not permitted. You'd have to open it "a+" (append/update) in order to read and write the stream.
You should always check the result of the *scanf() call (fscanf(), sscanf(), scanf(), etc.) for success before checking feof() or ferror(), and you should never make feof() the loop test condition (since it won't return true until after you've attempted to read past the end of the file, your loop will always execute once too many times).
I'd change your loop to something like this:
for(;;)
{
if (fscanf(cfile, "%s", mystring) != 1)
{
if (feof(cfile))
{
fprintf(stderr, "Reached end of file!\n");
break; // exit loop
}
if (ferror(cfile))
{
fprintf(stderr, "Error while reading from file!\n");
break;
}
}
/**
* continue as before
*/
}
It ends when you hit Enter and only stores characters till a whitespace.
Related
I am working in Unix and I am supposed to first read in text through redirection and then ask the user to enter in a specific character and count how many times it is in the character array.
const int MAX = 8000;
int input = 1;
int i = 0;
char text[MAX], letter;
while(input != 0)
{
scanf("%c", &text[i]);
if(text[i] == '0')
input = 0;
i++;
}
printf("\n%s",text);
printf("\nEnter a letter to search for in the text: ");
scanf("%c", &letter)
Currently, I am printing the correct file through redirection, however my second scanf is being skipped. I am redirecting the file using the command: ./a.out < filename.txt.
If I try and print the character letter then it will result in nothing. It must be reading the \n from inside the empty lines of the text file still. How do I stop the scanf from reading the same text file and let me enter a letter from my keyboard in the console? As an assignment I HAVE to use the command ./a.out < filename.txt.
The freopen() function is exactly what you're looking for. You just need to use it to (re)open /dev/tty as stdin. /dev/tty is a special file referring to the terminal that started the program.
From the manual page:
The freopen() function opens the file whose name is the string pointed to by pathname and associates the stream pointed to by stream with it. The original stream (if it exists) is closed. The mode argument is used just as in the fopen() function.
[...]
The primary use of the freopen() function is to change the file associated with a standard text stream (stderr, stdin, or stdout).
Here's an example:
// ...
FILE *tty;
tty = freopen("/dev/tty", "r", stdin);
if (tty == NULL) {
perror("Unable to open terminal for reading");
exit(1);
}
printf("Enter a letter to search for in the text: ");
// Now scanf will read from the console where the process started.
scanf("%c", &letter);
By the way, your program has some issues. You could read past the end of your text array, you don't correctly terminate it with a NUL character, and you also don't check for errors. A more correct version would be:
const size_t MAX = 8000;
char text[MAX];
size_t i;
int c;
for (i = 0; i < MAX; i++)
{
c = fgetc(stdin);
if (c == EOF)
break;
text[i] = (char)c;
}
text[i] = '\0';
puts(text);
There are a few ways to do this, probably the easiest is just to open /dev/tty which is a special device referring the terminal attached to the current process. I don't recommend replacing stdin as then you will lose access to your file which is redirected there. Instead just use a different file pointer and use functions like fscanf and fgetc. Eg:
FILE *tty = fopen("/dev/tty", "r");
// fopen will return NULL if there is no attached terminal
if(NULL == tty)
{
fputs("Failed opening /dev/tty", stderr);
}
else
{
printf("\nEnter a letter to search for in the text: ");
// Read a character from the terminal
char search = fgetc(tty);
// Now you can still read from the file on stdin and search for
// your letter without needing an array (which may not be large
// enough for the whole file)
char ch;
int count = 0;
while(EOF != (ch = getchar())
{
if(ch == search)
++count;
}
printf("%d occurrences of %c\n", count, search);
}
For more information on /dev/tty and other similar special files, see: https://unix.stackexchange.com/questions/60641/linux-difference-between-dev-console-dev-tty-and-dev-tty0
So i'm trying to write a function that will read number of lines in a text file. However, I notice that the function will not exit even when it exceeded number of lines in my text file. Why? Why does it work when i put
fgets(sentence, 70, inputFile);
before counter ++
int GetNumLine(char *fileName){
FILE *inputFile;
//counter are used to store number of lines
int counter = 0;
char sentence [70];
inputFile = fopen(fileName,"r");
//if there are anything wrong with inputfile
if(inputFile == NULL){
printf("Error while opening file");
exit(1);
}
while(!feof(inputFile) ){
counter++;
}
fclose(inputFile);
return counter;
}
This will be always true
while(!feof(inputFile))
you need to read from the file in order to reach the end and the EOF marker be set, i'd recommend doing it this way
int chr;
while ((chr = fgetc(inputFile)) != EOF)
counter += (chr == '\n') ? 1 : 0;
when you put fgets() before counter++ you read from the file and change the position in the FILE * structure, when you try to read beyond the end of the file, EOF will be set and feof(inputFile) will return non-zero.
The code with the fgets() works but is not robust because you can have a line with more than 69 characters and it will be counted twice, with my suggestion the result will be always correct.
I am taking a course on C and have been faced with the following task: 1. Load XCode and start a new C project. If you wish, remove
any extraneous code from the project so that you are left
with only what’s necessary to run the main function in your
project.
2. Prompt the user to enter two values-- the first a char
value of ‘D’ or ‘C’. The second value should be a floating
point value representing an amount of money.
3. As each value is entered record it to a text file that
saves it in the following format:
D, 250\n
C, 500\n
4. Test your program and examine the text file that it creates
to insure that it is in the required format.
5. Write a second program that assumes a starting balance of
$1,000.00 and outputs a completed ledger and final balance
for the account, adding or subtracting each entry from the
text file you previously created. Entries marked as a ‘C’
should be added to the account and entries marked as a ‘D’
should be debited (subtracted).
I have already created the file and am now onto step 5, I believe i know how to obtain the first character from the file to check if it is a 'c' or 'd', but after that i am not sure how to obtain the numerical value from the same line. How do I do this? This is my code so far(I am unsure what to put in the if/else if statements):
FILE *pFile = fopen("Users/Justin/Desktop/Ledger.txt", "r");
float startingBalance = 1000.00;
char action;
if(pFile != NULL)
{
while(!(feof(pFile)))
{
fgets(action, 1, pFile);
if(action == 'D' || action == 'd')
{
}
else if(action == 'C' || action == 'c')
{
}
else
printf("IO Error: Problem with file");
}
}
return 0;
}
Your file is organised in lines, so it's best to read it line-wise. The function for that is fgets, which will read a whole line of a certain maximum length into a char buffer. It keeps the terminating newline (unless the line is truncated because of the max length, but let's not deal with that right now). fgets returns the line buffer or NULL if the end of the file is reached.
Once you have a line, you must examine that line. Your lines all have the same syntax, namely
<action>, <amount>
so you could use sscanf, which isn't nice but quick and dirty. (scanfs error handling, for example, is very basic, so a good strategy is to ignore badly formatted lines altogether.)
The skeleton of your function might look like this:
int ledger(const char *fn)
{
FILE *f;
char line[80]; /* char buffer for line */
int lineno = 0; /* for error reporting */
f = fopen(fn, "r");
if (f == NULL) return -1; /* error */
while (fgets(line, sizeof(line), f)) {
char action;
double amount;
int n;
lineno++;
n = sscanf(line, " %c, %lf", &action, &amount);
if (n < 2) {
printf("Skipping badly formatted line %d\n", lineno);
continue;
}
/* Do stuff, e.g. just print */
printf("%c, %16.2f\n", action, amount);
}
fclose(f);
return 0; /* success */
}
Im taking a class in c programming and I have this project where they give us a half-made project, and we need to finish it and fix some of the functions.
This project is about sort of a social network.
In this project you can send messages to other users (on the same computer for now) by writing the target user and then you enter the message. Afterwards the message is saved in a file called "messages.txt" in the same folder in this Format:
"[At]25/08/2013 [From]user1 [To]user2 [Message]hello whats up?"
"[At]Date [From]user [To]user2 [Message]any user input"
now after writing this, i go to the second user and try to read from the file with this function:
void showUnreadMessages(char* userName) // the function gets the name of the current
user that wishes to read his/hers messages
{
char msg[MAX_MESSAGE];
char toU[MAX_USER_NAME];
char fromU[MAX_USER_NAME];
char at[15];
int count = 0, flag = 0, count1 = 0;
FILE *file = fopen(MESSAGE_FILENAME, "rt"); //open the messages file
FILE *temp;
clearScreen(); //system("CLS")
if (file == NULL) //if the file didn't exict open one
{
printf("No messages\n");
flag = 1;
_flushall();
file = fopen(MESSAGE_FILENAME, "wt");
_flushall();
}
while (!feof(file) && flag == 0) //if the file did exict
{
if (count1 == 0)
{
temp = file;
}
_flushall();
fscanf(file, "[At]%s [From]%s [To]%s [Message]%s\n", at, fromU, toU, msg); //scan one line at a time
_flushall();
if (strcmp(userName, toU) == 0) //if the userNames match than its a message for the current user
{
count++;
}
count1++;
}
fclose(file);
if (count > 0 && flag == 0) //if there are messages to user
{
printf("You have %d new Messages\n", count);
_flushall();
while (!feof(temp))
{
_flushall();
fscanf(temp, "[At]%s [From]%s [To]%s [Message]%s\n", at, fromU, toU, msg); //scan one line at a time to print it for the user
_flushall();
if (strcmp(userName, toU) == 0)
{
printf("New message at %s from: %s\nStart of message: %s\n-----------------------------------------\n", at, fromU, msg);
}
}
fclose(temp);
}
else if (count == 0 && flag == 0)
{
printf("You have no Messages\n");
}
if (!file)
{
remove(MESSAGE_FILENAME);
}
PAUSE; // system("PAUSE")
}
Now when i try to read with this function, it only shows that the message is the first word in the message section on the first line...
For example For "[At]25/08/2013 [From]user1 [To]user2 [Message]hello whats up?"
the message will be "hello"
and it will be printed twice.. i dont know what to do, for some reason when i open the file and do fscanf for one time it also shows that the pointer file starts "up?[At]... (what appears on the second line)"
Please help me if you understand what i did wrong (which i know is a lot)
Thanks in advance
This part of fscanf :
"..etc. [Message]%s\n"
will only read ONE word of "Hello what's up" because %s parses for contiguous characters.
nr_fields = fscanf(file, "[At]%s [From]%s [To]%s [Message]%80c\n"
would read up to 80 characters regardless of spaces etc. in the text message. Also, the destination for %80c must be 80 characters or more!
Also, always test for number of fields found by fscanf.
Finally, fscanf works when used as directed, but it does have some subtle aspects.
One issue is that temp is pointing to a handle that is no longer valid after you call fclose(file) after the first loop. You could use fgets() to read a line and strtok() and strncpy() to split the read string.
I think it would be a good idea to encapsulate the reading in an extra function to reduce code duplication.
Hey I have been trying to count the number of words in my text file, to load up a bunch of words for a Hangman game, from C but I am hitting a brick wall. This piece of code I am using is supposed I am using this piece of code;
FILE *infile;
FILE *infile;
char buffer[MAXWORD];
int iwant, nwords;
iwant = rand() %nwords;
// Open the file
infile = fopen("words.txt", "r");
// If the file cannot be opened
if (infile ==NULL) {
printf("The file can not be opened!\n");
exit(1);
}
// The Word count
while (fscanf(infile, "%s", buffer) == 1) {
++nwords;
}
printf("There are %i words. \n", nwords);
fclose(infile);
}
If anyone has anyone has any suggestions on how to fix this I would be very grateful.
The text file has 1 word per line, with 850 words.
Applied the buffer suggestion, however the word count still came out at 1606419282.
The correction of putting
int nwords = 0;
Worked!! Thank you very much!
So the words are one entry per line?
while (fscanf(infile, "%s", &nwords) == 1); {
++nwords;
}
Doesn't do what you think it does. It reads a string in nwords, which isn't a string.
If you want to do it like this then you need to allocate a string ie char buffer[XXX] which is long enough to contain the longest lien in your data file and use:
while (fscanf(infile, "%s", buffer) == 1) {
++nwords;
}
The variable nwords is never initialized. You cannot assume it to start out as zero.
If it were, you'd get a crash ("divide by zero") on the next line, whose purpose eludes me:
iwant = rand() %nwords;
So, replace
int iwant, nwords;
iwant = rand() %nwords;
by
int nwords = 0;
After reading the first word and whitespace after it, your fscanf RETURNS to input buffer the whitespace. So, the next time you read EMPTY word.
Change proposed:
fscanf(infile, "%s ", &buffer) // notice the space!!! And & before buffer
It will throw off ALL whitespace till the next word. It should work.
P.S. Better not use [f]scanf :-)