LinuxQuestions.org
Review your favorite Linux distribution.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 05-19-2013, 10:38 PM   #16
Erik_FL
Member
 
Registered: Sep 2005
Location: Boynton Beach, FL
Distribution: Slackware
Posts: 821

Rep: Reputation: 258Reputation: 258Reputation: 258

Quote:
Originally Posted by lleb View Post
question about this. isnt %d the place holder for integer? isnt %c that place holder? if the answer is going to be a char, why would we be looking for an integer? is that due to ANS[2] or BUFFER[81]?
The reason that the "fgets( )" does not wait for the Y/N answer is a little bit involved to explain.

After typing in the number 1000, the information in "stdin" would look like this, for example.

1000\n

I used "\n" to represent the new-line character. Your program is reading the number like this.

Code:
scanf( "%d", &FAH );
That will leave information in "stdin" like this.

\n

Later, your program wants to read a Y or N answer. When your program calls "fgets" to read a line, or "scanf" to read a character, it will read the new-line character (without waiting). What I was getting at is that the whole not waiting problem is caused by how the program reads the number, since it does not read the entire input line. So it is not enough to just use "fgets" in one place (reading Y/N) and not the other (reading the number). If you want the program to wait for input, then you need to make sure that all previous lines that were entered have been completely read in, including the new-line at the end of each line.

The "scanf" function is not very good for reading input because it does not know nor care about new-line characters or input lines. The new-line characters are the same as spaces as far as "scanf" is concerned.

These are all the same as far as "scanf" is concerned.

1\n
N\n
10\n
Y\n

1 N\n
10 Y\n

1 N 10 Y\n

1\n
N\n
10 Y\n

That wouldn't really matter much, except that the program is also displaying messages to prompt for the input. If the data that "scanf" wants to read has already been typed in before the prompt, then the program won't wait for any input after displaying the prompt message.

You could do something like this.

Code:
scanf( "%d ", &FAH );
That will skip white-space following the number, including a new-line. That still won't work if the input line looks like this.

1000N\n

When "scanf" tries to read white-space after the number, it will fail, since "N" is not white-space. That leaves the following in the input buffer.

N\n

And the next call to "scanf" or "fgets" will read the remainder of the line, just as if it had been typed in as a separate line.

The solution is to always use "fgets" to read entire input lines and then use "sscanf" to determine if the information that was entered is valid. That way you know that the program is not reading left-over information from some other input line.
 
Old 05-19-2013, 11:12 PM   #17
lleb
Senior Member
 
Registered: Dec 2005
Location: Florida
Distribution: CentOS/Fedora/Pop!_OS
Posts: 2,983

Original Poster
Rep: Reputation: 551Reputation: 551Reputation: 551Reputation: 551Reputation: 551Reputation: 551
so it would require an entire rework of the script to get what i want. ok.

just to make sure im following what you are saying. for my request for the FAH value at the start of the script i would have to do something like:

Code:
fgets( FAH, sizeof(FAH), stdin );
sscanf( FAH, "%d", <no_clue what goes here> );
is that at least on the right track?
 
Old 05-20-2013, 12:28 PM   #18
Erik_FL
Member
 
Registered: Sep 2005
Location: Boynton Beach, FL
Distribution: Slackware
Posts: 821

Rep: Reputation: 258Reputation: 258Reputation: 258
Quote:
Originally Posted by lleb View Post
so it would require an entire rework of the script to get what i want. ok.

just to make sure im following what you are saying. for my request for the FAH value at the start of the script i would have to do something like:

Code:
fgets( FAH, sizeof(FAH), stdin );
sscanf( FAH, "%d", <no_clue what goes here> );
is that at least on the right track?
That's close. This is what I was suggesting.

Code:
fgets( BUFFER, sizeof(BUFFER), stdin );
sscanf( BUFFER, "%d", &FAH );
It reads an entire input line into "BUFFER" and then converts the characters to an integer value. The key point being that "fgets" will read the entire input line including the new-line.
 
