a C programming question; howto prompt for restart script?
I am in a C class, but we get a week off (only had 1 class and already a day off, Fri morning class) so I got to thinking about the three scripts the Prof. had us write for homework.
The scope is simple. create script that takes input, then prints the desired output to screen and end. Id like to take it a bit further. Id like to figure out how to get the script to ask would you like to continue. if [Yy] then continue if anything else then exit. In BASH id just create a simple if/then statement to call a function, but from reading around on google and in The ANSI C Programming Language book the examples they have for functions are the mathematics I am running in my main(void). As i am still really a newB, i consider myself a newB at least, to BASH scripting I am not wrapping my head around the function(s) in C. here is one of the programs id like to add the prompt to continue to: Code:
/* 5. Write a program to convert a temperature in degrees Fahrenheit to degrees Celsius. */ What I'm asking is for examples of how I would turn the main(void) section into either a function, or how would I get the script to start back at the top to run again until the user input is != [Yy]??? Thanks. |
*grumble*
ive been mucking around with do/while loops and just can not get it to work: Code:
#include<stdio.h> |
I think the first scanf leaves the newline in the input buffer. So the second scanf gets the newline the user typed for the first.
Anyway, the do and the while(1) are worthless because both sides of the if are return. |
[QUOTE=lleb;4954023]
Code:
scanf("%c", &ANS); Code:
scanf(" %c", &ANS); By the way, I am not sure if your Y/N conditional is correctly written. I see that Y is declared as a character, but I don't see where it is assigned a value. I would write the conditional as: Code:
if (ANS == 'Y') |
The problem is that "scanf( )" does not read the new line "\n" at the end of a line. In fact, "scanf" is not guaranteed to read an entire line. It only reads what is necessary. For example, if you typed this in at the first prompt.
100y Then BOTH of your "scanf( )" functions would succeed and return immediately. The first one reads "100" and stops because it sees a non-numeric character. the second one reads the "y" since there is another character that can be read. Typing in a number followed by a new-line character reads only the number, and not the new-line after the number. So, "scanf("%d", &FAH)" leaves the new-line character waiting to be read. The next "scanf("%c", &ANS)" reads ANY character. It reads the new-line character of the first input line that you typed. There are a few different ways around this problem. One way around the problem is to skip white-space in the "scanf" before reading the character. Code:
scanf(" %c", &ANS); Another way to solve the problem is to read a string instead of a character. Reading a string skips leading white-space. A string also ends at the first white-space. With "scanf" a string is really more like a token. Code:
char ANS[2]; Code:
char BUFFER[81]; Code:
do Reading numbers can work much the same way. Code:
do |
Erik FL, you are way over my head, but i think i understand some of what you are saying. I attempted to incorporate the code you have for the Y/N response, but I am getting the following error when compiling:
Code:
ssma-imac:ENG-3211 ssma$ gcc -o hw_1_5.v2 hw_1_5.v2.c Code:
#include<stdio.h> |
Quote:
Code:
char ANS[2], BUFFER[81]; The input buffer "BUFFER" is 81 characters, so the first 80 characters can be text, leaving the last character for the zero terminator. Of course if the user enters less text, the zero terminator will be somewhere else. For example typing in "test" will result in BUFFER[0] through BUFFER[3] being "test" and BUFFER[4] will be 0. The error on line 54 is because you need to include a header file to define the "strchr" function. Code:
#include <string.h> The other thing you may be wondering about is the "sizeof( )" function. It is actually a compiler built-in function. It returns the size of a variable in bytes. For a character array, the size in bytes is always equal to the size in characters. The zero terminator takes up a byte, so an array of 81 characters can hold a character string that has 80 characters. If you use "sizeof( )" for other kinds of data, keep in mind that they may be more than one byte each. For example, sizeof(int) is usually 4 and sizeof(short) is usually 2. Code:
int numbers[3]; In cases where the type of the data in the array might be changed later, you can divide by the total size of one array element. Code:
printf( "The array is %d bytes and can hold %d numbers\n", sizeof(numbers), sizeof(numbers)/sizeof(numbers[0]) ); One of the hardest concepts to understand in C is the difference between a character, a character array, and a string. A character is a single byte (8-bits). A character array is a sequence of characters, with a fixed size. A string is a variable-length sequence of characters ending with a 0. The zero at the end of a string is a normal character, and takes up a byte. You can store a string in a character array if the array is large enough for the characters and the terminating 0 byte. There may be other characters after the 0 byte if the array is larger than the string. Adding to the confusion, C does not have a separate "string" data type. A "char *" could be a pointer to a single character, a pointer to all or part of a character array, or a pointer to a string. That is determined by how the program and functions use the pointer. A string constant is really just a convenient way of declaring a constant array of characters, and then using the pointer to that array. Code:
const char msg[] = { 'T', 'e', 's', 't', '\n', 0 }; Code:
msg2 = "New text string"; Also, "msg2" is not a constant, the characters that "msg2" points to are constant. Otherwise, how could the program change the pointer? The following would make msg2 a constant pointer to constant characters. Code:
const char *const msg2 = "Test\n"; Code:
msg2 = "New text string"; Code:
const char *(const msg2) = "Test\n"; |
ok. much information.
i added the new include, but i am still getting an error with the fget line. reading around there seem to be 2 standards. the one you provided above and one that has a -1 for the 2nd part... Code:
fgets( BUFFER, sizeof(BUFFER), stdin ); Code:
fgets( BUFFER, sizeof(BUFFER)-1, stdin ); Code:
$ gcc -o hw_1_5.v2 hw_1_5.v2.c |
Quote:
Code:
char BUFFER[81]; Using the "-1" isn't necessary since "fgets" already subtracts one from the length. |
Read the definition of fgets() http://linux.die.net/man/3/fgets.
1st arg must be ptr-to-char, not char. |
thanks found the compiling error issue. i was redefining both ANS and BUFFER as char instead of strings. i deleted that line and it was then able to compile. Now i need to figure out how to get the script to wait for user input before it starts over. now it just prints the question, does not wait, then restarts the script. so it is at least restarting, just want it to wait for the Y/N response to it will exit properly too.
|
You need to make sure that the first new-line character (following the number) is read in before the program reads the Y/N answer. One way to do that is to use "fgets" to read the entire input line.
Code:
fgets( BUFFER, sizeof(BUFFER), stdin ); Code:
scanf( "%d", &FAH ); |
Quote:
Quote:
|
In C, a single 'char' fits exactly into the space for an int, therefore you can (under certain circumstances) treat them either way, depending on context.
See the ASCII table http://www.asciitable.com/. Its been while since I've written any C, but as an example you can check for eg a lowercase single alpha char using arithmetic methods; something like (off the top of my head) Code:
if ( x >= 'a' && x <= 'z' ) I used to like this book a lot when i was learning C http://www.amazon.com/Book-Programmi.../dp/0201183994 (A Book on C; Auth by Kelley & Pohl). Extremely clear teaching, inc line by line analysis of examples. I highly recommend you lookup each new C (library) fn you come across and become familiar with its args, & rtn value (if any). Details, Details.... a very powerful lang, but takes some focus to pick up. :) |
thanks.
|
Quote:
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 ); \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 ); 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. |
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 ); |
Quote:
Code:
fgets( BUFFER, sizeof(BUFFER), stdin ); |
progress:
Code:
#include<stdio.h> Code:
ssma-imac:ENG-3211 ssma$ gcc -o hw_1_5.v2 hw_1_5.v2.c |
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. |
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) |
Quote:
(I see Erik_FL beat me to this answer. Well done.) |
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. |
I can answer some questions, not all:
Quote:
Code:
sscanf( BUFFER, "%1s%*1s", ANS ) != 1 Code:
|| Code:
strchr( "YyNn", *ANS ) == NULL 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. |
Quote:
Code:
if ( i == 5 ) Code:
i = 5; Code:
while ( i-- > 0 ) Quote:
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 ) 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 Code:
ANS Quote:
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:
The pairing of the braces is important. The entire statement is really like this. Code:
do { /* statements... */ } while ( *ANS == 'Y' || *ANS == 'y' ); Code:
do { do { /* statements... */ } while ( /* not valid */ ); } while ( *ANS == 'Y' || *ANS == 'y' ); Code:
*ANS = 'y'; |
All times are GMT -5. The time now is 07:18 AM. |