Week 2: Rotation, Digits, and sizeof
Rotating three values through one temporary, cutting a real number into its integral and decimal parts and reading off a digit, and printing the size of every basic type: what truncation, the sign of a remainder, and implementation-defined widths actually mean.
Values That Move, Split, and Get Measured
Week 2 has four short programs and every one of them is about what happens to a value in transit. Three variables rotate through each other, which is the swap from chapter 3 with one more step. A real number is cut into its whole and fractional parts, which is the double-to-integer conversion from chapter 3 doing exactly what the standard says and nothing more. And sizeof reports how much room each type takes, which is chapter 2 turned into a printout. Nothing beyond chapters 2 to 4 is needed.
Program 1: Rotate Three Values
Given x, y, and z, make x take the value of y, y take the value of z, and z take the value of x. Print the three before and after.
Algorithm:
- Start.
- Read x, y, and z.
- Print the three values.
- Save x in a temporary variable.
- Assign y to x.
- Assign z to y.
- Assign the saved value to z.
- Print the three values again.
- Stop.
Run it with 1 2 3 and the second line reads x = 2, y = 3, z = 1. Now delete temp, replace the last assignment with z = x;, and run it again: z comes out as 2, because by the time that line runs x already holds the old y. The chapter 7 bubble sort needed a temporary to swap two values; a rotation of three needs the same one temporary, and only one, because after x is saved every other value has a free slot to move into. Trace it on paper with the three boxes and an arrow for each assignment; that trace is what an examiner asks for in the viva.
Program 2: The Right-Most Digit of the Integral Part
Read a real number such as 123.45 and print the last digit of its whole part, here 3.
Algorithm:
- Start.
- Read the real number.
- Convert it to a whole number, discarding the fraction.
- Take the remainder on division by 10; if it is negative, negate it.
- Print the digit.
- Stop.
123.45 gives 3, and 9.99 gives 9, not 0: the cast to long truncates toward zero, it never rounds, so 9.99 becomes 9. That is the whole reason the cast is the right tool here and a rounding function is not. -56.7 gives 6 only because of the sign fix: the cast produces -56, and week 1's rule says -56 % 10 is -6, so the program negates a negative remainder before printing.
One thing the standard says and the lab manual does not: converting a double to an integer type is undefined behaviour when the whole part does not fit in that type. A long is guaranteed at least 32 bits, and on this platform it is 64, so any number you would type at a keyboard is safe; a program that reads values from a file it does not control would need to check the range before casting.
Program 3: Integral and Decimal Parts
Read a real number and print its whole and fractional parts separately: 123.45 becomes 123 and 0.45.
Algorithm:
- Start.
- Read the real number.
- Convert it to a whole number to get the integral part.
- Subtract the integral part from the number to get the decimal part.
- Print both parts.
- Stop.
The subtraction on step 4 mixes a double and a long, and chapter 3's conversion rule promotes the long to double, so decimal is a real number. For -12.75 the parts come out as -12 and -0.75: both carry the sign, and that is the honest answer, since the two parts must add back up to the original.
Change %.2f to %.20f and run 123.45 again. The decimal part prints as something like 0.45000000000000284217, not 0.45, because 123.45 has no exact binary representation and the subtraction exposes the error that was there all along. %.2f is not hiding a bug; it is the correct amount of precision to claim for a number that was never exact. The library function modf in <math.h> does this split in one call and is a good answer to the viva question "is there another way".
Program 4: Sizes of the Data Types
Print the size in bytes of each basic type.
Algorithm:
- Start.
- For each type in turn, compute its size with
sizeof. - Print the type's name and its size.
- Stop.
sizeof yields a value of type size_t, an unsigned type whose exact identity the platform chooses. C99 added %zu to print it directly; C89 has no such specifier, so the portable C89 form is the one above: cast to unsigned long and print with %lu. Chapter 2 stored the result in an unsigned long variable first, which is the same idea in two statements.
What the output means is the exam question. On this platform int is 4 and long is 8. Those are facts about this compiler, not about C: the standard guarantees only minimums, char exactly 1 byte by definition, short and int at least 16 bits, long at least 32. The textbook's tables, written for 16-bit Turbo C, say int is 2, and an answer that says "int is 2 bytes" or "int is 4 bytes" without naming the platform is wrong either way. The sentence to write is that sizeof(int) is implementation-defined, and this program is how you find out.
Key Takeaways
- Rotating three values takes one temporary and three assignments, saved value first, in the order that leaves each slot free before it is written.
- Casting a
doubleto an integer type truncates toward zero, never rounds; it is undefined behaviour if the whole part does not fit. - The remainder of a negative number is negative, so extracting a digit from a possibly negative value needs a sign fix.
- Subtracting the truncated whole part from a
doubleleaves the fraction, with the same sign as the original and the binary error%.2fsensibly hides. sizeofyieldssize_t; in C89 print it as(unsigned long)with%lu.- Type sizes are implementation-defined: the standard fixes minimums, not widths, and the program is the only way to learn what a platform chose.
How did you find this lesson?
Your rating helps us improve the content.
Create an account to track your progress and access interactive exercises. Already have one? Sign in.
Practice Exercises
Rotate Three Values
Read three integers x, y, and z. Print them on one line in the form before: x = 1, y = 2, z = 3. Then rotate the values so that x takes the value y had, y takes the value z had, and z takes the value x had, and print them again in the form after: x = 2, y = 3, z = 1. Use a single temporary variable for the rotation. If the three integers cannot be read, print invalid input and return 1.
The Right-Most Digit of the Integral Part
Read one real number and print the right-most digit of its integral part, in the form right-most digit = 3. For 123.45 the integral part is 123 and the answer is 3. Truncate the number to a whole number, do not round it: 9.99 gives 9. The digit is always printed as a value from 0 to 9, even for a negative input, so -56.7 gives 6. If the number cannot be read, print invalid input and return 1.
Integral and Decimal Parts
Read one real number and print its integral part and its decimal part on two lines, in the form integral part = 123 and decimal part = 0.45. The integral part is the number truncated toward zero, printed as a whole number; the decimal part is what remains when the integral part is subtracted, printed to two decimal places. Both parts keep the sign of the input, so -12.75 gives -12 and -0.75. If the number cannot be read, print invalid input and return 1.
Sizes of the Data Types
Print the size in bytes of each basic type using the sizeof operator, one type per line, in this order and format: char: 1, short: 2, int: 4, long: 8, float: 4, double: 8, long double: 16. The numbers must come from sizeof, not from typing them in, and they are printed with %lu after casting the result of sizeof to unsigned long, since C89 has no conversion specifier for size_t. The program reads no input.
Lesson Discussion
Share your thoughts and questions
No comments yet. Be the first to share your thoughts!