Old 05-20-2013, 01:55 PM   #19
lleb
Senior Member
 
Registered: Dec 2005
Location: Florida
Distribution: CentOS/Fedora/Pop!_OS
Posts: 2,983

Original Poster
Rep: Reputation: 551Reputation: 551Reputation: 551Reputation: 551Reputation: 551Reputation: 551
progress:

Code:
#include<stdio.h>
#include<string.h>
#define TRUE  1
#define FALSE  0

//Problem Input
//int fahrenheit /* temperature in degrees Fahrenheit */
//Problem Output
//double celsius /* temperature in degrees Celsius */
//Relevant Formula celsius = 5/9 ( fahrenheit \u2212 32)

int main(void)

{
char ANS[2], Y, BUFFER[81];
do	{
	
	int FAH;
	double CEL;
	
	/* Get the degree in Fahrenheit */
	printf("\nPlease enter the temperature in Fahrenheit: ");
	//scanf("%d", &FAH);
	fgets( BUFFER, sizeof(BUFFER), stdin );
	sscanf( BUFFER, "%d", &FAH );

	/* Convert F to C */
	CEL = 5 * (FAH-32) / 9;

	/* Display results */
	printf("\n%d degrees Fahrenheit converts to %.2f degrees Celsius.\n", FAH, CEL);
	//sleep(10);
	
	/* Prompt for new input */
	printf("\nWould you like to enter a new temperature [Y]es or [N]o?  ");
	fgets( BUFFER, sizeof(BUFFER), stdin );
	
	}
	while ( sscanf( BUFFER, "%1s%*1s", ANS ) != 1 || strchr( "YyNn", *ANS ) == NULL  );
	return(0);

}
it not waits for a response, but always exits.

Code:
ssma-imac:ENG-3211 ssma$ gcc -o hw_1_5.v2 hw_1_5.v2.c 
ssma-imac:ENG-3211 ssma$ 
ssma-imac:ENG-3211 ssma$ 
ssma-imac:ENG-3211 ssma$ ./hw_1_5.v2 

Please enter the temperature in Fahrenheit: 75

75 degrees Fahrenheit converts to 23.00 degrees Celsius.

Would you like to enter a new temperature [Y]es or [N]o?  y
ssma-imac:ENG-3211 ssma$ 
ssma-imac:ENG-3211 ssma$ 
ssma-imac:ENG-3211 ssma$ ./hw_1_5.v2 

Please enter the temperature in Fahrenheit: 75

75 degrees Fahrenheit converts to 23.00 degrees Celsius.

Would you like to enter a new temperature [Y]es or [N]o?  Y
ssma-imac:ENG-3211 ssma$ 
ssma-imac:ENG-3211 ssma$ 
ssma-imac:ENG-3211 ssma$ ./hw_1_5.v2 

Please enter the temperature in Fahrenheit: 75

75 degrees Fahrenheit converts to 23.00 degrees Celsius.

Would you like to enter a new temperature [Y]es or [N]o?  N
do i need/want the #define TRUE/FALSE at the top of the script?
 
Old 05-20-2013, 02:01 PM   #20
lleb
Senior Member
 
Registered: Dec 2005
Location: Florida
Distribution: CentOS/Fedora/Pop!_OS
Posts: 2,983

Original Poster
Rep: Reputation: 551Reputation: 551Reputation: 551Reputation: 551Reputation: 551Reputation: 551
im reading up on the following links. they do explain a bit more about fgets and what not. still not sure what is wrong with the while statement preventing the script from restarting.

http://faq.cprogramming.com/cgi-bin/...&id=1043284385

http://faq.cprogramming.com/cgi-bin/...&id=1043284392

http://faq.cprogramming.com/cgi-bin/...&id=1043284392

i now see why you like fgets so much v scanf.
 
Old 05-20-2013, 05:56 PM   #21
Erik_FL
Member
 
