I am reading an Integer with scanf and at the same time checking the number of digit read by scanf with the format %n, the first output is always correct but after that the output increased one more. That is scanf reads the last "\n" for the second scanf.
I know this kind of problem with scanf and char that is scanf("%c",&cval) ---> to scanf(" %c",&cval) leaving some little space to avoid scanf reading the end of line. but what is with integers?
I have already seen some question here Link here and they all seems to think scanf() is "retarted" and fget() should always be used.. Is it really so and is it good to avoid it in projects? I mean to void all this kind of bugs and is there a way to prevent this.
Do i have to use fget() for this or is there a way to fix this in scanf(). All comments are welcome, and thanks for your time. I just want to know if there is a way to fix it, i know how to use %n.
#include <stdio.h>
int main(void) {
int i =0 ,byte_count = 0,val;
printf("Enter a number: ");
scanf("%d%n",&val,&byte_count);
while (i < 3){
printf("byte count is: %d\n",byte_count);
scanf("%d%n",&val,&byte_count);
i++;
}
return 0;
}
the first output is always correct but after that the output increased one more.
The value of n in subsequent scans is one greater than expected because they scanned in the trailing '\n' of the previous entry. #BLUEPIXY
\n3876 --> 5 characters
not
3876
Also reset n each loop in case the scan of "%d" failed.
int val = 0; // add initialization
while (i < 3){
printf("byte count is: %d\n",byte_count);
byte_count = 0; // add
scanf("%d%n",&val,&byte_count);
i++;
}
To consume white-space in the stdin use " "
while (i < 3){
printf("byte count is: %d\n",byte_count);
byte_count = 0;
scanf(" "); scanf("%d%n",&val,&byte_count);
i++;
}
%n captures all the characters processed by scanf including leading whitespace. Using %n twice can correct that. The format string skips leading whitespace and then gets the beginning count of characters. Then the integer is scanned and finally the total count of characters is captured. The difference in the count is the characters in the integer.
Always check the return of scanf as the input stream may need cleaning.
int begin = 0;
int end = 0;
int val = 0;
int clean = 0;
int result = 0;
do {
if ( ( result = scanf(" %n%d%n",&begin,&val,&endn)) != 1) {// scan one int
while ( ( clean = getchar ( )) != '\n') {//clean bad input
if ( clean == EOF) {
fprintf ( stderr, "problem reading input\n");
exit ( 1);
}
}
}
else {//scanf success
printf("byte count is: %d\n",end-begin);
}
} while ( result != 1);
Indeed you should always use fgets() plus sscanf() or strtod() or strtol() etc. Don't bother trying to make plain scanf() work, it's just not as effective as your other options.
Related
So after scanf, the printf(); skips the first line
I have read some questions that tells that , "%[^\n]" must be " %[^\n]" to skip the newline.
I have tried it both, but it still print the same result and now I don't know why it doesn't work.
Example input
Enter number of Materi: 4
Materia 1 name : a
Materia 2 name : b
materia 3 name : c
materia 4 name : d
Output:
Materia - 1 : R╒fu
Materia - 2 : a
Materia - 3 : b
Materia - 4 : c
#include<stdio.h>
#include<windows.h>
int main(int argc, const char *argv[]){
int i;
int V;
printf("Enter number of Materi: ");
scanf("%d", &V); fflush(stdin);
//Insert materia
char materia[V][50];
for(i = 0; i < V; i++){
printf("Materia %d name : ", i+1);scanf("%[^\n]", &materia[i][50]);fflush(stdin);
}
for(i = 0; i < V; i++){
printf("Materia - %d: %s\n", i+1, materia[i]);
}
system("pause");
return 0;
}
There are several mistakes in the program
The array passed to scanf is wrong.
fflush(stdin) is non-standard, although Windows does support it it's not portable. But you aren't using Windows because it does not support the VLA char materia[V][50];
The newlines which the scanf format "%[^\n]" will stop at, are already the next character in the input buffer.
The return value from scanf was not checked. It is the number of items successfully scanned.
You can have buffer overflow because the input string length is not restricted.
Here is the adjusted code:
#include<stdio.h>
int main(int argc, const char *argv[]){
int i;
int V;
printf("Enter number of Materi: ");
if(scanf("%d", &V) != 1) {
/* add some error message */
return 1;
}
// fflush(stdin); // removed
//Insert materia
char materia[V][50];
for(i = 0; i < V; i++){
printf("Materia %d name : ", i+1);
// add a space to filter the newline
// correct the array passed
// and restrict the length to prevent buffer overflow
if(scanf(" %49[^\n]", materia[i]) != 1) {
/* add some error message */
return 1;
}
// fflush(stdin); // removed
}
for(i = 0; i < V; i++){
printf("Materia - %d: %s\n", i+1, materia[i]);
}
return 0;
}
About the newlines. Format specs %d and %s and %f automatically filter out leading whitespace, but %c and %[] and %n do not. The scanf functions stop at the first character they cannot convert, which is left in the input buffer. The %[^\n] tell it to stop at the first newline. But there is one already there, from the first %d scanf and it needs to be removed, also in subsequent iterations and adding the space does that job. Trying to remove it afterward is clumsy and not guranteed to work.
You must check the return value from scanf every time it is used. It is the number of items successfully scanned. Here, it should be 1 in both uses. So if you have two items in one statement, its return value must be 2.
In the line:
scanf("%[^\n]", &materia[i][50]);
You are storing the inputed string in the address of materia[i][50], effectively storing it outside the bounds of the array.
Something interesting happens here, 2D array storage is contiguous as if it was a one dimensional vector, what happens is you are storing the first string in the beginning of the second line of the array, the second on the third and so on, leaving the first empty. That's the rational for the output the program produces.
Correct you code with:
#include<stdlib.h>
//...
if(scanf(" %49[^\n]", materia[i] != 1) {
puts("Read error");
return EXIT_FAILURE;
}
49 character + the nul terminator to avoid overflow, a space in the beginning of the specifier avoids the consuption of blank characters left in the stdin buffer. Always verify scanf return to avoid reading errors.
Some other issues:
fflush(stdin) should be removed as fflush is meant to be called on an output stream.
Variable lenght arrays can cause stack overflow if enough memory is consumed, in this case it's not likely, but it's something to keep in mind.
Use fgets instead of scanf. The newline character is consumed as a character by your subsequent scanf. That's why you are facing this problem.
int main() {
char userInput[100]; //Store user input
//Take user input
//scanf(" %s",&userInput);
//scanf("%[^\n]s",&userInput);
//scanf("%[^\n]", &userInput);
//gets(userInput);
scanf("%[]s", &userInput); //This takes input but doesnt leave input loop
printf(" %s",userInput);
//i = index to start for looping through the string, starting at the beginning
//count = Stores occurrences of '$'
//inputLength = length of the input, used for limit of loop
int i =0,count =0;
int inputLength = strlen(userInput);
//Loop through the user input, if the character is '$', the integer count will be incremented
for (i; i < inputLength; i++){
if (userInput[i] == '$'){
count++;
}
}
printf("%d", count);
return 0;
}
Hi i'm having some issues with my code, i need to take an input of 3 lines and count the number of'$' in the input. The input method not commented "scanf("%[]s", &userInput);" is the one only i have discovered to take all 3 lines of input, BUT i can't break the input loop and continue with my program.
Any help would be greatly appreciateed
To read 3 lines with the cumbersome scanf(), code needs to look for '$', '\n', and EOF. The rest of input is discardable.
int count = 0;
int line = 0;
while (line < 3) {
scanf("%*[^$\n]"); // Scan for any amount of characters that are not $ nor \n,
// "*" implies - do not save.
char ch;
if (scanf("%c", &ch) != 1) { // Read next character.
break;
}
if (ch == '$') count++;
else line++;
}
printf("$ count %d\n", count);
As #chux suggested, reading with fgets provides a convenient way to protect from buffer overrun and without having to hard code field-width modifiers in scanf conversion specifiers.
Here, if all you need to do is count the number of '$' characters found in your input (regardless of how many lines), you can simply read ALL the input in fixed sized chunks of data. fgets does just that. It doesn't matter if you have one line, or one million lines of input. It also doesn't matter if your input lines are one-character or one million characters long. You can simply read each line and count the number of '$' found within each chunks of data read, keeping a count of the total found.
You can do this for any character. If you wanted to also count the number of line, you can simply check for '\n' characters and keep a total there as well. The only corner-case in counting lines with fgets is to insure you protect against a non-POSIX end-of-file (meaning a file with no '\n' as the final character). There are a couple of ways to handle this. Checking that the last character read was a '\n' is as good as any.
Putting the pieces together, and protecting against a non-POSIX eof, you could do something similar to the following, which simply reads all data available on stdin and outputs a final '$' and line count:
#include <stdio.h>
#define MAXC 100
int main (void) {
char buf[MAXC] = ""; /* buffer to hold input in up to MAXC size chunks */
size_t lines = 0, dollars = 0; /* counters for lines and dollar chars */
int i = 0;
while (fgets (buf, MAXC, stdin)) /* read all data */
for (i = 0; buf[i]; i++) /* check each char in buf */
if (buf[i] == '$') /* if '$' found */
dollars++; /* increment dollars count */
else if (buf[i] == '\n') /* if '\n' found */
lines++; /* increment line count */
if (i && buf[i-1] != '\n') /* protect against non-POSIX eof */
lines++;
/* output results */
printf ("input contained %zu lines and %zu '$' characters.\n",
lines, dollars);
return 0;
}
Look things over and let me know if you have further questions.
scanf("%[]s", &userInput);" is the one only i have discovered to take all 3 lines of input, BUT i can't break the input loop and continue with my program.
"%[]" is an invalid scanf() specifier. Anything may happen, it is undefined behavior, including taking all lines in and not returning.
The 's' in the format serves no purpose here - drop it.
Yes fgets() is best but let us abuse scanf() to read 3 lines and look for '$'.
char line[3][100] = {0};
// v--------- Consume all leading whitespace
// | vv ----- limit input to 99 characters as scan() appends a \0
// | || v-v-- Look for "not \n"
#define FMT_1LINE " %99[^\n]"
// Let the compiler concatenate the 3 formats into 1 string for scanf
int scan_count = scanf(FMT_1LINE FMT_1LINE FMT_1LINE, line[0], line[1], line[2]);
// Check return value
if (scan_count == 3) {
// Successfully read 3 lines
int count = 0;
for (int line_index = 0; line_index < 3; line_index++) {
char *s = line[line_index];
while (*s) { // no need for strlen(), just loop until the null character
count += *s == '$';
s++;
}
}
printf("$ count %d\n", count);
}
You write:
scanf("%[]s", &userInput); //This takes input but doesnt leave input loop
but the comment is at best misleading. Your format string is malformed, so the behavior of the scanf call is undefined. An empty scan set (between the [] in the format) does not make sense, because the resulting field could never match anything. Therefore, a ] appearing immediately after the opening ] of the scan set is interpreted as a literal character not the ending delimiter. Your scan set is therefore unterminated.
Note, too, that %[ is its own field type, separate from %s. An 's' following the closing ] of the scan set is not part of such a field descriptor, but rather an ordinary character to match.
A trivial way to do this with scanf would be to read characters one at a time in a loop via a %c field. This is probably not what the exercise is looking for, and it's a hack to use scanf() instead of getchar() for this purpose, but perhaps it would serve:
int nl_count = 0;
int dollar_count = 0;
do {
char c;
int result = scanf("%c", &c);
if (result != 1) {
break;
}
switch (c) {
case '\n':
nl_count++;
break;
case '$':
dollar_count++;
break;
}
} while (nl_count < 3);
I'm afraid it would be much more complicated to do it safely reading multiple characters at a time with a %[ field, and there is no safe way to read all three lines in one scanf call, unless you can rely on the input lines not to exceed a line length limit known to you.
int readMatrix() {
char userInput[100][3]; //Store user input
int j = 0, m = 0;
for(m = 0; m < 3; m++){
scanf("%s", &userInput[j][m]); //This takes input (Ex: 22 *(enter)* 33$ *(enter)* 66$ *(enter)*
j++; //increase the column
}
int i =0,count =0;
m = 0;
//Loop through the user input, if the character is '$', the integer count will be incremented
for (i = 0; i < 100; i++){
for(m = 0; m < 3; m++){
if (userInput[i][m] == '$'){
count++;
}
}
}
printf("%d", count);
return 0;
}
I'm using command line to input a text file to a program, which uses the info from the file to display other values accoring what was in that text file.
test.exe < input.txt (Command line)
File looks like this:
2
abc 123
qwe 456
Number 2 tells me how many things program has to read. (Named COUNT in code)
double number[MAXVALUE];
char name[MAXVALUE][MAXLENGTH];
for(i = 0; i < COUNT; i++)
{
scanf("%s %lf", name[i], &number[i]);
}
This what the input code looks like.
Now, what happens is if I put 3 as COUNT, the program will try to read 3 lines and displays the 3rd line as gibberish.
How can I prevent the scanf from operating, if the values entered are non-existant?
I tired if(scanf(....) != 1) but it doesn't seem to work.
First of all, avoid invoking undefined behavior %lf is for reading double, not int.
Then, the return value of scanf() is useful for checking if reading is successful.
Quote from N1570 7.21.6.4 The scanf function, paragraph 3:
The scanf function returns the value of the macro EOF if an input
failure occurs before the first conversion (if any) has completed.
Otherwise, the scanf function returns the number of input items
assigned, which can be fewer than provided for, or even zero, in the
event of an early matching failure.
Here is an example of improved code:
double number[MAXVALUE];
char name[MAXNAME][MAXLENGTH];
for(i = 0; i < COUNT; i++)
{
if (scanf("%s %lf", name[i], &number[i]) != 2)
{
fputs("read error\n", stderr);
exit(1); /* stdlib.h should be included to use this */
}
}
Use a while loop to iterate as long as two items have been scanned. Increment i and check to make sure it is less than COUNT or MAXVALUE. i will then have the number of elements completed in the arrays.
double number[MAXVALUE] = {0.0};
char name[MAXVALUE][MAXLENGTH] = {{ '\0'}};
int i = 0;
while ( ( scanf("%s %lf", name[i], &number[i])) == 2)
{
i++;
if ( i >= COUNT || i >= MAXVALUE)
{
break;
}
}
I'm having trouble with scanf (and before anyone mentions it, I have to use it. I can't use getchar(), fgets(), and various other things). In my code below, I need to add (or subtract) two real numbers or integers, and store the sum to memory. I think I can sort out the memory stuff myself, but the problem is with printing the result of the sum.
I have to type '6+6', press enter, and then input another character for the original sum to be displayed. Also if I type '6+6+' the program acts I want it to.
I imagine I've made a very basic error. I'm very tired.
#include <stdio.h>
#include <stdlib.h>
int main(){
char memoryExitSwitch[256];
int q =1;
double operandOneHalf;
double operandTwo;
double result = 0.0;
while(q == 1){
scanf("%lf" "%lf ", &operandOneHalf, &operandTwo);
scanf( " %s", memoryExitSwitch);
switch (memoryExitSwitch[0]) {
case 'p':
result = memoryExitSwitch[1] + operandTwo;
printf("ANS1= %lf\n", result);
memoryExitSwitch[1] = result;
break;
case 'q':
q = 0;
break;
default:
result = operandOneHalf + operandTwo;
printf("ANS2= %lf\n", result);
memoryExitSwitch[1] = result;
break;
}//switch
}//main while loop q
return 0;
}
Various problems
The trailing space "%lf " obliges scanf() to detect following non-white-space after the number, delaying scanf() return. #Jonathan Leffler. The " " says to consume all optional following white-space. scanf() needs to see some non-white-space to know it has seen all the following white-space.
// scanf("%lf" "%lf ", &operandOneHalf, &operandTwo);
// v--- no space
if (scanf("%lf" "%lf", &operandOneHalf, &operandTwo) != 2) return -1;
Good code limits the input width to prevent buffer overflow
char memoryExitSwitch[256];
// scanf( " %s", memoryExitSwitch);
// v ---- space not needed
// |255 - lit input to 1 less than buffer size
// | | v--- Check result
if (scanf( "%255s", memoryExitSwitch) != 1) return -1;
Your program waits for a non-whitespace character after the second number, because of the trailing space after the second %lf here:
scanf("%lf" "%lf ", &operandOneHalf, &operandTwo);
..and if you fix that, it will still wait for a non-whitespace string to be input after the two numbers, because of the following call to scanf():
scanf( " %s", memoryExitSwitch);
For my programming class I've written a program to calculate the sum of divisors. So I've gotten to my final part which is error checking, which I am having a problem with if I read a character in. I have searched on S.O. earlier,as well as tried to figure something out, and couldn't find a solution that works for endless negative numbers until 100.
When I hit a character it sets it to 0 and just goes to the end, where I want it to exit once it reads it in
int main (void){
int userIN=0;
int i = 0;
int next = 0;
int temp= 105;
int cycle;
puts("Enter up to 10 integers less than or equal to 100");
while(scanf("%d ", &userIN) !=EOF && (i < 10))
{
if(userIN > 100){
printf("Invalid Input\n");
exit(1);
}
else if(userIN < 100)
{
Thanks for the help in advance
EDIT: The program is cycling through correctly, My Issue is error checking for a character being entered not anything with the code itself
scanf() returns a value other than EOF if it cannot read the values specified by the format string (e.g. with %d, it encounters data like foo). You can check for that. The caveat is that it does not read the offending data from stdin, so it will still be there to affect the next call of scanf() - which can result in an infinite loop (scanf() reporting an error, call scanf() again, it encounters the same input so reports the same error).
You are probably better off reading a whole line of input, using fgets(). Then check the input manually or use sscanf() (note the additional s in the name). The advantage of such an approach is that it is easier to avoid an infinite loop on unexpected user input.
You could loop while i is less than 10. The first if will see if scanf failed. If so the input buffer is cleared and the while loop tries again. If EOF is captured, then exit. If scanf is successful, the input is compared to 100 and if in range, the while loop counter is incremented.
Declare int ch = 0;
while ( i < 10) {
printf("Enter %d of 10 integers. (less than or equal to 100)\n", i + 1);
if(scanf(" %d", &userIN) != 1)
{
while ( ( ch = getchar()) != '\n' && ch != EOF) {
//clear input buffer
}
if ( ch == EOF) {
exit ( 1);
}
}
else {
if(userIN > 100){
printf("Invalid Input\n");
}
else
{
i++;// good input advance to the next input
printf("Valid");
}
}
}