So I'm scanning strings from a file and comparing them with the string from a stack. If i scan all the string from the file and don't find the one from the stack i want to rewind the file, pop the string from the stack and continue unless the stack is empty.
char buffer[ENOUGH];
while(fscanf(stream, "%s", buffer) != EOF)
{
if(strcmp(buffer, tos->string) == 0)
{
pop(&tos);
//do something with the string
}
// here i would need something to stop the EOF
}
I have a file like this:
02.01.2021 8:45 8:57 9:45
03.01.2021 15:40 16:30
05.01.2021 07:30 08:30
And stack contains:
01.01.2021 <- TOS
02.01.2021
03.01.2021
04.01.2021
So i need to find 01.01.2021 in file and if not there remove it from stack.
To avoid reading the stream till the end of file, just break from the loop. Also note that you should compare the return value of fscanf() to 1 to detect all cases of failure. fscanf() will not return 0 for the %s or %c conversions, but would do so for other specifiers in case of a match failure that does not happen at end of file. Also pass a maximum number of characters to avoid undefined behavior on long input strings.
char buffer[100];
while (fscanf(stream, "%99s", buffer) == 1) {
if (strcmp(buffer, tos->string) == 0) {
pop(&tos);
//do something with the string
break; // break from the loop.
}
}
rewind(stream);
Probably something like this:
while (1)
{
if (fscanf(stream, "%s", buffer) != EOF)
{
if (strcmp(buffer, tos->string) == 0)
{
if (stack is empty)
break;
pop(&tos);
//do something with the string
}
}
else
{
fseek(stream, 0, SEEK_SET);
}
}
This is untested code, but you should get the idea.
But there is something flawed in your algorithm anyway: what happens if strcmp(buffer, tos->string) is never true?
You can use a method,
#include <stdio.h>
void compare(){
char buffer[ENOUGH];
while(fscanf(stream, "%s", buffer) != EOF){
if(strcmp(buffer, tos->string) == 0){
//do something
}
}
}
int main(void) {
while(!stactIsEmpty()){
pop();
compare();
}
return 0;
}
This code is not tested. I hope you'll get the idea.
Related
Is it possible to use fscanf to read words without symbols from a text file
this function prints one word on a single line but if the word had comma or brackets it will print those too is there anyway to only print letters?
void load(const char *file)
{
FILE *inFile = fopen(file , "r");
if (inFile == NULL )
{
return false;
}
char word[LENGTH];
while (fscanf(inFile, "%s", word) != EOF)
{
printf("%s\n", word);
}
}
Your function will not compile at all as it is returning value and it is declared as void
Read char by char and print only what you want.
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
bool load(const char *file)
{
FILE *inFile = fopen(file , "r");
if (inFile == NULL )
{
return false;
}
char word;
int retval;
while ((retval = fscanf(inFile, "%c", &word)) != EOF && retval == 1)
{
if(isalnum((unsigned char)word) || isspace((unsigned char)word))
printf("%c", word);
}
fclose(inFile);
return true;
}
Is it possible to use fscanf to read words without symbols from a text file
Well, yes...
You can use a scanset to tell which characters to match. Like:
%[a-zA-Z]
This will match/accept all upper and lower case letters and reject all other characters.
But... That will give you another problem. When the next character the the file doesn't match, the file pointer won't be advanced and you are kind of stuck. To handle that you need a way to skip non-matching characters, e.g. fgetc to read a single character.
Something like:
char word[32];
while (1)
{
int res = fscanf(inFile, "%31[a-zA-Z]", word); // At most 31 characters and only letters
if (res == EOF) break;
if (res == 1)
{
printf("%s\n", word);
}
else
{
// Didn't match, skip a character
if (fgetc(inFile) == EOF) break;
}
}
With a file like:
Hallo World, having() fun ....
Oh,yes...
the output is
Hallo
World
having
fun
Oh
yes
An alternative that only uses fsanf could be:
char word[32];
while (1)
{
int res = fscanf(inFile, "%31[a-zA-Z]", word); // Read letters
if (res == EOF) break;
if (res == 1)
{
printf("%s\n", word);
}
res = fscanf(inFile, "%31[^a-zA-Z]", word); // Skip non-letters
if (res == EOF) break;
}
Notice the ^ in the second scanset. It changes the meaning of the scanset to be "Don't match ...." So the code alternate between "Read a word consisting of letters" and "Skip everything not being letters" which is likely a better way of doing this than the fgetc method above.
That said, I normally prefer reading the file using fgets and then parse the buffer afterwards (e.g. using sscanf) but that's another story.
I'm creating a file management program for a project in C and I have this error which is probably obvious to most programmers but since I'm really bad I can't spot what I have done wrong. My main program is an interface which asks users for a file name and assigns it to the array fileName.
int main() {
char fileName[50];
assignFileName(fileName);
char option[2];
int checkInput;
do {
printf("File management program. Options :\n '1' for File operations (Create, copy, delete or display file)\n '2' for Line operations (Append, delete, display or insert line to file)\n '3' for General operations (Display change log or number of lines for file)\n '4' to select a new file\n '9' to exit program\n");
printf("aaa %s\n", fileName); //first printf check - prints "aaa" and value in fileName
checkInput = checkUserInput(option);
printf("aaa %s\n", fileName); // second printf check = prints only "aaa"
if (checkInput == 1) {
//... etc
}
void assignFileName(char *fileName) {
printf("Enter file name to operate on, or 'E' to exit the program.\n");
do {
if ((fgets(fileName, 50, stdin)) != NULL) {
if (fileName[strlen(fileName)-1] = '\n') {
fileName[strlen(fileName)-1] = '\0';
}
if (strlen(fileName) == 1 && *fileName == 'E') {
exit(0);
} else if (strlen(fileName) == 0) {
printf("Error : Please enter a file name or 'E' to exit.\n");
}
} else {
perror("Error assigning file name ");
}
} while (strlen(fileName) == 0);
}
I'm fairly sure this code is fine. There's probably lots of ways to make it more efficient and if anyone wants to offer their input I will take it into account. However, the problem is later on in the code. I have 2 printf statements to check the value of fileName. After the first one, everything seems to be alright but then the for the second one the value of fileName seems to be cleared, so something is clearly happening in checkUserInput. All checkUserInput does is check the user enters a single digit number :
void flush() {
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) {
}
}
int checkUserInput(char *input) {
if (fgets(input, 3, stdin) != NULL) {
printf("you entered %c\n", input[0]);
if (input[1] == '\n') {
return 1;
} else {
flush();
printf("Error : Please enter one of the options given.\n");
}
} else {
printf("Error : Please try again.\n");
}
return 0;
}
I put more printf statements to error check and it seems after the call to fgets(input, 3, stdin) the value in fileName is cleared. Can anyone explain to me why this is the case? I'm not even passing the array fileName to checkUserInput so I don't even know how the program is changing it. This is a link to what the console displayed : (can't post images sorry not 10 rep).
https://cdn.discordapp.com/attachments/708320229737889832/802557193043050516/unknown.png
All help would be very appreciated. Thanks.
if (fileName[strlen(fileName)-1] = '\n') should be:
if (fileName[strlen(fileName)-1] == '\n')
Note that you can strip the trailing newline with this simple line:
filename[strcspn(filename, "\n")] = '\0';
error was char option[2] when it should be char option[3]. Thanks to #Nate Eldredge and #M Oehm
Here is my code:
#include "game.h"
#define LINEINPUT 30
int loadMainMenu(void);
void playGame()
{
Cell board[BOARD_HEIGHT][BOARD_WIDTH];
char input[LINEINPUT + EXTRA_SPACES];
printInstructions();
while( getchar() != '\n' );
initialiseBoard(board);
while(TRUE)
{
displayBoard(board, NULL);
printf("At this stage of the program, only two commands are acceptable:\n");
printf("load <g>\n");
printf("quit\n");
fgets(input, LINEINPUT , stdin);
if(input[strlen(input) - 1] != '\n')
{
printf("BUFFER OVERFLOW\n");
readRestOfLine();
EXIT_FAILURE;
continue;
}
if(strcmp(input, "test") == 0)
{
printf("success!\n");
continue;
}
if(strcmp(input, "load 1") == 0)
{
printf("lfdsfsdfoad");
loadBoard(board, BOARD_1);
continue;
}
if(strcmp(input, "load 2") == 0)
{
loadBoard(board, BOARD_2);
continue;
}
if(strcmp(input, "quit") == 0)
{
loadMainMenu();
break;
}
}
}
i have cut it down so that it doesn't take up too much space. I was editing some of it this morning trying to fix things up and somehow, it doesnt read my inputs anymore. Well it does read my inputs but doesnt use strcmp to check if input matches and run the functions in the if statements. It was working fine previously but i did not change anything much.
As evidenced by your first if statement, fgets() returns strings with the \n line ending present. You'll want to either strip off that character, or add it to the strings you're testing against.
So the current function is supposed to see anything stored between two pound signs (#abc# should give back abc), but if I want to error check to see if there's a pound sign missing, or there's nothing between the pound signs, or that the length of the string in between the two pound signs is greater than a certain number of characters, do I use the fscanf function to do that?
Here's what the fscanf code looks like:
if (fscanf(fp, " %c%[^#]%c", &start, buffer, &end) == 3) {
return strdup(buffer);
} else {
return NULL;
}
do I use the fscanf function to do that?
No, you don't. Using the scanf() family of functions is very rarely a good idea.
char buf[0x1000];
// expect leading `#'
int ch = fgetc(fp);
if (ch != '#') {
puts("Error, missing # at beginning of input");
exit(-1);
}
// read until terminating `#' or until the buffer is exhausted
char *p = buf;
while ((ch = fgetc(fp)) != '#' && p - buf < sizeof(buf)) {
*p++ = ch;
}
// expect terminating `#'
if (ch != '#') {
puts("Error, missing # at end of input");
exit(-1);
}
If you need to deal with the zero-characters case, then probably fscanf() is not the right tool. There's a reasonable argument that fscanf() is seldom the correct tool; you'd do better with fgets() and sscanf().
In this case, I'd collect lines until there's one that's not blank (since that's what the fscanf() does), and then search for the # symbols with strchr():
char line[4096];
while (fgets(line, sizeof(line), fp) != 0)
{
if (strspn(line, " \t\n") == strlen(line))
continue;
char *hash1 = strchr(line, '#');
if (hash1 == 0)
...error no hashes...
else
{
char *hash2 = strchr(hash1+1, '#');
if (hash2 == 0)
...second hash is missing...
if (hash2 - hash1 > MAX_PERMITTED_STRING_LEN)
...too long a string...
*hash2 = '\0';
char *res = strdup(hash1);
}
}
EDIT:
complete code with main is here http://codepad.org/79aLzj2H
and once again this is were the weird behavious is happening
for (i = 0; i<tab_size; i++)
{
//CORRECT OUTPUT
printf("%s\n", tableau[i].capitale);
printf("%s\n", tableau[i].pays);
printf("%s\n", tableau[i].commentaire);
//WRONG OUTPUT
//printf("%s --- %s --- %s |\n", tableau[i].capitale, tableau[i].pays, tableau[i].commentaire);
}
I have an array of the following strcuture
struct T_info
{
char capitale[255];
char pays[255];
char commentaire[255];
};
struct T_info *tableau;
This is how the array is populated
int advance(FILE *f)
{
char c;
c = getc(f);
if(c == '\n')
return 0;
while(c != EOF && (c == ' ' || c == '\t'))
{
c = getc(f);
}
return fseek(f, -1, SEEK_CUR);
}
int get_word(FILE *f, char * buffer)
{
char c;
int count = 0;
int space = 0;
while((c = getc(f)) != EOF)
{
if (c == '\n')
{
buffer[count] = '\0';
return -2;
}
if ((c == ' ' || c == '\t') && space < 1)
{
buffer[count] = c;
count ++;
space++;
}
else
{
if (c != ' ' && c != '\t')
{
buffer[count] = c;
count ++;
space = 0;
}
else /* more than one space*/
{
advance(f);
break;
}
}
}
buffer[count] = '\0';
if(c == EOF)
return -1;
return count;
}
void fill_table(FILE *f,struct T_info *tab)
{
int line = 0, column = 0;
fseek(f, 0, SEEK_SET);
char buffer[MAX_LINE];
char c;
int res;
int i = 0;
while((res = get_word(f, buffer)) != -999)
{
switch(column)
{
case 0:
strcpy(tab[line].capitale, buffer);
column++;
break;
case 1:
strcpy(tab[line].pays, buffer);
column++;
break;
default:
strcpy(tab[line].commentaire, buffer);
column++;
break;
}
/*if I printf each one alone here, everything works ok*/
//last word in line
if (res == -2)
{
if (column == 2)
{
strcpy(tab[line].commentaire, " ");
}
//wrong output here
printf("%s -- %s -- %s\n", tab[line].capitale, tab[line].pays, tab[line].commentaire);
column = 0;
line++;
continue;
}
column = column % 3;
if (column == 0)
{
line++;
}
/*EOF reached*/
if(res == -1)
return;
}
return ;
}
Edit :
trying this
printf("%s -- ", tab[line].capitale);
printf("%s --", tab[line].pays);
printf("%s --\n", tab[line].commentaire);
gives me as result
-- --abi -- Emirats arabes unis
I expect to get
Abu Dhabi -- Emirats arabes unis --
Am I missing something?
Does printf have side effects?
Well, it prints to the screen. That's a side effect. Other than that: no.
is printf changing its parameters
No
I get wrong resutts [...] what is going on?
If by wrong results you mean that the output does not appear when it should, this is probably just a line buffering issue (your second version does not print newline which may cause the output to not be flushed).
It's highly unlikely that printf is your problem. What is far, far more likely is that you're corrupting memory and your strange results from printf are just a symptom.
There are several places I see in your code which might result in reading or writing past the end of an array. It's hard to say which of them might be causing you problems without seeing your input, but here are a few that I noticed:
get_lines_count won't count the last line if it doesn't end in a newline, but your other methods will process that line
advance will skip over a newline if it is preceded by spaces, which will cause your column-based processing to get off, and could result in some of your strings being uninitialized
get_word doesn't do any bounds checks on buffer
There may be others, those were just the ones that popped out at me.
I tested your code, adding the missing parts (MAX_LINE constant, main function and a sample datafile with three columns separated by 2+ whitespace), and the code works as expected.
Perhaps the code you posted is still not complete (fill_table() looks for a -999 magic number from get_word(), but get_word() never returns that), your main function is missing, so we don't know if you are properly allocating memory, etc.
Unrelated but important: it is not recommended (and also not portable) to do relative movements with fseek in text files. You probably want to use ungetc instead in this case. If you really want to move the file pointer while reading a text stream, you should use fgetpos and fsetpos.
Your approach for getting help is very wrong. You assumed that printf had side effects without even understanding your code. The problem is clearly not in printf, but you held information unnecessarily. Your code is not complete. You should create a reduced testcase that compiles and displays your problem clearly, and include it in full in your question. Don't blame random library functions if you don't understand what is really wrong with your program. The problem can be anywhere.
From your comments, i am assuming if you use these printf statements,
printf("%s\n", tableau[i].capitale);
printf("%s", tableau[i].pays);
printf("%s\n", tableau[i].commentaire);
then everything works fine...
So try replacing your single printf statement with this. (Line no. 173 in http://codepad.org/79aLzj2H)
printf("%s\n %s %s /n", tableau[i].capitale, tableau[i].pays, tableau[i].commentaire);