sscanf - reading from empty string - c

When I pass an empty string to sscanf, it returns zero and it doesn't change the given variable.
char* ptr = "";
abc = sscanf(ptr, "%s", output);
// abc == 0
Can you let me know the way to work it out?

sscanf awaits the first argument to be the C string that the function processes as its source to retrieve the data. Passing an empty string to this function can't yield your variable to be initialized, since there is nothing this function would initialize it with.
Also note that On success, the function returns the number of variables filled. This count can match the expected number of readings or fewer, even zero, if a matching failure happens. In the case of an input failure before any data could be successfully read, EOF is returned.
Following code, compiled with MinGW (gcc-core 4.5.0-1)
char str[10];
int ret = sscanf("", "%9s", str);
printf("%d\n", ret);
outputs -1 (EOF)
Good way of checking whether sscanf was successful is to check whether it's return value is really equal to the number of provided variables. In this case it would be if (ret == 1). Although many people just check, whether value greater than 0 was returned, to make sure that something has been read and that no error has occurred.

Related

reading string from a file via stdin in c11

So I have a .txt file that I want to read via stdin in c11 program using scanf().
The file is essentially many lines made of one single string.
example:
hello
how
are
you
How can I know when the file is finished, I tried comparing a string with a string made only with eof character but the code loops in error.
Any advice is much appreciated.
Linux manual says (RETURN section):
RETURN VALUE
On success, these functions return the number of input items
successfully matched and assigned; this can be fewer than
provided for, or even zero, in the event of an early matching
failure.
The value EOF is returned if the end of input is reached before
either the first successful conversion or a matching failure
occurs. EOF is also returned if a read error occurs, in which
case the error indicator for the stream (see ferror(3)) is set,
and errno is set to indicate the error.
So test if the return value of scanf equals to EOF.
You can read the file redirected from standard input using scanf(), one word at time, testing for successful conversion, until no more words can be read from stdin.
Here is a simple example:
#include <stdio.h>
int main() {
char word[40];
int n = 0;
while (scanf("%39s", word) == 1) {
printf("%d: %s\n", ++n, word);
}
return 0;
}
Note that you must tell scanf() the maximum number of characters to store into the destination array before the null pointer. Otherwise, any longer word present in the input stream will cause undefined behavior, a flaw attackers can try and exploit using specially crafted input.

