Why is scanf(); skipping the first line? - c

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.

Related

'\n' saved in array after memset (C)

I read chars until '\n', convert them to int and sum the numbers until the result is only one digit.
I can't use mod or .
The first run went well, but the second one keep running and not waiting to \n.
any reason for keeping the '\n'?
#include<stdio.h>
int main(){
char str[8], conv_str[8],c;
int i,val,ans = 0;
while(1){
printf("Enter 8 values(0-9) :\n");
scanf("%[^\n]", str); // Scan values to str untill \n
for(i = 0;i < 8;i++){
val = str[i]-48; //convert from asci to int
ans += val;
}
while(ans > 9){
// itoa convert int to string, str(the input) is the buffer and 10 is the base
itoa(ans,conv_str,10);
ans = (conv_str[0]-48) + (conv_str[1]-48) ;
}
printf("the digit is: %d", ans);
printf("\ncontinue? (y/n)\n");
scanf("%s", &c);
if (c == 'n')
break;
memset(str, 0, sizeof(str));
}
return 0;
}
TIA
You have multiple problems in the code. Some of them are
scanf("%s", &c); is wrong. c is a char, you must use %c conversion specifier for that.
You never checked for the return value of scanf() calls to ensure success.
While scanning for character input, you did not clear the buffer of any existing inputs. Any existing character, including a newline ('\n') already present in the buffer will be considered as a valid input for %c. You need to clear the buffer before you read a character input.

Looping scanf horizontally

If I use this code:
int a, b[100];
scanf("%d", &a);
for (int x = 0; x < a; x++) {
scanf(" %d", &b[x]);
}
For example if
1st input: 3
2nd input: 4
3rd input: 3
4th input: 1
The output on the screen will be like this (because I use enter at the end of the scanf on every loop)
3
4
3
1
I want to make a code which will loop the second scanf in the for loop horizontally without pressing enter (but use space) until the end of the loop, like this:
scanf(" %d %d %d", &b[x], &b[x+1], &b[x+2]);
You can type the count and the entries on a single line, separated by spaces and the current code will parse them in a single uninterrupted flow because scanf() skips any whitespace before a value for %d, be it spaces, tabs, newlines...
Note that the format " %d" is redundant: %d skips any pending whitespace before the integer, and a space in the format string means exactly the same thing. Just use scanf("%d", &b[x]);
Note also that you should add a safety check to avoid scanning values beyond the end of the array and you should test the return value of scanf() to avoid undefined behavior on invalid input.
Here is a modified version:
#include <stdio.h>
int main() {
int a, x, b[100];
if (scanf("%d", &a) == 1) {
for (x = 0; x < 100 && x < a; x++) {
if (scanf("%d", &b[x]) != 1)
break;
}
printf("read %d values:", x);
for (int i = 0; i < x; i++)
printf(" %d", b[i]);
printf("\n");
}
return 0;
}
The scanf function will read and ignore any whitespace characters encountered before the next non-whitespace character (whitespace characters include spaces, newline and tab characters). A single whitespace in the format string validates any quantity of whitespace characters extracted from the stream (including none).
So whether you use ENTER (newline) or a SPACE (single or multiple) does not make a difference for reading the input values in this case.
See this online reference for scanf for more details on how scanf works.

scanf with %n giving wrong output

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.

How to limit input length with scanf

