# Category : C Source Code

Archive : TEACH-C.ZIP

Filename : LESSON1

A NOTE ABOUT THE LESSONS in C

.b4-24

.R5C4

These were written while the author was ~Ilearning~N the language and since

.R6C4

they are ~Ifree~N ( to copy and/or distribute ) there is a money-back

.R7C4

guarantee on the accuracy of each and every statement in the lessons (!)

.R9C4

The ~Idisplay~N program was written ( in C ) in order to provide a vehicle

.R10C4

for displaying the lessons.

.R12C5

.B

P.J.Ponzo

.B

Dept. of Applied Math

.B

Univ. of Waterloo

.B

Ontario N2L 3G1

.K16,30

[1mPonzoTUTOR

.WNT

Getting Started in C : INPUT and OUTPUT

Using a word processor, we begin our C-program with ~b~Imain()~N and a

left curly bracket ~b~I{~N. Now we can write a program and finish it

with a right curly bracket:

~b~Imain() {~N

~b~I.........................~N

~b~Iyour program goes in here~N

~b~I.........................~N

~b~I}~N

Everything between ~b~I{~N and ~b~I}~N constitutes the ~b~Imain()~N program.

One of the things we will want to do is print to the screen. There is

a C command called ~b~Iprintf~N, meaning ~b~Iprint~N with ~b~If~Normat.

~b~Iprintf("this is some text to print.");~N

The above command will simply print ~r~Ithis is some text to print.~N

The ~b~If~Normat part of ~b~Iprintf~N comes in handy if we want to print,

say, a number with a specified number of decimal places.

.W

.N

.T

More on printf

.R4C1

~b~Iprintf("the answer is %6d",x);~N

.R6C1

The above will print the value of the variable ~b~Ix~N.

.W

.R4C1

~b~Iprintf("~Vthe answer is ~N~b~I%6d",x);~N

.R6C1

This part just prints the words ~r~Ithe answer is ~N

.W

.R4C1

~b~Iprintf("the answer is ~V%6~N~b~Id",x);~N

.R6C1

This says the number ~b~Ix~N is printed to ~b~I6~N digits.

.W

.R4C1

~b~Iprintf("the answer is %6~Vd~N~b~I",x);~N

.R6C1

This says that a ~b~Id~Necimal is being printed.

.W

.R4C1

~b~Iprintf("the answer is %6d",~Vx~N~b~I);~N

.R6C1

Here is the variable ~b~Ix~N which is to be printed.

.w

.W

.R4C1

~b~Iprintf("the answer is %6d",x)~V;~N

.R6C3

~I

.B

~R...and (almost) EVERY C STATEMENT ENDS IN A SEMI-COLON ! ~N

.W

.R11C1

Here's the whole program:

~b~Imain() {~N

~b~Ix=1234~N

~b~Iprintf("the answer is %6d",x);~N

~b~I}~N

and we expect the program to give the output: ~r~Ithe answer is 1234~N

...but it WON'T ( yet ).

(In fact, your ~IC-compiler~N won't compile the program!)

.K17,60

...alas...

.WNT

A look at DATA TYPES

When we write ~b~Ix=1234~N we expect the C compiler to reserve some memory

for the variable ~b~Ix~N and place in this memory the number ~b~I1234~N.

If, subsequently, we write ~b~Ix=12345678~N, will this fit into the memory

reserved for the variable ~b~Ix~N?

In order to know ,in advance, how much memory to set aside for each

variable we use in our C program, we must declare the variable ~Itype~N.

If ~b~Ix~N is an integer (so we will NOT set ~b~Ix=1.234~N) then we say

so with the declaration: ~b~Iint x;~N

If ~b~Ix~N will take on values like ~b~I1.234~N (a ~Ifloating point~N

~Inumber~N) then we write: ~b~Ifloat x;~N

If ~b~Ix~N is a ~Icharacter~N variable (for example ~b~Ix='A'~N) then

we declare this too: ~b~Ichar x;~N

.WNT

Declaring the DATA TYPE

Now we may write:

~b~Imain() {~N

~b~Iint x;~N

~b~Ix=1234;~N

~b~Iprint("the answer is %6d",x);~N

~b~I}~N

and NOW our program WILL print: ~r~Ithe answer is 1234~N

.WR13C1

What will the following program print?

~b~Imain() {~N

~b~Ifloat x;~N

~b~Ix=1234;~N

~b~Iprint("the answer is %6d",x);~N

~b~I}~N

.K17,60

I give up!

.WN

~b~Imain() {~N

~V~Ifloat x;~N

~b~Ix=1234;~N

~b~Iprint("the answer is %6d",x);~N

~b~I}~N

Because we declared ~b~Ix~N to be a ~V~Ifloat~Ning point number

the value of ~b~Ix~N is stored in a different format, in memory.

As a ~V~Ifloat~N, ~b~Ix=1234~N will be stored as a number ~Iless than~N

~I1~N together with an ~Iexponent~N ("scientific notation").

The above program will print: ~r~Ithe answer is 0~N !!!

.WR2C1

~b~Ifloat x;~N

.R4C1

~b~Iprint("the answer is %6~Vd~N~b",x);~N Note the ~Vd~N.

.R13C1

The ~b~Iprintf~N command expected a number in ~V~Id~Necimal format.

But ~b~Ix~N was stored in memory in ~b~Ifloat~N format.

The result is a misinterpretation of the value of ~b~Ix~N by ~b~Iprintf~N!

.K17,60

all greek

.W

.N

~b~Imain() {~N

~b~Ifloat x;~N

~b~Ix=1234;~N

~b~Iprint("the answer is %6~Vf~N~b",x);~N Note the ~Vf~N

~b~I}~N

To tell ~b~Iprintf~N the format in which ~b~Ix~N was stored, we use an

~V~If~N in the "format" portion of the ~b~Iprintf~N command (i.e. the

part within quotes).

.WR4C1

~b~Iprint("the answer is %6f",x);~N

.R10C1

~b~Imain() {~N

~b~Ichar x;~N

~b~Ix='A';~N

~b~Iprintf("As a character, x has the value %c",x);~N

~b~I}~N

What will this program print?

.K17,60

I give up!

.WR17C1

~r~IAs a character, x has the value A~N

.WNT

INTEGERS and FLOATS

.R4C1

~b~Ifloat x;~N

~b~Ix=1234+1/2;~N

In the above program segment, what do you think the value of x is ?

.W

It's ~I1234.0~N !!!

.sR5C1

~b~Ix=~V1234~N~b~I+~V1~N~b~I/~V2~N~b~I;~N

.r

Numbers like ~b~I1234~N and ~b~I1~N and ~b~I2~N are automatically ~b~Iint~Negers

and dividing the last two would give ~I0~N (dropping the fractional part!)

so ~I1234+0~N gives ~I1234~N which (because ~b~Ix~N is a ~b~Ifloat~Ning point

number) is NOW converted to a ~b~Ifloat~N and assigned to ~b~Ix~N !!!

In order to yield the value ~I1234.5~N we ~Iinclude the decimal points~N:

~b~Ix=1234.+1./2.;~N

and NOW all numbers are ~b~Ifloat~Ning point and ~b~Ix~N will be assigned the

value ~I1234.5~N so ...~Iinclude the decimal points~N when necessary!

.WN

~b~Ifloat x;~N

~b~Ix=1234+1./2.;~N

Here the ~b~I1./2.~N is evaluated as ~b~I.5~N (a float, because of the decimal

points) and ~b~I1234~N is converted to a float then added, giving ~I1234.5~N

which is assigned to ~b~Ix~N.

~b~Ifloat x;~N

~b~Ix=1234+1./2;~N

Here, the decimal associated with ~b~I1.~N causes the ~b~I2~N to be converted

to a float, so ~b~I1./2~N gives ~I.5~N, and the addition of ~b~I1234~N (which

is first converted to a float) gives ~b~I1234.5~N, which is then assigned to ~b~Ix~N.

The conclusion? ~IC~N tends to convert numbers in a ~Imixed~N expression to

~b~Ifloat~Ning point before evaluation ....but don't rely on it!

If you want ~b~Ifloat~Ning point operations, ~Iinclude the decimal points!~N

.WNT

INPUT from the KEYBOARD with scanf()

Now that we've been introduced to ~b~Iprintf~N (which will print things

on the screen, or to the printer, or to a disk file, as we will see...)

we should introduce ~b~Iscanf~N which allows us to input numbers 'n' such

from the keyboard.

~b~Imain() {~N

~b~Ichar x;~N

~V~Iscanf("%c",x);~N Note the ~V~I%c~N!

~b~Iprintf("You pressed the ~V%c~N~b key",x);~N Note the ~V~I%c~N!

~b~I}~N

The ~b~Iscanf~N command waits for the user to type something, and

~b~Iscanf("%c",x)~N puts the ~b~Ic~Nharacter typed, into the memory

reserved for the variable ~b~Ix~N. When the compiled program is run

it will wait for the user to press a key (followed by the ~IEnter~N key).

Suppose you ran the program and pressed the ~Ia~N key (then ~IEnter~N).

What would the program print on the screen?

.WR22C1

~r~IYou pressed the key~N ~IIT DIDN'T WORK!!!~N

.WNT

About Memory Locations...and the & prefix

~b~Imain() {~N

~b~Ichar x;~N

~V~Iscanf("%c",x);~N

~b~Iprintf("You pressed the %c key",x);~N

~b~I}~N

When ~b~Iscanf()~N is used, we must tell it WHERE, in memory, to put

the ~b~Ichar~Nacter ~b~Ix~N. Saying ~b~Iscanf("%c",x)~N is not enough!

To identify the ~Imemory address~N for the variable ~b~Ix~N, we prefix

~b~Ix~N with ~b~I&~N.

If ~b~Ix~N is ~Iany~N variable (~b~Iint~N or ~b~Ifloat~N or ~b~Ichar~N)

then ~b~I&x~N is the ~Iaddress~N in memory of ~b~Ix~N.

.K17,60

[1m&x[0m=address

.WN

~b~Imain() {~N

~b~Ichar x;~N

~V~Iscanf("%c",x);~N

~b~Iprintf("You pressed the %c key",x);~N

~b~I}~N

The above program must be changed to read:

~b~Imain() {~N

~b~Ichar x;~N

~b~Iscanf("%c",~V&x~N~b);~N Note the ~V&x~N.

~b~Iprintf("You pressed the %c key",x);~N

~b~I}~N

...THEN it will wait for a key-press (for example the letter ~Iz~N)

and print: ~r~IYou pressed the z key~N

.W

.R18C1

Since ~b~Ichar x;~N reserved only enough space for ~IONE~N character,

what would the printout be if you pressed several keys...say ~Ipqr~N?

.W

.R21C1

~r~IYou pressed the p key~N ~IJUST THE FIRST CHARACTER!~N

.WNT

What's wrong with the following program?

.R4C1

~b~Imain() {~N

~V~Iint x;~N

~V~Ichar y;~N

~V~Ifloat z;~N

~b~Iprintf("Enter 3 numbers (separated by a space)");~N

~b~Iscanf("%d%c%f",&x,&y,&z);~N

~b~Iprintf("x=%c y=%f z=%d",x,y,z);~N

Note that ~b~Ix~N, ~b~Iy~N and ~b~Iz~N are declared ~V~Iint~N, ~V~Ichar~N

and ~V~Ifloat~N.

.WR5C1

~b~Iint x;~N

~b~Ichar y;~N

~b~Ifloat z;~N

~V~Iprintf("Enter 3 numbers (separated by a space)");~N

.R12C1

This line just prints instructions:

~r~IEnter 3 numbers (separated by a space)~N

.WR8C1

~b~Iprintf("Enter 3 numbers (separated by a space)");~N

~V~Iscanf("%d%c%f",&x,&y,&z);~N

.R12C1

This line waits for you to type in the 3 numbers (with spaces).

Note the ~V~I&x~N, ~V~I&y~N and ~V~I&z~N as required by ~V~Iscanf()~N!

.W

.R9C1

~b~Iscanf("%d%c%f",&x,&y,&z);~N

~V~Iprintf("x=%c y=%f z=%d",x,y,z);~N

.R12C1

Now we ~V~Iprintf()~N the 3 numbers, expecting the printout to appear as:

~r~Ix=123 y=123 z=123~N (assuming the 3 numbers were all ~I123~N).

What do you think gets printed on the screen?

.W

.R10C1

~b~Iprintf("x=~V%c~N~b y=~V%f~N~b z=~V%d~N~b",x,y,z);~N

.R15C1

Alas, we gave ~b~Iprintf()~N the DATA TYPES in the wrong order!

Although ~b~Iscanf()~N got the ~b~Iint~Neger ~b~Ix~N as ~I123~N, and

put it in the right memory location ('cause we said ~b~I&x~N)...and

it also got ~b~Iy~N as ~I1~N (NOT 123), a single ~b~Ichar~N.....

(because the ~b~Iy~N memory location only holds a single character!)

and it also got ~b~Iz~N and stored it as a ~b~Ifloat~Ning point number,

and put it in the correct memory location...so ~Iwhat gets printed?~N

.WN

~b~Imain() {~N

~b~Iint x;~N

~b~Ichar y;~N

~b~Ifloat z;~N

~b~Iprintf("Enter 3 numbers (separated by a space)");~N

~b~Iscanf("%d%c%f",%x,%y,%z);~N

~b~Iprintf("x=%c y=%f z=%d",x,y,z);~N

The printout produced by the above program (after entering ~I123~N

for each of ~b~Ix~N, ~b~Iy~N and ~b~Iz~N, separated by a space) is:

~r~Ix={ y=-2.000000 z=16478~N

.K2,60

mamma mia!

...so ~b~Iprintf()~N was confused once more!

~I>~N It interpreted ~b~Ix~N as a ~b~I%c~Nharacter variable (!) and out came ~r~I{~N.

(the ASCII code for '{' is 123 ...but more on ASCII later).

~I>~N It printed the contents of ~Iseveral~N memory locations, starting with

the ~IONE~N reserved for ~b~Iy~N (a ~b~Ic~Nhar) as a ~b~I%f~Nloating point

number (and out came ~r~I-2.000000~N).

~I>~N Finally, it went to the memory location reserved for ~b~Iz~N (which held

a ~b~If~Nloating point number ... in "scientific" format, remember?)

and interpreted it as an ~b~Ii~Nnteger, namely ~r~I16478~N !!!

.WNT

REVIEW of printf() and scanf()

.R4C1

~b~Iprintf("~Vtext and 'format' info~N~b",variable names separated by commas);~N

~b~Iscanf("NO TEXT, just 'format' info",variable names separated by commas);~N

We must give ~b~Iprintf()~N information about the 'format' of the

variables which are to be printed. Text may be mixed with the various

~b~I%d~N, ~b~I%c~N and ~b~I%f~N format information.

.W

.R4C1

~b~Iprintf("text and 'format' info",~Vvariable names separated by commas~N~b);~N

.R12C1

In here goes the variables to be printed (if any).

.W

.R4C1

~b~Iprintf("text and 'format' info",variable names separated by commas);~N

~b~Iscanf("~VNO TEXT, just 'format' info~N~b",variable names separated by commas);~N

.R14C1

In here goes ~IONLY~N format information for ~b~Iscanf()~N.

.W

.R6C1

~b~Iscanf("NO TEXT, just 'format' info",~Vvariable names separated by commas~N~b);~N

.R16C1

In here goes the names of the variables, like ~b~Ix,y,z~N....~Iright?~N

.W

.R18C1

~IWRONG! WRONG! WRONG!~N

In here goes the ~Iaddresses~N of the variables, like ~b~I&x,&y,&z~N!

~V~BNOTE: These addresses are called ~Rpointers~B, because they 'point'~N

~V~B to the memory locations which are reserved for the variables.~N

.W

.N

.T

some final comments about printf() and scanf()

.R4C1

We saw, earlier in this lesson, the statement:

~b~Iprintf("the answer is ~V%6~N~bd",x);~N

We may specify the number of screen positions (the ~Ifield width~N) which the

number is to occupy when ~b~Iprintf()~N is invoked (in the above

example, it's ~b~I6~N positions). For an ~b~Iint~Neger, that's all

that's necessary, but for a ~b~Ifloat~Ning point number we may also

specify the number of digits after the decimal. If we just say ~b~I%f~N

then we will get ~I6~N decimal places (remember ~r~Iy=-2.000000~N?).

.W

.R15C1

~b~Iprintf("the answer is ~V%6.3~N~bf",x);~N

In this statement, if ~b~Ix~N were a ~b~If~Nloat and equal to ~I12.3456~N

then what do you think would be printed?

.W

.R20C1

~r~Ithe answer is 12.346~N rounded to ~I3~N decimal places!

.W

.N

~b~Imain() {~N

~b~Ifloat x;~N

~b~Ix=-12.3456;~N

~b~Iprintf("x=%6.3",x);~N

~b~I}~N

Note that ~b~Ix=-12.3456~N ~Icannot~N be printed in ~b~I6~N positions

with ~b~I3~N decimal places. The first ~b~I6~N positions would give

only ~r~Ix=-12.34~N (or ~r~Ix=-12.35~N if rounded). But ~b~Iprintf()~N

is a smart guy (gal?) and ~V~Bincreases the field width as necessary~N

...and prints:

~r~Ix=-12.346~N

For numbers (either ~b~Iint~N or ~b~Ifloat~N) the ~Ifield width~N is

understandable....but what about ~b~Ichar~N variables which are single

characters and will only occupy ~Ione~N screen position anyway?

~b~Ix='Z';~N What do you think

~b~Iprintf("x=%6c",x);~N this will print?

.W

.R22C1

~r~Ix= Z~N the ~IZ~N is right-justified in a field width of ~I6~N!

.WNT

...and then there's CAST

Suppose you desparately need to have an ~b~Iint~Neger variable converted

to a ~b~Ifloat~Ning point number. Maybe you wanted to compute the sine

of an ~b~Iint~N called ~b~Ix~N. Using ~b~Isin(x)~N is no good because the

~Isin(x)~N function only works for ~Ifloat~Ning ~b~Ix~N.

You could use a "spare" ~b~Ifloat~N variable, say ~b~I float y; ~N, and

say:

~b~I y=x; ~N (which does an ~Iautomatic conversion~N when it assigns

the x-value to y, from ~b~Iint~N to ~b~Ifloat~N)

then use:

~b~Isin(y)~N (which is OK since ~b~Iy~N is now a ~b~Ifloat~N)

~IOR~N, rather than having to declare ~b~I float y; ~N just to have ~b~Iy~N

in reserve for this "conversion" purpose, you may use the CAST.

.WK10,32

a CAST?

.WN

~b~Isin( (float)x )~N will temporarily convert the ~b~I int~Neger ~b~Ix~N

to a ~b~Ifloat~N (for purposes of computing the

~b~Isin~N) but ~Ileave x unchanged~N.

This is called a CAST (in C-speak).

.W

~b~Iint x;~N

~b~Ix=10;~N

~b~Iprintf("Here's an integer, printed to 6 decimal places! %f",~V(float)~N~b~Ix);~N

The above reCASTs the ~b~Iint~Neger ~b~Ix~N for ~b~Iprintf~Ning as a

~b~I%f~Nloat, and you get the output:

~r~IHere's an integer, printed to 6 decimal places! 10.000000~N

...and of course you may refer to ~b~I(int)y~N to provide an ~b~Iint~Neger

copy of ~b~Iy~N (without changing ~b~Iy~N herself).

.K19,60

fantastico

.WNT

...a final note on DATA TYPES

We have talked about numbers stored (in memory) in ~b~Iint~N and ~b~Ifloat~N

format. Whereas the ~b~Iint~N format can represent an integer in the range

-32768 to 32767 (with sign) and the ~b~Ifloat~N format can hold a number with

6 significant figures (roughly) we also can declare a number to be ~b~Idouble~N

which is an ~Iextended~N floating point number and gives (about) 13 significant

figures.

Also, we can have an integer which runs from 0 to 65535 by declaring it to

be an ~b~Iunsigned int~N (which then is always non-negative). Although

this ~Itype~N occupies the same memory space as ~b~Iint~N, dropping the

'sign' allows for double the magnitude of integer.

We can also have a ~b~Ilong int~N which occupies twice as much memory

and can represent integers from (about) -2,000,000,000 to 2,000,000,000.

.b21-23

.R22C8

The sizes given above, may differ from one machine to another!

.WN

.T

That's all folks!

.K16,32

au revoir!

.q

Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/