Registered: Sep 2005
Location: Boynton Beach, FL
Distribution: Slackware
Posts: 821

Rep: Reputation: 258Reputation: 258Reputation: 258
Take a look at the last 10 lines. The "while" statement that you had at the end was checking for invalid input. To check for a yes answer you would need something similar to the "while" statement at the end.

Code:
int main(void)

{
char ANS[2], Y, BUFFER[81];
do	{
	
	int FAH;
	double CEL;
	
	/* Get the degree in Fahrenheit */
	printf("\nPlease enter the temperature in Fahrenheit: ");
	//scanf("%d", &FAH);
	fgets( BUFFER, sizeof(BUFFER), stdin );
	sscanf( BUFFER, "%d", &FAH );

	/* Convert F to C */
	CEL = 5 * (FAH-32) / 9;

	/* Display results */
	printf("\n%d degrees Fahrenheit converts to %.2f degrees Celsius.\n", FAH, CEL);
	//sleep(10);
	
        do  /* Do while not valid input */
        {
	    /* Prompt for new input */
	    printf("\nWould you like to enter a new temperature [Y]es or [N]o?  ");
	    fgets( BUFFER, sizeof(BUFFER), stdin );
	}
	while ( sscanf( BUFFER, "%1s%*1s", ANS ) != 1 || strchr( "YyNn", *ANS ) == NULL  );
}
while ( *ANS == 'Y' || *ANS == 'y' );
return(0);
}
 
1 members found this post helpful.
Old 05-20-2013, 06:10 PM   #22
Beryllos
Member
 
Registered: Apr 2013
Location: Massachusetts
Distribution: Debian
Posts: 529

Rep: Reputation: 319Reputation: 319Reputation: 319Reputation: 319
Quote:
Originally Posted by Erik_FL View Post
[...]One can check to see if exactly the correct number of items was typed on each line.
Code:
do
{
    printf("\nWould you like to enter a new temperature [Y]es or [N]o?  ");
    fgets( BUFFER, sizeof(BUFFER), stdin );
}
while ( sscanf( BUFFER, "%1s%*1s", ANS ) != 1 || strchr( "YyNn", *ANS ) == NULL  );
Using "fgets" instead of "gets" limits the number of characters to the size of the character buffer. The "sscanf" function tries to read two character strings (tokens) of a single character. If just a "Y" or "N" is entered, then only one character string is returned and "sscanf" returns 1. If extra "garbage" is typed, then "sscanf" reads two strings and returns 2[...]
lleb, The reason your while-loop is not working as you expected is that you used this code from Erik_FL which is designed to loop back for invalid input (number of characters !=1 or character not in "YyNn"). You could make Erik_FL's while-loop the inside loop of 2 nested while-loops. Your loop would be the outer loop, with appropriate tests for the character value of ANS. Hint: you could use the return value of strchr( "YyNn",*ANS ).

(I see Erik_FL beat me to this answer. Well done.)

Last edited by Beryllos; 05-20-2013 at 06:14 PM. Reason: response to Erik_FL's post
 
1 members found this post helpful.
Old 05-20-2013, 10:01 PM   #23
lleb
Senior Member
 
Registered: Dec 2005
Location: Florida
Distribution: CentOS/Fedora/Pop!_OS
Posts: 2,983

Original Poster
Rep: Reputation: 551Reputation: 551Reputation: 551Reputation: 551Reputation: 551Reputation: 551
thanks guys. question about the {}'s. i notice they are not nested. it is like math were you only need to have the same number of { as you need } or is it not like in BASH were you need a { to open a section (function) and a } to close that same section.

just so that i can understand what the code is saying, let me see what i get.

sscanf ( BUFFER, "%ls%*ls", ANS )

that reads the BUFFER from above and puts in long string(?) to the variable ANS is that right?

!=1, not 100% on this, but reading beryllos this is anything other then YyNn? so kind of like the bash expression d != were the directory does not exist?