In this program I have taken a dimensional character array of size[3][4],
as long as I enter a 3 characters for each row it will work well.
For example: if I enter abc abd abd I get the same output but if i enter more letters in the first or second or 3rd row I get an error.
How should I check for null character in 2 dimensional?
# include <stdio.h>
#include <conio.h>
# include <ctype.h>
void main()
{
int i=0;
char name[3][4];
printf("\n enter the names \n");
for(i=0;i<3;i++)
{
scanf( "%s",name[i]);
}
printf( "you entered these names\n");
for(i=0;i<3;i++)
{
printf( "%s\n",name[i]);
}
getch();
}
As pointed out by #SouravGhosh, you can limit your scanf with "%3s", but the problem is still there if you don't flush stdin on each iteration.
You can do this:
printf("\n enter the names \n");
for(i = 0; i < 3; i++) {
int c;
scanf("%3s", name[i]);
while ((c = fgetc(stdin)) != '\n' && c != EOF); /* Flush stdin */
}
How should I chk for null character in 2 dimensional ... [something has eaten the rest part, I guess]
You don't need to, at least not in current context.
The problem is in your approach of allocating memory and putting input into it. Your code has
char name[3][4];
if you enter more that three chars, you'll be overwriting the boundary of allocated memory [considering the space of \0]. You've to limit your scanf() using
scanf("%3s",name[i]);
Note:
change void main() to int main(). add a return 0 at the end.
always check the return value of scanf() to ensure proper input.
EDIT:
As for the logical part, you need to eat up the remainings of the input words to start scanning from the beginning of the next word.
Check the below code [Under Linux, so removed conio.h and getch()]
# include <stdio.h>
# include <ctype.h>
int main()
{
int i=0; char name[3][4];
int c = 0;
printf("\n enter the names \n");
for(i=0;i < 3;i++)
{
scanf( "%3s",name[i]);
while(1) // loop to eat up the rest of unwanted input
{ // upto a ' ' or `\n` or `EOF`, whichever is earlier
c = getchar();
if (c == ' ' || c == '\n' || c == EOF) break;
}
}
printf( "you entered these names\n");
for(i=0;i<3;i++)
{
printf( "%s\n",name[i]);
}
return 0;
}
(Cringing after reading the answers to date.)
First, state the problem clearly. You want to read a line from stdin, and extract three short whitespace separated strings. The stored strings are NUL terminated and at most three characters (excluding the NUL).
#include <stdio.h>
void main(int, char**) {
char name[3][4];
printf("\n enter the names \n");
{
// Read tbe line of input text.
char line[80];
if (0 == fgets(line, sizeof(line), stdin)) {
printf("Nothing read!\n");
return 1;
}
int n_line = strlen(line);
if ('\n' != line[n_line - 1]) {
printf("Input too long!\n");
return 2;
}
// Parse out the three values.
int v = sscanf(line, "%3s %3s %3s", name[0], name[1], name[2]);
if (3 != v) {
printf("Too few values!\n");
return 3;
}
}
// We now have the three values, with errors checked.
printf("you entered these names\n%s\n%s\n%s\n",
name[0], name[1], name[2]
);
return 0;
}
you might consider something on the order of scanf( "%3s%*s",name[i]);
which should, if I recall correctly, take the first three characters (up to a whitespace) into name, and then ignore anything else up to the next white space. This will cover your long entries and it does not care what the white space is.
This is not a perfect answer as it will probably eat the middle entry of A B C if single or double character entries are mode. strtok, will separate a line into useful bits and you can then take substrings of the bits into your name[] fields.
Perhaps figuring out the entire requirement before writing code would be the first step in the process.

Scan single character C

