An integer is a number without a decimal point – a whole number. Integers are good for problems like counting. Some problems, like counting every person on the planet, require really large numbers. Other problems, like counting the number of children in a classroom, require numbers that aren’t as large.
To address these different problems, integer variables come in different sizes. An integer variable has a certain number of bits in which it can encode a number, and the more bits the variable has, the larger the number it can hold. Typical sizes are: 8-bit, 16-bit, 32-bit, and 64-bit.
Similarly, some problems require negative numbers, while others do not. So, integer types come in signed and unsigned varieties.
An unsigned 8-bit number can hold any integer from 0 to 255. How did I get that? 28 = 256 possible numbers. And we choose to start at 0.
A signed 64-bit number can hold any integer from -9,223,372,036,854,775,807 to 9,223,372,036,854,775,807. 263 = 9,223,372,036,854,775,808 minus one bit for the sign (+ or -).
When you declare an integer, you can be very specific:
UInt32 x; // An unsigned 32-bit integer SInt16 y; // An signed 16-bit integer
However, it is more common for programmers just to use the descriptive types that you learned in Chapter 3.
char a; // 8 bits short b; // Usually 16 bits (depending on the platform) int c; // Usually 32 bits (depending on the platform) long d; // 32 or 64 bits (depending on the platform) long long e; // 64 bits
Why is char a number? Any character can be described as an 8-bit number, and computers prefer to think in numbers. What about sign? char, short, int, long, and long long are signed by default, but you can prefix them with unsigned to create the unsigned equivalent.
Also, the sizes of integers depend on the platform. (A platform is a combination of an operating system and a particular computer or mobile device.) Some platforms are 32-bit and others are 64-bit. The difference is in the size of the memory address, and we’ll talk more about that in Chapter 8.
Apple has created two integer types that are 32-bit on 32-bit platforms and 64-bit on 64-bit platforms:
NSInteger g; NSUInteger h;
In much of Apple’s code, you will see these types used. They are, for all intents and purposes, the same as long and unsigned long.
Create a new project: a C Command Line Tool called Numbers. In main.c, create an integer and print it out in base-10 (as a decimal number) using printf():
#include <stdio.h> int main (int argc, const char * argv[]) { int x = 255; printf("x is %d.n", x); return 0; }
You should see something like
x is 255.
As we’ve seen, %d prints an integer as a decimal number. What other tokens work? You can print the integer in base-8 (octal) or base-16 (hexadecimal). Add a couple of lines to the program:
#include <stdio.h> int main (int argc, const char * argv[]) { int x = 255; printf("x is %d.n", x); printf("In octal, x is %o.n", x); printf("In hexadecimal, x is %x.n", x); return 0; }
When you run it, you should see something like:
x is 255. In octal, x is 377. In hexadecimal, x is ff.
(We’ll return to hexadecimal numbers in Chapter 33.)
What if the integer has lots of bits? You slip an l (for long) or an ll (for long long) between the % and the format character. Change your program to use a long instead of an int:
#include <stdio.h> int main (int argc, const char * argv[]) { long x = 255; printf("x is %ld.n", x); printf("In octal, x is %lo.n", x); printf("In hexadecimal, x is %lx.n", x); return 0; }
If you are printing an unsigned decimal number, you should use %u:
#include <stdio.h> int main (int argc, const char * argv[]) { unsigned long x = 255; printf("x is %lu.n", x); // Octal and hex already assumed the number was unsigned printf("In octal, x is %lo.n", x); printf("In hexadecimal, x is %lx.n", x); return 0; }
The arithmetic operators +, -, and * work as you would expect. They also have the precedence rules that you would expect: * is evaluated before + or -. In main.c, replace the previous code with a calculation:
#include <stdio.h> int main (int argc, const char * argv[]) { printf("3 * 3 + 5 * 2 = %dn", 3 * 3 + 5 * 2); return 0; }
You should see
3 * 3 + 5 * 2 = 19
Most beginning C programmers are surprised by how integer division works. Try it:
#include <stdio.h> int main (int argc, const char * argv[]) { printf("3 * 3 + 5 * 2 = %dn", 3 * 3 + 5 * 2); printf("11 / 3 = %dn", 11 / 3); return 0; }
You’ll get 11 / 3 = 3.666667, right? Nope. You get 11 / 3 is 3. When you divide one integer by another, you always get a third integer. The system rounds off toward zero. (So, -11 / 3 is -3)
This actually makes sense if you think “11 divided by 3 is 3 with a remainder of 2.” And it turns out that the remainder is often quite valuable. The modulus operator (%) is like /, but it returns the remainder instead of the quotient:
#include <stdio.h> int main (int argc, const char * argv[]) { printf("3 * 3 + 5 * 2 = %dn", 3 * 3 + 5 * 2); printf("11 / 3 = %d remainder of %d n", 11 / 3, 11 % 3); return 0; }
What if you want to get 3.666667? You convert the int to a float using the cast operator. The cast operator is the type that you want placed in parentheses to the left of the variable you want converted. Cast your denominator as a float before you do the division:
int main (int argc, const char * argv[]) { printf("3 * 3 + 5 * 2 = %dn", 3 * 3 + 5 * 2); printf("11 / 3 = %d remainder of %d n", 11 / 3, 11 % 3); printf("11 / 3.0 = %fn", 11 / (float)3); return 0; }
Now, floating point division will be done instead of integer division, and you’ll get 3.666667. Here’s the rule for integer vs. floating-point division: / is integer division only if both the numerator and denominator are integer types. If either is a floating-point number, floating-point division is done instead.
All the operators that you’ve seen so far yield a new result. So, for example, to increase x by 1, you would use the + operator and then assign the result back into x:
int x = 5; x = x + 1; // x is now 6
C programmers do these sorts of operations so often that operators were created that change the value of the variable without an assignment. For example, you can increase the value held in x by 1 with the increment operator (++):
int x = 5; x++; // x is now 6
There is also a decrement operator (--) that decreases the value by 1:
int x = 5; x--; // x is now 4
What if you want to increase x by 5 instead of just 1? You could use addition and assignment:
int x = 5; x = x + 5; // x is 10
But there is a shorthand for this, too:
int x = 5; x += 5; // x is 10
You can think of the second line as “assign x the value of x + 5.” In addition to +=, there is also -=, *=, /=, and %=.
To get the absolute value of an int, you use a function instead of an operator. The function is abs(). If you want the absolute value of a long, use labs(). Both functions are declared in stdlib.h:
#include <stdio.h> #include <stdlib.h> int main (int argc, const char * argv[]) { printf("3 * 3 + 5 * 2 = %dn", 3 * 3 + 5 * 2); printf("11 / 3 = %d remainder of %d n", 11 / 3, 11 % 3); printf("11 / 3.0 = %fn", 11 / (float)3); printf("The absolute value of -5 is %dn", abs(-5)); return 0; }