strchr( "YyNn", *ANS ) this takes the standard characters of YyNn and puts them into the string ANS?

not sure what the == NULL does, but im guessing its like 1>&2 in bash?

In the 2nd while statement (still not sure how the {} work to get that there with the do statement at the top of the script) this allows for any version of Yy to fill the string ANS. Kind of like BASH [Yy]?

please tell me what i have right and wrong. Thanks.
 
Old 05-20-2013, 11:47 PM   #24
Beryllos
Member
 
Registered: Apr 2013
Location: Massachusetts
Distribution: Debian
Posts: 529

Rep: Reputation: 319Reputation: 319Reputation: 319Reputation: 319
I can answer some questions, not all:
Quote:
Originally Posted by lleb View Post
thanks guys. question about the {}'s. i notice they are not nested. it is like math were you only need to have the same number of { as you need } or is it not like in BASH were you need a { to open a section (function) and a } to close that same section.
The braces {} are nested and matched, they have to be, but opening and closing braces can be many lines apart. They mark the beginning and end of a function (for example, main{}) or a block of instructions (for example, the contents of a do{}while loop).

Code:
sscanf( BUFFER, "%1s%*1s", ANS ) != 1
Look for an explanation of this in an earlier post by Erik_FL. I don't know the syntax that well, but I think Erik said the sscanf function, written just so, counts how many characters were input by the user. If it is not equal to 1 (that's what !=1 means), the while-loop goes another cycle, repeating the user prompt and looking for user input.

Code:
||
That is a logical-OR operator.

Code:
strchr( "YyNn", *ANS ) == NULL
That strchr function returns a "valid pointer" (not sure if that is the correct terminology) if the character ANS occurs within the string "YyNn". For example, if ANS equals Y, I think it returns a pointer to the character Y in that string "YyNn". If ANS is a character not Y, y, N, or n (or the \0 which terminates the string), the function returns a NULL pointer. The == is a test for equality. In other words, if strchr("YyNn",*ANS) returns a valid pointer, the expression in the above code block becomes FALSE; if it returns a NULL pointer, the expression becomes TRUE.

Here are a few resources that may be helpful (not necessarily the best; just the first ones I found today that look good):

strchr function
http://www.codecogs.com/reference/co...g.h/strchr.php

relational operators (table including many programming languages)
http://en.wikipedia.org/wiki/Relatio...onal_operators

braces
Sorry, I can't find a clear introduction to the usage of braces in C. Perhaps an introductory textbook would help.
 
Old 05-21-2013, 12:20 AM   #25
Erik_FL
Member
 
Registered: Sep 2005
Location: Boynton Beach, FL
Distribution: Slackware
Posts: 821

Rep: Reputation: 258Reputation: 258Reputation: 258
Quote:
Originally Posted by lleb View Post
thanks guys. question about the {}'s. i notice they are not nested. it is like math were you only need to have the same number of { as you need } or is it not like in BASH were you need a { to open a section (function) and a } to close that same section.
You need the same number of opening and closing braces. In C/C++ the indentation does not matter. You will see different styles for indentation. Here are some valid examples.

Code:
if ( i == 5 )
{
    printf( "The number is 5\n" );
}
else
{
    printf( "The number is %d\n", i );
}

if ( i == 5 )
    {
    printf( "The number is 5\n" );
    }
else
    {
    printf( "The number is %d\n", i );
    }

if ( i == 5 ) {
    printf( "The number is 5\n" );
}
else {
    printf( "The number is %d\n", i );
}
Braces in C are used to group statements into a "block" that is equivalent to a single statement. For example, "while" is a statement.

Code:
i = 5;
while ( i-- > 0 ) printf( "The count is %d\n", i );
To include multiple statements in the "while" statement one uses a block of statements.

Code:
while ( i-- > 0 )
{
    printf( "The count is %d\n", i );
    printf( "This is another statement in the while loop\n" );
}
Braces are also used to group the statements that make up the body of a function.

