|
~ Introduction to Programming: C ~ Session 6 - Conversions & Useful Stuff |
In this session we will be taking a look at how we go about performing conversions between different types of variables in C (which we have taken a brief look at already by looking at the sprintf and sscanf functions). We will also take a look at the concept of type-casting, which also relates to conversions. We'll be taking a look at some of the more useful mathematical functions, including a second look at random numbers.
We shall be taking a final look at the use of the printf and scanf functions, and their string counterparts.
Finally, you will be given a "mock" examination to look at and attempt between now and the next session, to give you a flavour of what we are aiming to achieve for the examination, and also in order to gauge your own progress.
You can force C to convert between different types.
For example, in order to allow a floating-point (i.e. number, possibly with a
fractional amount) to be stored into an integer variable, we need to lose the
fractional amount. This would not normally be allowed, as you are losing
information by doing this. However, you can force (or coerce) the C
Compiler to do this by placing the type that you wish to convert to in
brackets before the number of formulae that you wish to convert from.
E.g.
float
f=3.57; int i=(int)f;
will store the value 3 in the variable i having converted it from the floating-point type given by variable f.
Another unexpected problem you can find is when you divide two integer variable together, and wish to store the result in a floating point number (it could have a fractional part, after all), then the C compiler will divide the two integer numbers by each other, and to produce an integer result, will remove the decimal part. The integer value will then get stored in the floating point variable.
Try the following program, and you
will see the problem:-
#include
<stdio.h>
#include
<conio.h>
void
main() {
int i1=7, i2=3; float f=i1/i2;
printf("%d/%d=%6.2f\n",i1,i2,f); getch();
}
This produces the following result (press a key to
finish):-
7/3=
2.00
To get the correct result, we need to convert at least one of the values being divided to a floating point number. Just to be safe, we'll convert both values, by prefixing them with the (float) casting operator: -
The program becomes: -
#include
<stdio.h>
#include
<conio.h>
void
main() {
int i1=7, i2=3; float f=(float)i1/(float)i2;
printf("%d/%d=%6.2f\n",i1,i2,f); getch();
}
which gives us the following result: -
7/3=
2.33
i.e. two and a third, which is what we would expect.
Converting data to and from string (text) data can be done in a number of ways. As strings are not built into the C language as a feature, we will need to make use of some standard libraries by using the #include directive and use the functions held in these libraries.
Here's a list of methods for
converting to and from strings:-
|
from type |
to type |
function |
library |
|
string |
float |
float f=atof("1.23"); |
math.h |
|
string |
integer |
int i = atoi("123"); |
math.h |
|
string |
float |
sscanf("1.23","%f",&f); |
stdio.h |
|
string |
integer |
sscanf("123","%d",&i); |
stdio.h |
|
float |
string |
sprintf(str,"%f",&f); |
stdio.h |
|
integer |
string |
sprintf(str,"%d,&i); |
stdio.h |
In general, you will find that the sprintf and sscanf functions are most useful, and can be tailored to accept input/output in a variety of forms. See the example in session 2 on using scanf to read a date format string into three variables.
printf is used for writing variables and text in combination to the console (screen). sprintf writes the output to a string variable instead of the screen.
Similarly, scanf is the opposite function, which takes input from the keyboard, expected to be a particular combination of text and values, and extracts those values into variables.
#include
<stdio.h>
#include
<conio.h>
void
main() {
char forename[30],surname[30]; int years;
printf("What is your name (forename then surname)? ");
scanf("%s %s",forename,surname);
printf("Name is: %s, %s\n\n",surname,forename);
printf("What is your age (n years)? ");
scanf("%d years",&years);
printf("Welcome %s, the %d year old member of the %s family.",
forename,years,surname);
getch();
}
Notice that the forename and surname are read in as two separate strings, separated by a space. It is then shown on the screen in reverse order, separated by a comma.
If you try typing out the number of years without typing out the word years afterwards, then the program will not continue until you have typed years. That is because the second scanf statement waits for an integer number followed by a space followed by the word years to be typed before it is satisfied. The integer number (%d) part is then placed in the &years variable.
Finally, all of this data is put together and displayed on the console in a single printf statement.
The following statement will take
a date previously entered into a string, and convert it to three integer values
for day, month and year: -
char
str[11]; int day,month,year;
strcpy(str,"05-06-2002");
sscanf(str,"%d-%d-%d",&day,&month,&year);
Remember that any parameters passed by reference to the sscanf procedure need to have an & put before them, except str which is a string variable, and implicitly passes the address of the character array.
char
str[11]; int day,month,year;
day=5;
month=6; year=2002;
sprintf(str,"%02d-%02d-%4d",day,month,year);
Format specifiers are the parts of the string template that start with a percentage (%) symbol and end with a character that specifies the type of string that is to be inserted at that point in the string. The most common characters to use are: s for string (or array of char), c for character, d for integer and f for float.
You can put a number between the % and the letter to specify the length of the field. In the example given above, the day is padded to 2 characters, the month to 2 characters, and the year to 4 characters. By default, the padding character is a space. However, if you prefix the width number with a zero (0), then the padding will be with zero characters.
Finally, if you specify a decimal with floating points (e.g. %5.2f) then the format will be 5 characters wide, with 2 decimal places, giving 2 digits before the decimal point (e.g. 12.34 is five characters wide, with two decimal places, which leaves two digits before the decimal point).
Write a program that reads in a time in the format hh:mm:ss where hh is the number of hours, mm is the number of minutes, and ss the number of seconds.
Work out the number of seconds elapsed since midnight – the formula is (minutes*60)+(hours*60*60)+seconds.
Write a program that reads ten floats into an array called float_array. Find the total, average, smallest and largest numbers, and display each results with a width of 10 and to four decimal places.
If you can, split each of the tasks of the program into separate functions – one to display the title, one to read the values, one to find the statistics, and one to display all of the values (formatted) again, followed by the statistics. Make your variables global instead of passing them as parameters. This will make the program much easier to write.
There are various mathematical
functions defined in the standard C library stdlib.h and math.h
|
function |
library |
Description |
|
int i=abs(-123); |
stdlib.h |
Returns the absolute value of an integer number – i.e. the positive value. Thus, abs(123) returns 123, and abs(-123) also returns 123. |
|
int i=rand()%100; |
stdlib.h |
Returns a pseudo-random number from 0 to 99. |
|
randomize(); |
stdlib.h |
Randomizes the production of random numbers. Always include this line at least at the beginning of any program that uses random numbers. |
|
double d = pow(5.0,3.0); |
math.h |
Raises the first parameter to the power of the second parameter. The example given is 53 which is 5 x 5 x 5 = 125.0. Note that the parameters can be fractions. |
|
double s = sqrt(25.0); |
math.h |
Find the square root of the given value and return a double float value. In this example, the square root of 25 is 5 (i.e. 5 x 5 = 25 – this is the same as 51/2. |
For example, to generate 10 random
squared numbers: -
#include
<stdio.h>
#include
<stdlib.h>
#include
<math.h>
#include
<conio.h>
main()
{
for(int i=1; i<=10; i++) {
int rno = rand()%100;
printf("Number %02d: Square of %2d is %5d\n",
i,rno,(int)pow(rno,2.0));
getch();
}
}
Write a program that works out the length of the long side of a triangle (called the hypotenuse) given the length of the other two sides (called the opposite and adjacent sides).
Store the three values as float values (float type) and ask the user to input the two values (using the scanf function and the %f specifier).
Work out the value of the
hypotenuse as being the square of the adjacent side plus the square of the
opposite side, all square-rooted. i.e.
hypotenuse = sqrt (
pow(opposite,2) + pow(adjacent,2) );
Display the values of opposite, adjacent and hypotenuse on three separate, aligned (i.e. lined up) lines, with the values displayed with a width of 10 and with 3 decimal places.
After displaying the result, ask the user if he or she wishes to work out another value, and loop back to the beginning if the user presses the Y or y key, otherwise exit the program.
Sample output might be as
follows:-
Hypotenuse Calculator
---------------------
Enter Opposite: 12.5
Enter Adjacent: 17.5
Opposite
is: 12.50
Adjacent
is: 17.50
Hypotenuse is:
21.50
Press a key...
The following is a sample exam question to take away with
you to complete for the next session.
9531 – INTRODUCTORY COMPUTER PROGRAMMING: STRUCTURED ASSIGNMENT
Topic Games and Quizzes
Title of this Assignment
Bombs
The game of Bomb is a one-player
game on a hidden grid.
Devise a program that will play the
game "Bombs", with a single player.
The game should be played on a grid
that is 10x10 in size, using 1 to 10 down and A to J across to identify each
square in the grid.
The computer places ten bombs
randomly in the grid, but which are not shown on the screen.
The grid is then shown on the
screen. The grid should display 1 to 10 down the left hand side of the grid and
A to J across the top.
The player chooses an option from
one of the following choices: R for reveal, M for Mark, U for Unmark or X to
exit.
The player types out a grid
reference (e.g. A1 gives the top-left grid position, J10 gives the
bottom-right). This is used to identify a square on the grid. If anything
outside this range is typed, then the player is prompted to choose one of the
choices (R/M/U/X) again.
If R was chosen, then if the square
contained a bomb, the player is told GAME OVER, and after pressing a key, the
program exits. If the square contained nothing, then the eight squares
surrounding that square are checked. If any of them contain a bomb, they should
be counted, and the number of bombs surrounding the square should be placed in
the revealed square.
If M was chosen, the square is
marked with an X. If U was chosen, the square is marked with an space.
If X was chosen, then the program
exits, after the user is prompted about whether they are sure they want to quit.
Check all squares. If all squares
have been revealed or marked (i.e. not a space), and all marked squares have a
bomb underneath them, then display GAME OVER. WELL DONE. and after the user
presses a key, end the program.
Otherwise, loop back to clear the
screen, re-display the board, and ask what the user wants to do next.
It is recommended that you use two
arrays, one for the location of the bombs, one to show the user marks / revealed
squares. For example, a square marked with a digit as a character (1 to 8) would
show a revealed square with the number of unrevealed bombs next to it. An X
would show a marked square. A space would show an unrevealed square.
a) Describe briefly in writing for a possible user
i) The purpose of your program
ii) The limitations of your program
b) Construct (on paper) a screen layout indicating what will appear on the screen – prompts, input, output with annotations, any other messages.
c) Describe (on paper) the main stages of the program - by means of a flowchart or an alternative technique.
d) Produce a listing of the program. This should have adequate comment lines and should demonstrate to the examiner that the program solves the problem set.
e) Include in the program statements to display adequate instruction to the user of the program – e.g. prompts for data entry and appropriate error messages for invalid input.
f) Key in and run the program, producing and using simple test data if necessary. Check that the program's output agrees with the expected results and correct any errors.
g) Use appropriate language facilities.
Hint – Two-Dimensional Arrays
We have talked so far about single-dimension arrays –
e.g.
int i[3]; i[0]=1; i[1]=2; i[2]=i[0]+i[1];
which leaves us with i[2] containing the value of 3.
However, we can reproduce a grid, which is effectively an array of an array. If you take a row on our grid as an array of ten characters (char grid_row[10]) then the whole grid can be taken as an array of rows (char grid[10][10]) which gives us 10x10 characters. To access each element in the two-dimensional array, refer to the grid position as each dimension's position (from 0 to 9) in separate square brackets. E.g.
|
|
These are some sample results to the exercises given earlier in the session: -
#include
<stdio.h>
#include
<conio.h>
#include
<stdlib.h>
void
main() {
int hours,minutes,seconds;
scanf("%d:%d:%d",&hours,&minutes,&seconds);
printf("Second since midnight: %d\n",
(minutes*60)+(hours*60*60)+seconds);
getch();
}
/*
**
Session 6, Exercise 2
**
Written by Simon Huggins
*/
#include
<stdio.h>
#include
<conio.h>
#include
<stdlib.h>
/*
Function Prototypes */
void
show_title();
void
read_data ();
void
find_stats();
void
show_stats();
/*
Global Variables */
float
float_array[10], total, average, smallest, largest;
/*
Main Function */
void
main() {
show_title();
read_data();
find_stats();
show_stats();
printf("\n\nPress a key... "); getch();
}
/*
Display the title banner */
void
show_title() {
printf("Statistics Program\n");
printf("------------------\n\n");
}
/*
Read data into array from user */
void
read_data() {
for(int i=0; i<10; i++) {
printf("Enter value #%2d: ",i+1);
/* remember arrays do not need to be
prefixed with an & symbol */
scanf("%f",&float_array[i]);
}
}
/*
Find statistics */
void
find_stats() {
total=0; smallest=99999; largest=-99999;
for (int i=0; i<10; i++) {
total = total + float_array[i];
if (float_array[i] < smallest) smallest = float_array[i];
if (float_array[i] > largest ) largest
= float_array[i];
}
average = total / 10.0;
}
/*
Show statistics */
void
show_stats() {
clrscr();
printf("Results are as follows: -\n\n");
for (int i=0; i<10; i++)
printf("No.%2d is %10.4f\n",i,float_array[i]+1);
printf("\n\nStats are:-\nCount is 10\n");
printf(" Total is %10.4f\n",total);
printf(" Average is %10.4f\n",average);
printf("Smallest is %10.4f\n",smallest);
printf(" Largest is %10.4f\n",largest);
}
/*
**
Session 6, Exercise 3
**
Written by Simon Huggins
*/
#include
<stdio.h>
#include
<conio.h>
#include
<math.h>
main()
{
float opposite, adjacent, hypotenuse;
printf("Hypotenuse Calculator\n");
printf("---------------------\n\n");
printf("Enter Opposite: "); scanf("%f",
&opposite);
printf("Enter Adjacent: "); scanf("%f",
&adjacent);
hypotenuse = sqrt ( pow(opposite,2) + pow(adjacent,2) );
printf("\n\n Opposite is: %10.3f\n", opposite);
printf(" Adjacent is: %10.3f\n", adjacent);
printf("Hypotenuse is: %10.3f\n", hypotenuse);
printf("\nPress a key..."); getch();
}