what does while(~scanf mean in C?

i watch some code and i don't know what the meaning of while(~scanf
while(~scanf("%s", word+1) !=EOF)
{
int a= strlen(word+1);
i already search google and found nothing on this. Please help
Analyzing the expression while(~scanf("%s", word+1) != EOF):
Run as long as the bitwise-inverted return value of scanf is not equal to the value of EOF.
Analyzing the equivalent expression while(scanf("%s", word+1) != ~EOF):
Run as long as the return value of scanf is not equal to the bitwise-inverted value of EOF.
Assuming that EOF is typically all 1s, this expression is essentially equivalent to:
while(scanf("%s", word+1) != 0)
Which means:
Run as long as the return value of scanf is not 0.
Or simply:
Run until the return value of scanf is 0.
I'm still scratching my head as to whether or not this analysis is correct.
Good question for a job interview (and a good example for how to not write code).
On success scanf will return the number of input items successfully matched. In this case there is only one input item to match therefore on success scanf will return 1, The code above will bitwise invert 1 which will make it -2. Since -2 != EOF, the loop will not end. Since EOF has a value of -1.
If scanf encounters an error or reaches end of input, for example because the user pressed Ctrl-D, it will return EOF and no new value will be placed in the memory location word+1. The code will bitwise invert EOF, which becomes 0, because ~EOF=0. Since 0 != EOF the loop will not end. The call to strlen will return the length of string that was in memory location word+1 prior to calling scanf.
The loop will only end if scanf returns 0, because ~0 = -1 = EOF. This will only happen if scanf was unable to match the input to a string for the conversion specifier "%s".

Trying to read an input integer from user, do not want to accept chars in C

Hi I have a function here where I just want to input an integer and I am aware that characters can be treated like integers but when scanning I would like to only get integers
I think you need to read from standard input and reject the data if it is not an integer.
You can check the value returned by scanf() for that. It will be the number of successful assignments.
int rv, c;
rv=scanf("%d", &guessNum);
if(rv!=1)
{
///Not an integer
while((c=getchar())!='\n' && c!=EOF);
}
Here, scanf() would return 1 if it assigned a value to guessNum and otherwise 0 will be returned.
However, if the scanf() didn't assign to guessNum due to incorrect input, that data will remain in the input buffer which must be cleared before reading data entered after that.
The while((c=getchar())!='\n' && c!=EOF); will take care of that.
This might be similar.
Edit: I just saw Michael's comment.
You are passing guessNum by value to the function. The changes that you make to this variable won't be reflected to the corresponding variable which calls this function. I can't think of any reason for doing that.
Perhaps you want the changes you make to be reflected back to the original variable.
If that's the case, pass the address of the variable to the function (call by reference).
Then the function declaration must be changed to void setMaxGuess(gameState* game, int *guessNum) and you should be passing the address of guessNum with the &guessNum in the function call.
First of all, if you are using recursion you need a proper base case!
Moreover, if you want user input at run-time, you shouldn't put the input variable as a parameter to the function.
Instead just use a temporary variable ( as 1. with your current code you cannot pass a constant to the function, 2. passing a global variable will be useless). Now if you use temporary variable, you can keep it static to prevent re-declaration on every recursive call.
Also since you want max guess (not sure), you should also compare maxGuesses with guessNum.
void setMaxGuess(gameState* game){
static int guessNum;
// Take input
if(guessNum < 0)
//Recurse
else if(game->maxGuesses > guessNum)
//Recurse
else{ //base case
game->maxGuesses = guessNum;
return;
}
}
These were some problems with your approach. Now coming to the question of checking if the user has input a valid integer.
You can take input as int and check if its not a char. Checking that at run-time can be troublesome (See this).
But, instead you can take the input as char array (string if you will), and loop through it and check using isdigit() from ctype.h
int isnum(char *str)
{
while (*str)
if (isdigit(*str++) == 0)
return 0;
return 1;
}
and if it is not a number throw error or otherwise convert back to int using atoi() from string.h.
Note: If you didn't need 0 as input, you could have just used atoi() to check if a string is a number, as it returns 0 for non-numeric values.
Once you are done, you should be able to do something like this in main():
gameState g1;
g1.maxGuesses = 7; //Setting the initial max value
printf("Initial max value = %d\n", g1.maxGuesses );
setMaxGuess(&g1);
printf("Now the max value = %d\n", g1.maxGuesses );

c - Last call to function is being printed again

This is the loop in my a4.c main method that calls the patternsearch function:
while(!feof(stdin)) {
scanf("%s", &word);
patternSearch(grid, word);
}
For some reason that I can't figure out, this prints the last call to patternsearch twice:
For example, look at my output for test3:
Found "tip" at 0 2, L
Found "pop" at 0 0, D
Found "pop" at 2 0, U
Found "key" at 0 3, D
Found "key" at 2 1, R
"nope" - Not Found
"nope" - Not Found
As you can see, the test result for 'nope' was printed twice. :(
I think my problem is similar to the one stated here:
Last line being printed twice (C++)
but I'm not sure.
Step 1 with any problem involving input: test the return value from the input function.
feof() checks if a prior read resulted in an end-of-file. It does not report about future reads.
Code is having trouble with unexpected results of scanf("%s", &word);, yet code did not check the return value from scanf(). Weak code does not check the return value. Robust code does. Research the proper use of scanf() and its return values.
Do not use "%s" without a width limit.
The & in scanf("%s", &word); is likely not needed. Would need to see word declaration to be sure.
char word[100];
while (scanf("%99s", word) == 1) {
patternSearch(grid, word);
}
The issue here was that feof() only returned true when I actually hit the EOF character.
That means that I was calling scanf(), and hitting the EOF;
that means the loop won't iterate again, but I was already in the middle of it.
But scanf() only actually changes the argument I hand it if it successfully reads what I asked;
since it failed (by hitting EOF),
it won't change the character array, which will still contain whatever it did before (i.e. the previous word).
I checked the return value of scanf(); the number it returns, which is the number of arguments it put a new value into;
if that's less than 1, then I didn't actually get a new string (I think it also explicitly returns EOF if it hits the end-of-file; EOF is a #defined constant that's equal to -1 on most platforms, so the <1 check will work anyway).
This is the code that finally worked:
while(!feof(stdin)) {
if (scanf("%s", &word) < 1)
break;
patternSearch(grid, word);
}

Float Checking from Char Array for Limit, Character Checking Front and Back

I am creating a simple Console application where its char *argv[] are expected to be in the form of floating number (such as 5.234, 7.197, and so on)
To ensure that the program only receive user inputs which are truly valid float, I created a function which combines sscanf (ref: character array to floating point conversion) and valid range checks (ref: How can I check if a string can be converted to a float?) results.
//buffer comes from agrv[n]
char MyFloatCheck(char* buffer)
{
float f;
char result;
result = sscanf(buffer, "%f", &f);
result &= isRangeValid(buffer);
return result;
}
Then I tested the the function above with:
Valid input: 12.15
Very large input: 4 x 10^40
Invalid inputs: (a) ab19.114, (b) 19.114ab
The results for my test no 1, 2, and 3(a) are expected:
1
0 (because it is too large)
(a) 0 (because it contains the invalid characters in front of the number)
However the result for 3 (b) is unexepected:
(b) 1 (??)
My questions are:
1. Why is that so?
2. Is there any built-in way to check this kind of input error?
3. Is there any well established workaround?
I am thinking of making my own function which checks the character from the right end to see if it contains invalid characters, but if there is any available built-in way, I would rather use it.
As you noticed, sscanf consumes characters one by one and writes the number that has been read in %f regardless of whether the reading stopped because of the end of the input string, a space, a newline, or a letter.
You would get the same behavior from strtof, a simpler substitute for sscanf(buffer, "%f", &f);:
char *endptr;
f = strtof(buffer, &endptr);
The above two lines give you a simple way to check that the entire string has been consumed after the call to strtof:
if (endptr != buffer && *endptr == 0) …
The condition endptr != buffer means that a floating-point number has been read. Otherwise, f is zero but that doesn't mean anything since no character was consumed. *endptr == 0 means that the entire input buffer was consumed in reading the floating-point number, which appears to be what you are looking for.

Resources