Copyright (C) 1989 by Victor A. Wagner, Jr. All rights reserved. First off, a couple of apologies. I was somewhat under the weather this weekend which is why this lecture is late. Additionaly, I inadvertently uploaded the UNedited version of the CO from Thursday night (edited version uploaded tonight). You may want to download this weeks CLASS4.ARC even if you were at the class because it contains Daivd Art's homework #9 (as an example of a job well done). Additionally you may wish to review 'scope' which we talked about at the end of the CO. In an effort to see what we're talking about and where we are on the syllabus, I've decided to put the section headers in the text. 3. Types, Operators, and Expressions 3.1 Variable Names (would a rose by another name smell as sweet?) Even though we've been writing programs for several weeks now, and NO one has even hinted at difficulties in making up variable or constant names, I think I should _mention_ that there are, in fact, some restrictions on the formulations of names. There are two (2) main restrictions: 1) Names MUST start with a letter. 2) Names consist ONLY of letters and digits. Ok, ok! , the UNDERSCORE ('_') character (that looks almost like a fat smiley face, doesn't it?) is treated by the C language as a "letter". This character is VERY useful for making long variable names readable. Oh, I don't know whether to class this is a 'feature' or a 'restriction' but C is case sensitive; that is, UPPER case letters are distinct from lower case letters. This means that 'God' and 'god' would be distinct variables (The ONLY word in the English language that I'm aware of for which case makes a difference). Tradition ("...is wonderful, it just lasts too long") in C has variables spelled with lower case letters and symbolic constants spelled in UPPER. 3.2 Data Types and Sizes (the beginnings of abstraction) There are only a few basic data types in C: char a single byte, capable of holding one character in the local character set int an integer, typically reflecting the 'natural' size of the host computer (LOTS of argument here re: Amiga 'natural' size) float a single precision floating point double a double precision floating point In addition there are a number of qualifiers which can be applied to int's: short, long, and unsigned. short and long refer to different sizes of integers (about all you can say about them is that the range of shorts is guaranteed to be no larger than that of int and the range of long is guaranteed to be at least as large as that of int). unsigned numbers obey the laws of arithmetic just like integers except they are ALWAYS treated as if they are greater than or equal to zero (0). This means (for you math people, that the arithmetic is modula 2(to the)nth....where n is the number of bits in an integer. Declarations using qualifiers look like this: short int x; long int y; unsigned int z; The word int may be ommitted in such situations and typically is. The precision of these objects depends on the compiler and options you are using, but I'll try to give a rundown. type Lattice Manx PDC char 8 8 8 short int 16 16 16 long int 32 32 32 float 32 32 --Not supported int 32/opt 16/opt 32(I think) Note that you're probably better explicitly using short or long rather than int because of the uncertainty. The notation x/opt means that it defaults to x, but there is a compiler option to change it. 3.3 Constants (some things DON'T change) We've previously discussed integer constants and we're currently ignoring float (since the PDC does NOT support it, and until you understand error analysis a little better, it's safer to stay away from it). Long constants, by the way, are written thus: 123L. If you write a constant that is too big to fit in an 'int' it will be taken to be a long (assuming it's small enought to fit in a long). If you're into 'octal' (you know, it's like decimal...if you don't have thumbs) you can write octal constants by starting them with a zero (0) as in 012. Hexadecimal numbers can be written with a leading 0x or 0X. For example the number 25 in decimal can be written 031 in octal or 0x19 in hex. Either hexadecimal or octal constanst may be followed by an L to make them long. A character constant is a single character written within single quotes (I'll call them squotes in the future) for example, 'y'. The value of the character constant is the numeric value of the character in the machines character set. In the ASCII character set, '0' is 48; in EBCDIC, '0' is 240 each of which is different from the value 0. Writing '0' instead of either 48 or 240 makes the program independent of the character set, and to some extent of the machine. Character constants may be used in expressions just like any other constants although they are most often used in comparisons with other characters. Some of the more common non-grapic characters can be represented in character constants by 'escape sequences' like in \n (newline), \t(tab), \\(backslash), \'(squote), etc. which LOOK like 2 characters but are actually only one. You can represent an arbitrary byte-sized constant by writing: \ddd where ddd is one to three OCTAL digits, as in #define LINEFEED \012 /* ASCII line feed */ The constant '\0' represents the character with zero value (null) and is often written instead of 0 to show the 'characterness' of the expression (Thomas Aquinas's ghost would be proud). A constant expression is an expression which contains ONLY constants. Such expressions are evaluated at compile time (rather than at execution time) and may then be used in any place that a constant may be: #define MAXWORDSIZE 15 long lengths[MAXWORDSIZE+1]; or perhaps seconds = 60 * 60 * hours; A string constant is a sequence of zero or more characters surrounded by double quotes (") like: "this is a string" or "" /* the null string */ The quotes are part of the string, but only to delimit it. You can use the same escape sequences in a string as you can in a character constant (\" represents the double quote). From one point of view, a string looks like an array whose elements are single characters. The compiler automatically places a null charcter \0 at the end of each string. This allows you to conveniently find hte end of the string. This representation allows for unlimited length strings, but programs have to scan the entire string to find out how long it is. The physical storage required is one MORE location that the length of the string (to hold the \0). The function which follows is an example of how the library function strlen(s) _could_ be written; int strlen(s) /* return length of s */ char s[]; { int i; i = 0; while (s[i] != '\0') i++; return(i); } Be careful to distinguish between 'x' and "x", the former is a single character used to produce the numeric value of the letter x in the machines instruciton set. The latter is a character string which contains TWO (2) characters (the letter x and a \0). 3.4 Declarations (how we tell the compiler what we are talking about) All variables must be declared to the compiler before we can use them, although certain declarations can be made implicitly by use. A declaration consists of a 'type' followed by a list of variables of that type e.g. short bottom, top, side; char c, buffer[80]; Variables may be collected together or distributed like: short bottom; short top; short side; char c; char buffer[80]; The second method takes more room, but allows you to put comments with each declaration. Variables may also be initialized in the declaration, although thre are some restricitons. If you put an equals sign (becomes operator (=)) behind the name and a constant, that is an initializer. char squuote = '\''; int i = 0; If the variable in question is external (more later) or static, then the initialization appears to be done BEFORE program execution (and therefor occurs only once). Explicitly initialized local variables (also called 'automatic' variables) are initialized each time the function is called. Local variables which are NOT explicetly intializd have undefined values. Static and external varialbles are initialized to zero (0) if you give no explicit initialization, but good style dictates that you initialize them anyhow, if you expect them to have initial values. 3.5 Arithemetic Operators (you know, normal add, subract...) There are 5 binary operators (they require two operands) and only one unary operator. The binary operators are +, -, *, /, and %. The unary operator is - (there is no + unary operator). The symbols have their normal meanings BUT: Integer division truncates any fraction part (we saw that early on) and the expression: x % y produces the remainder when x is divided by y. If y 'goes into' x exactly, the above expression will be 0; so if, for example, you're trying to find out if it's a leap year (and write a _correct_ date routine), you might: if (year%4==0 && year%100!=0 || year%400==0) else assuming the Gregorian calendar. By the way, the % operator cannot be applied to float or double. Just as we learned when we were in school, in an expression without parenthesis, there are some operators which we do before others. We indeed do 'multiply' and 'divide' before 'add' and 'subtract'. The % (remainder) operator is considered to belong to the 'multiply divide' group for these purposes. We do the unary 'minus' even before the multiply and divides. The order of evaluation is NOT specified for associative and commutative operators (like * and +) and the compiler MAY rearrange even a parenthesized expression using one of these. Therefore a+(b+c) MAY be evaluated as (a+b)+c. This rarely makes any difference (but in MY opinion is almost criminal to allow....it makes error analysis a _real_ problem), but if you _need_ to specify order, explicit temporary variables MUST be used. Again I apologize for the lateness (and therefore shortness) of this lecture (I am feeling better, but the time is getting short). Therefore there will be ONLY one homework problem...and this one is sort of a research problem (not everything you will need has been covered in class), but you should be able to come up with part of the solution. HOMEWORK #10. Write a program which prints out the smallest and largest values which can be held by variables of the type char, short, int, long as well as the unsigned versions of them. See if you can write this program so that it would run on _any_ C machine. This program has _some_ practical use (we should find some differences in the compilers) but it is mostly an exercise in 'thinking at the problem differently'. Oh, if your compiler has a switch for the size of int, compile this problem with the default setting. See you Thursday night.