Quote:
Originally Posted by lleb View Post
...just so that i can understand what the code is saying, let me see what i get.

sscanf ( BUFFER, "%1s%*1s", ANS )

that reads the BUFFER from above and puts in long string(?) to the variable ANS is that right?
The font is unfortunately not very good. Those are ones not Ls. It is scanning the contents of "BUFFER", a character string. The format specifier says to look for a one-character string (the Y or N) and store it in "ANS", then look for another one-character string and don't store it. If the information is correct, then "sscanf" should be able to find the first string, but NOT the second string. So, "scanf" should return a one to say that one item was found. If both items are found then there was more than a single non-blank character typed on the line. The "scanf" function will return 2. That also means "Yes" or "Yx" is not considered a valid answer, while "Y" is valid.

If you get rid of the "%*1s" then it just looks for the first non-blank character and does not care if there are more characters after that.

Code:
sscanf ( BUFFER, "%1s", ANS )
When you use "sscanf" or "scanf" the specifier "%1s" does not mean the same thing as "%c". Reading a single-character "string" with "%1s" skips blank characters and also stores a zero byte after the character (it stores two bytes). Reading a "character" with "%c" does not skip blanks and it stores just the 8-bit character (one byte). The only difference between an array of characters and a string is that a string has a zero byte to mark the end.

On a different subject, something that might not be obvious is these two expressions mean the same thing in C when "ANS" is a character array (string). Both expressions produce an 8-bit character value.

Code:
*ANS
ANS[0]
Also, these two expressions mean the same thing. Both expressions produce a character pointer (memory address of the array/string).

Code:
ANS
&ANS[0]
Quote:
Originally Posted by lleb View Post
not 100% on this, but reading beryllos this is anything other then YyNn? so kind of like the bash expression d != were the directory does not exist?

strchr( "YyNn", *ANS ) this takes the standard characters of YyNn and puts them into the string ANS?
not sure what the == NULL does, but im guessing its like 1>&2 in bash?
The "strchr" function searches the string "YyNn" for the character in ANS[0]. If ANS[0] is one of those characters then "strchr" returns a pointer to the character that was found. If ANS[0] is NOT one of the characters then "strchr" returns a NULL pointer. So "== NULL" means that the character was NOT found.

C does not have I/O redirection statements like a scripting language. The default output always goes to a file called "stdout", for example, and "stdout" is usually set by the operating system or shell that runs the C program.

Quote:
Originally Posted by lleb View Post
In the 2nd while statement (still not sure how the {} work to get that there with the do statement at the top of the script) this allows for any version of Yy to fill the string ANS. Kind of like BASH [Yy]?
It is checking to see if ANS[0] is the character 'Y' or 'y'. The "sscanf" statement found a one-character string (token), so ANS[0] has the first non-blank character that was typed on the input line.

The pairing of the braces is important. The entire statement is really like this.

Code:
do { /* statements... */ } while ( *ANS == 'Y' || *ANS == 'y' );
And with both loops it does something like this.

Code:
do { do { /* statements... */ } while ( /* not valid */ ); } while ( *ANS == 'Y' || *ANS == 'y' );
If you find it less confusing you could do something like this instead.

Code:
*ANS = 'y';
while ( *ANS == 'y' || *ANS == 'Y' )
{

     do {
          /* Statements */
     } while ( /* not valid */ ); 

}

Last edited by Erik_FL; 05-21-2013 at 12:25 AM.
 
2 members found this post helpful.
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] howto restart hal daemon Fred Caro SUSE / openSUSE 3 03-27-2011 12:04 PM
bash programming question - hand over variables to another script ppr:kut Linux - General 5 02-09-2008 10:00 AM
question about shell-script programming GSX Programming 11 11-22-2005 04:58 PM
Restart apache service without password prompt? Phaethar Linux - Software 2 07-06-2004 01:28 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 11:45 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration