CSC 180 Notes for Tutorial #5 Wednesday 16 October Monday 21 October ============ Notes for your tutorial ========================================= SOME SMALL PROGRAMMING EXAMPLES ================================ A. reading input until end-of-file ================================== In the examples that we have seen so far, input data lists have always been terminated by a "sentinel" value. For example in assignment one, when finding the maximum number in a list of numbers, the list was terminated by "0". This technique usually works fine - but it has one serious design flaw. (See if they can suggest flaws. ... ) What if you want the "sentinel" value to be treated as an input value - not a marker of the end of input? This cannot be done with the current approach. What can we do instead? We need another way marking the end of the input. If the input data had been entered into a file, and then read into the program, the end of the input would be marked by reaching the end of the file. (We will discuss how to run a program with the input coming from a file instead of directly from the keyboard in a minute ...) How can we recognize when the reading of the input file has reached the end of the file? So far, we have always used the scanf() function to read in data to our program. We have used the scanf() function in statements like: int i; scanf("%d", &i); to read in a single number. But, remember that scanf() is a function. It turns out that the return type of scanf() is int. What is the meaning of the returned value? It represents the number of items that were read in that were in prescribed format. Hence in this case we can use the scanf() return result to indicate whether or not an integer was read. If the result is not 1, we know that a new number was not read in, and we are finished reading in values. Here is a simple program that reads a list integer numbers and prints the list. It terminates when a noninteger is input. int main() { int i, n; n = scanf( "%d", &i ); while ( n == 1 ) { printf( "I read in the number : %d\n" , i ); n = scanf( "%d", &i ); } printf( " n = %d\n" , n ); printf("Stopped reading numbers.\n"); return 0; } Suppose that the above program was entered into the file: readInts.c and compiled with the linux command % cc readInts.c -o readInts.x Suppose further that a file named data was created with the following contents: 1 2 3 4 5 6 If we execute the linux command : % readInts.x < data Then the displayed output would be: I read in the number : 1 I read in the number : 2 I read in the number : 3 I read in the number : 4 I read in the number : 5 I read in the number : 6 n = -1 Stopped reading numbers. Note: Using the "<" symbol when executing the program means that the input will come from the given file, not the keyboard. Note: Each scanf() call read in the next number. It didn't advance to the next input line each time. Note: scanf() returns "-1" when the end of the file is reached. Question: How can you save the output in a file instead of having it be displayed in the terminal window? Use the linux command: % readInts.x < data > outputFile where outputFile is the name of the file that is to contain the output results. (The use of > and < is called i/o redirection.) Question: What if I wanted to enter data from my keyboard interactively with the program instead of entering the data into a file before execution? How can I indicate that the end of the file has been reached? Ans:Entering control-D (^D) indicates that the end of the input file has been reached. So, at my keyboard, I could type in 1 2 3 4 5 6  and get the same results as last time. Question: What if my input looked like: 1 2 3.1415 4  Ans:The output would be: Read the number : 1 Read the number : 2 Read the number : 3 n = 0 Stopped reading numbers. Integers don't have decimal points, and so scanf() returns with value 0 after reading the decimal point - because it doesn't know how to interpret the decimal point - it has been instructed (via the "%d" format) to read a decimal integer. It has successfully read in 0 integers, so 0 is returned. The value of i is unchanged. Question: What if my input looked like: 1 2 buckle my shoe 3 4 lock the door  Ans:The output would be: Read the number : 1 Read the number : 2 n = 0 Stopped reading numbers. Same situation as last time. "b" is not a decimal number, so scanf() does not know how to follow the format instructions. The value 0 is returned because 0 integers were read. Question: Can the original program be written more efficiently? Yes, this program would usually be written as: int main() { int i; while ( scanf( "%d", &i ) == 1 ) { printf( "I read in the number : %d\n" , i ); } printf("Stopped reading numbers.\n"); return 0; } Exercise for students: Enter the program - original or updated - and run it on different data files / interactive input that you make up to explore how different files are interpreted. ========= B. developing a program that uses "subprograms" -- functions in C ================================================================= General comments: - Now that they have seen a bit about functions, always use a function where appropriate. I haven't said much about local variables in functions, but you can introduce them if they crop up. What to cover: - Develop a main program that requires one or more functions, design the function header for at least one of them, and if you have time, write the function body for at least one of them. - try to explain why you have chosen to use a function and not just written the program with everything in the main function. (top-down design, don't let the details get in the way of the structure of the problem solving, etc.) - Try to trace what happens when you call a function (including the return!). I have done this in lecture, but it needs repeating. - Suggested example: - a program to read in a list of integer numbers and prints out the number of numbers that have doubled digits in them. So, for example 1233456 contains doubled digits - the 33 - but 919 does not - because the 9's are not side-by-side. - This is a silly example, but it's hard to think of something that has all the properties listed above and isn't too hard. The code is at the end of this message (it has not been run and tested). - Please develop the code with your class, emphasizing top-down design and good use of parameters. Here is my solution: #include #define FALSE 0 #define TRUE 1 int hasDoubles( int number ) { int result = FALSE; /* explain the initialization */ int digit, nextDigit; number = abs( number) ; digit = number%10; number = number / 10; while ( digit > 0) { nextDigit = number%10; number = number / 10; if ( digit == nextDigit ) { result = TRUE; break; } digit = nextDigit; } return result; } int main () { int numDoubles = 0; int inputNumber; /* note that writing the "hasDoubles" function in place here would make it more difficult to follow what is going on from a "structural" point of view. */ while ( scanf( "%d", &inputNumber ) == 1 ) { if ( hasDoubles( inputNumber ) ) { numDoubles = numDoubles + 1; } } printf( "The number of entries containing doubled digits is: %d\n", numDoubles ); return 0; }