C's 37 reserved words:
Identifiers in C:
auto enum restrict unsigned
break extern return void
case float short volatile
char for signed while
const goto sizeof _Bool
continue if static _Complex
default inline struct _Imaginary
do int switch
double long typedef
else register union
Note:
int myAge;
is different from
int MyAge;
int abcdefghijklmnopqrstuvwxyz12345;
and
int abcdefghijklmnopqrstuvwxyz12346;
but compilers are not guaranteed to distinguish between
int abcdefghijklmnopqrstuvwxyz123456;
and
int abcdefghijklmnopqrstuvwxyz123457;
num_courses_taken = compute_num_courses_taken (student_ID);
numCoursesTaken = computeNumCoursesTaken (studentID);
for (i=0; i < 10; i++) {
A[i] = B[i] * C[i];
}
Exercise 2.1:
What kind of a compiler error do you get if you try to use
a reserved word as an identifier? Use a reserved word to
declare an integer identifier.
There are two types of comments in ANSI C99:
to the end of the line.
#include <stdio.h> /* This is a block comment. Everything between the begin-comment symbol and the end-comment symbol is ignored by the compiler. It is conventional to use a separate line for the end-comment symbol. */ // This is an in-line comment. int main (/* A strange place for a block comment */) { printf ("Hello World!\n"); // Another inline comment. }Note:
gcc -o helloworld -std=c99 helloworld.c
gcc -o helloworld helloworld.calso works, but will not check for ANSI C99 compatibility.
The first line, and perhaps the next few, typically have
#include's.
#include <stdio.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int main ()
{
printf ("Hello World!\n");
}
with the understanding that the
actual file
has the necessary
#include's.
About C's data types:
Integer types (ANSI C99 additions shown in bold):
Type | Typical storage size | Range | Print specifier |
int | 2 or 4 bytes | -32,768 to 32,767 (2 bytes)
-2,147,483,648 to 2,147,483,647 (4 bytes) |
%d |
unsigned int | 2 or 4 bytes | 0 to
65,535 (2 bytes) 0 to 4,294,967,295 (4 bytes) |
%u |
short | 2 bytes | -32,768 to 32,767 | %d |
unsigned short | 2 bytes | 0 to 65,535 | %u |
long | 4 bytes | -2,147,483,648 to 2,147,483,647 | %ld |
unsigned long | 4 bytes | 0 to 4,294,967,295 | %lu |
long long | 8 bytes | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 | %lld |
unsigned long long | 8 bytes | 0 to 18,446,744,073,709,551,615 | %llu |
Let's look at an example:
(source file)
#include <stdio.h>
int main ()
{
int numDaysInYear = 365;
long int numStarsInUniverse = 2000000000L;
unsigned long long int largestIntegerInC = 18446744073709551615LL;
printf ("numDaysInYear = %d\n", numDaysInYear);
printf ("numStarsInUniverse = %ld\n", numStarsInUniverse);
printf ("largestIntegerInC = %llu\n", largestIntegerInC);
}
Note:
int main () { int numDaysInYear = 365; printf ("numDaysInYear = %d\n", numDaysInYear); if (numDaysInYear < 366) { long int numStarsInUniverse = 2000000000L; printf ("Thank your lucky %ld stars\n", numStarsInUniverse); } else { unsigned long long int numStarsInUniverse = 1844674407370955161LL; printf ("Thank your lucky %llu stars\n", numStarsInUniverse); } }
int main () { int i; for (i=0; i<10; i++) { // Allowed. printf ("i=%d\n", i); } for (int j=0; j<10; j++) { // Not allowed in C89. j needs to be declared at the top. printf ("j=%d\n", j); } }
int main () { int numDaysInYear = 365; // Allowed. printf ("numDaysInYear = %d\n", numDaysInYear); long int numStarsInUniverse = 2000000000L; // Not allowed. printf ("Number of stars = %ld stars\n", numStarsInUniverse); }
#include <stdio.h> // Declaration and assignment. int numDaysInYear = 365; int main () { // Declaration. long int numStarsInUniverse; printf ("numDaysInYear = %d\n", numDaysInYear); // Assignment. numStarsInUniverse = 2000000000L; printf ("numStarsInUniverse = %ld\n", numStarsInUniverse); }For variety, we have declared numDaysInYear as a global variable.
int main () { int numDaysInYear = 365; long numStarsInUniverse = 2000000000L; unsigned long long largestIntegerInC = 18446744073709551615LL; printf ("numDaysInYear = %d\n", numDaysInYear); printf ("numStarsInUniverse = %ld\n", numStarsInUniverse); printf ("largestIntegerInC = %llu\n", largestIntegerInC); }
Screen output:
printf (format-string [zero or more variables])
int main () { int numDaysInYear = 365; long int numStarsInUniverse = 2000000000L; unsigned long long int largestIntegerInC = 18446744073709551615LL; printf ("numDaysInYear = %d numStarsInUniverse = %ld largestIntegerInC = %llu\n", numDaysInYear, numStarsInUniverse, largestIntegerInC); }
int main () { int numDaysInYear = 365; long int numStarsInUniverse = 2000000000L; unsigned long long int largestIntegerInC = 18446744073709551615LL; // Up to 5 digits: printf ("numDaysInYear = %5d\n", numDaysInYear); // Up to 10 digits: printf ("numStarsInUniverse = %10ld\n", numStarsInUniverse); // Up to 20 digits: printf ("largestIntegerInC = %20llu\n", largestIntegerInC); }
#include <stdio.h> int main () { int numDaysInYear = 365; long int numStarsInUniverse = 2000000000L; unsigned long long int largestIntegerInC = 18446744073709551615LL; printf ("numDaysInYear = %d numStarsInUniverse = %ld largestIntegerInC = %llu\n", numDaysInYear, numStarsInUniverse, largestIntegerInC); }What happens when you mistakenly use %d for all the integers above?
Floating-point types:
Type | Typical storage size | Range | Print specifier | Approximate precision |
float | 4 bytes | 1.2 x 10-38 to 3.4 x 1038 | %f | 6 decimal places |
double | 8 bytes | 2.3 x 10-308 to 1.7 x 10308 | %lf | 15 decimal places |
long double | 10 bytes | 3.4 x 10-4932 to 1.1 x 104932 | %llf | 19 decimal places |
Consider this example:
(source file)
int main ()
{
// Constant with "F" appended:
float PI = 3.141F;
// Constant in exponent format:
double doublePI = 314.159265E-2;
// Long double constant:
long double ldoublePI = 3.14159265358979L;
// Output in exponent format:
printf ("float PI = %7.5e\n", PI);
// Output in decimal format with field width and number of significant digits:
printf ("double PI = %16.10lf\n", doublePI);
// Long double's need to be printed as double's
printf ("long double PI = %15.12lf\n", (double) ldoublePI);
}
Note:
float PI = 3.141F;
double doublePI = 314.159265E-2;
Character types:
Type | Typical storage size | Range | Print specifier |
char | 1 byte | -128 to 127 | %c |
unsigned char | 1 byte | 0 to 255 | none |
signed char | 1 byte | -128 to 127 | none |
Consider this example:
(source file)
int main ()
{
char letter = 'a';
unsigned char letter2 = 'b';
signed char letter3 = 'c';
printf ("letter = %c\n", letter);
printf ("letter2 = %c\n", letter2);
printf ("letter3 = %c\n", letter3);
}
Note:
Consider this example:
(source file)
int main ()
{
int i = 5;
long j = 6;
double d = 3.141;
j = i; // Works fine. Implicit cast from int to long.
d = i; // Works fine. Implicit cast from int to double
i = j; // May not compile.
i = d; // May not compile.
d = 3.141;
i = (int) j; // Compiles. Explicit cast from long to int.
i = (int) d; // Compiles. Explicit cast from double to int.
// Cast's can be used in any expression:
printf ("The int part of d=%lf is %d\n", d, (int) d);
}
Note:
i = (int) d;
short → int → unsigned int
→ long → unsigned long → long long
→ float → double → long double
An example with arithmetic operators
(source file)
An example with bitwise operators
(source file)
An example with boolean operators
(source file)
Boolean types:
int main ()
{
double x = 6, y = 5;
int i = 8, j = 5;
// Standard: plus, minus, multiple, divide
printf ("x+y=%lf\n", x+y); // Prints 11.0
printf ("x-y=%lf\n", x-y); // Prints 1.0
printf ("x*y=%lf\n", x*y); // Prints 30.0
printf ("x/y=%lf\n", x/y); // Prints 1.2
// Integer divide and remainder:
printf ("i/j=%d\n", i/j); // Prints 1
printf ("i mod j=%d\n", i%j); // Prints 3
// Post and pre-increment:
printf ("i++ = %d\n", i++); // Prints 8
printf ("++j = %d\n", ++j); // Prints 6
// Assignment shortcut example.
i += j;
printf ("i=%d\n", i); // Prints 15
}
int main ()
{
int a = 9;
int b = 4;
printf ("a&b = %d\n", a&b); // Bitwise AND: Prints 0
printf ("a|b = %d\n", a|b); // Bitwise OR: Prints 13
printf ("a^b = %d\n", a^b); // Bitwise EOR: Prints 13
printf ("~a = %d\n", ~a); // Complement: Prints -10
printf ("b << 1 = %d\n", (b << 1)); // Left shift by 1: Prints 8
printf ("b >> 2 = %d\n", (b >> 2)); // Right shift by 2: Prints 1
}
int main ()
{
double x = 5, y = 6, z = 6;
int result;
printf ("x < y = %d\n", (x < y)); // Prints 1 (true)
printf ("x <= y = %d\n", (x <= y)); // Prints 1
printf ("y > z = %d\n", (y > z)); // Prints 0 (false)
printf ("y >= z = %d\n", (y >= z)); // Prints 1
printf ("x == y = %d\n", (x == y)); // Prints 0
printf ("y == z = %d\n", (y == z)); // Prints 1
printf ("x != y = %d\n", (x != y)); // Prints 1
result = (x < y);
printf ("result=%d\n", result); // Prints 1
if (result == 1) { // Equality comparison.
printf ("x < y\n");
}
else {
printf ("x >= y\n");
}
// Prints "x < y"
}
Note:
int main ()
{
double x = 5, y = 6;
int result = (x < y);
if (result == 1) {
printf ("x < y\n");
}
else {
printf ("x >= y\n");
}
}
#define boolean int
#define true 1
#define false 0
int main ()
{
double x = 5, y = 6;
boolean result = (x < y);
if (result == true) {
printf ("x < y\n");
}
else {
printf ("x >= y\n");
}
}
#include <stdio.h>
#include <stdbool.h>
int main ()
{
double x = 5, y = 6;
bool result = (x < y);
if (result == true) {
printf ("x < y\n");
}
else {
printf ("x >= y\n");
}
}
#include <stdio.h>
#include <stdbool.h>
int main ()
{
double x = 5, y = 6;
_Bool result = (x < y);
if (result == true) {
printf ("x < y\n");
}
else {
printf ("x >= y\n");
}
}
There are two ways of defining constants in C:
#define PI 3.14159
int main ()
{
double radius = 5.0;
printf ("Area of Circle with radius %lf is %lf\n", radius, PI*radius*radius);
}
const double PI = 3.14159;
int main ()
{
double radius = 5.0;
printf ("Area of Circle with radius %lf is %lf\n", radius, PI*radius*radius);
}
The latter approach is more general, and can be applied to function
parameters as well:
const double PI = 3.14159;
// "const" declaration makes it illegal for a function to
// change the input parameter.
double computeArea (const double radius)
{
return PI * radius * radius;
}
int main ()
{
double radius = 5.0;
printf ("Area of Circle with radius %lf is %lf\n", radius, computeArea(radius) );
}
An overview of C's control flow statements via examples:
(source file)
int main ()
{
int i = 1;
// if-statement:
if (i == 0) {
printf ("i is zero\n");
}
// if-statement with compound expression:
if ( (i >= -1) && (i <= 1) ) {
printf ("-1 <= i <= 1\n");
}
// if-else combination
if (i == 1) {
printf ("one\n");
}
else if (i == 2) {
printf ("two\n");
}
else {
printf ("larger than two\n");
}
// Variation of if-else above:
if (i == 1) {
printf ("one\n");
}
else {
if (i == 2) {
printf ("two\n");
}
else {
printf ("larger than two\n");
}
}
// Equivalent switch statement:
switch (i) {
case 1: {
printf ("one\n");
break;
}
case 2: {
printf ("two\n");
break;
}
default: {
printf ("larger than two\n");
}
}
// for-loop example:
printf ("Numbers 0 through 9: \n");
for (i=0; i < 10; i++) {
printf (" %d\n", i);
}
// while-loop equivalent:
printf ("Numbers 0 through 9: \n");
i = 0;
while (i < 10) {
printf (" %d\n", i);
i++;
}
// do-while equivalent:
printf ("Numbers 0 through 9: \n");
i = 0;
do {
printf (" %d\n", i);
i++;
} while (i < 10);
// Example of using "break"
printf ("Numbers 0 through 9: \n");
i = 0;
while (1) {
if (i == 10) {
break;
}
printf (" %d\n", i);
i++;
}
printf ("Odd numbers less than 10:\n");
i = 0;
while (1) {
// If we've reached the limit, break out of the loop.
if (i == 10) {
break;
}
// If it's an even number, skip to next iteration of loop.
if (i % 2 == 0) {
i++;
continue;
}
// Print odd number.
printf (" %d\n", i);
i++;
}
}
Note:
for (int i=0; i < 10; i++) {
// ...
}
Versions prior to C99 do not. For compatibility with many textbooks,
we will declare variables at the top.