/*
Program to calculate trip and plan flights
*/
#define TRIP 6
#define DEST 1
#include <stdio.h>
int error_dest(int type_num, int cont_num, int dest_code, int check);
int main(void)
{
int check, type_num, cont_num, index, i, dest_code, trip_num, row, col;
int travelint[TRIP][DEST], travelarea[TRIP];
char area_code, S, M, L, N, P, K, R, C, U, W, O;
trip_num = 7;
while (trip_num > TRIP)
{
printf("Please enter the number of trips:");
scanf("%d", &trip_num);
if ( trip_num < TRIP)
{
printf("Valid trip number. Please proceed to enter destination code.\n");
}
else
{
printf("Invalid trips. Please enter no more then 6 trips.\n");
}
}
/*********************************************************************************/
for (i=0; i < trip_num ; i++) /*destination code input*/
{
printf("Please enter destination code:");
scanf("%d", &dest_code); /*input of destination code*/
check = error_dest(type_num, cont_num, dest_code, check);
if (check == 2)
{ travelint[i][0]=dest_code; }
else
{
while (check == 1)
{
printf("Please enter destination code:");
scanf("%d", &dest_code); /*input of destination code*/
check = error_dest(type_num, cont_num, dest_code, check);
if (check == 2)
{ travelint[i][0]=dest_code; }
}
}
printf("Please select from the following that best describes your destination:\n");
printf("S Small city - population under 50,000\n");
printf("M Medium city - population between 50,000 and 500,000\n");
printf("L Large city - pop. over 500,000\n");
printf("N Natural formation like a mountain, a lake, a cave, a geyser, a fjord, a canyon, etc.\n");
printf("P Designated park or reserve such as a wildlife refuge, a national park, a bioreserve, or a protected marine area\n");
printf("K Man made landmark like the Great Wall of China, the Taj Mahal, or Stonehenge\n");
printf("R State or province or region of a country\n");
printf("C Whole country\n");
printf("U Multiple countries like traveling through Europe\n");
printf("W Ocean voyage\n");
printf("O Any other type of destination - such as visiting the sites of the seven wonders of the world\n");
printf("Please enter the Area Letter code:");
scanf("%c", &area_code);
}
/*******************************************************************************/
/*print for destination_code*/
for (row = 0; row < trip_num; row++)
{
for (col=0; col < DEST; col++)
printf("Trip[%d] = %d\n", row+1, travelint[row][col]);
}
return 0;
}
error_dest(type_num, cont_num, dest_code, check)
{
cont_num = dest_code / 10000; /*math for error check*/
type_num = dest_code/1000 - cont_num*10;
if ( (cont_num <= 7) && (cont_num > 0) && (type_num <= 5) && (type_num >=0) )
{ /* loop for checking destination code*/
check = 2 ;
return check;
}
else
{
printf("%d is a invalid code\n", dest_code);
check = 1;
return check;
}
}
for some strange reason at the scanf("%c", &area_code); it just runs ahead and print the dest_code array without letting me input any character and I'm not sure what exactly I am doing wrong.
If you're looking to grab only one character, perhaps it would be better to use getchar() instead of scanf()?
Basically what's happening is this: you print the "Please enter the number of trips" message to the screen. The user types in 4 and then hits the enter key, which means the stdin buffer looks like this: "4\n". You then call scanf with the "%d" format string. scanf looks at the stdin buffer, and sees the 4. It looks at the next character, which is the newline, and sees it's not part of a number (as %d specifies), so it is done fulfilling the format string and leaves the file pointer at the newline. It converts the char '4' to an integer 4 and places it in trip_num and returns.
The next time you call scanf, it picks up where it left off at the newline. The format string this time is "%c", so it just grabs the next character from the buffer which is currently the newline ("\n"), places it in dest_code, and returns. If you want the scanf function to skip over the whitespace in this case, you have to explicitly tell it by adding a space before the "%c" format for the second scanf (destination code). Then scanf will skip over all whitespace (including that newline) until it encounters a non-whitespace character that it places in dest_code.
TL;DR: Change the second scanf call to scanf(" %c", &dest_code). And fix the other errors others have pointed out so other bugs won't manifest.
You may print area_code after scanf, I guess it may be '\n' which is the last character of the dest_code line you entered.
You should empty the buffer before reading a character from stdin:
int c = 0;
while (c != '\n' && c != EOF)
{
c = getchar();
}
then you can read your character using scanf or replace it with getchar.
This may or may not help, but previously stated you probably need to put the getchar() into the while loop. You may also need the fgets to grab the stdin from the keyboard.
while(1){
printf("Enter Message Type:");
fflush(stdout) ;
// scan msg.hdr from received message.
scanf("%d", &(msg.m_hdr));
while(getchar() != '\n'){}
printf("Enter your Message:");
fflush(stdout);
// grab data from keyboard
fgets(msg.m_data, sizeof(msg.m_data), stdin);
Use "fflush(stdin)" before you enter the character, i.e. before the "printf" statement for the character. It will flush out the input buffer and thus you can scan the desired character. Or simply give a Space before the "%c" command. Like---------- scanf(" %c", &area_code); ---------------

Resources