 The C language was created around 1972 by Ken Thompson and Dennis Richie, who at the time were working at Bell Labs. More accurately, Richie created C alone, but Thompson created C's direct predecessor, the B language. In the same time frame, Thompson and Richie together created the original UNIX operating system, the bulk of which was written in C. Aside from being very widely used, C has also been extremely influential in other languages. The C++ and Objective C languages, for example, created in the 1980s extended C with object-oriented features. Because of C's success, the American National Standards Institute, ANSI, codified a standard for the C language in 1989 called C89. This was followed by revised standards in 1990, 1999, and 2011. All the popular C compilers support at least C89, but full support for later revisions is still spotty. The most popular C compilers in use today are the GNU compiler, Apple's Clang compiler, and Microsoft's Visual Studio compiler. Unlike the GNU and Clang compilers, the Microsoft compiler is not open source, but it is free for download. The C language is imperative and procedural, so unlike a functional language, C makes no effort to constrain the use of mutable state, and unlike an object-oriented language, C provides no explicit facilities for encapsulation, inheritance, or polymorphism. C is also statically typed, meaning that, unlike in a dynamic language, we must declare in our C code the types of our variables, function parameters, function return values, and user-defined types. C is also weakly typed in the sense that it is not memory-safe. This lack of memory-safety is the cost the C programmer pays for control over memory. Unlike in, say, JavaScript, the C programmer can directly read and write individual bytes of memory, and this allows the programmer to potentially make more efficient use of memory, but at the cost of having to manually allocate and deallocate memory. There is no garbage collector in C, so when we create an object, we must keep track of the memory it occupies so that that memory may be reused when we're done with the object. This burden not only complicates code, but also leads to a whole swath of potential bugs. When a C compiler generates machine code, it has a lot of freedom in how it might optimize the code. However, for the sake of interoperation with natively compiled code from other languages such as assembly, the C language establishes a so-called calling convention, a convention for how functions are invoked in terms of machine instructions. The details, of course, differ for different compilation targets, e.g. the x86 processor calling convention differs from the ARM processor calling convention, but the idea is that within a particular platform, C code can be linked with any non-C code that abides by the same convention. Understand, though, that for languages which do not compile to native machine code like, say, JavaScript, interop with C code requires much more complicated solutions. Because C compiles to native machine code, gives the programmer control over memory, and can interop quite easily with assembly code, C is very well suited to what we sometimes call systems programming, which refers to writing the low-level code of operating systems and device drivers. The Linux kernel, for example, is written mostly in C. These facets of C also facilitate high-performance code, making C very suitable for performance-sensitive purposes, such as games and media playback. In fact, most high-performance games today are written in C++, which shares these facets of C. Instead of having just one number type, as we do in JavaScript, the C language has several number types, each representing numbers with a different number of bits, and therefore supporting a different range of values. Four of the most commonly used number types are char, int, float, and double. A char, pronounced by some as car as in character, is an integer stored as a single byte. A char is so named because it is most commonly used to store an ASCII character. By default, a char is signed, meaning it represents both negative and positive values using two's complement form, so a signed char can represent the values from negative 128 to positive 127. While we can perform arithmetic on chars, our first choice for doing arithmetic is to use int. An int, short for integer, unlike a char, is stored as multiple bytes. How many bytes exactly depends upon the compiler and the target of compilation. When compiling for a 32-bit processor, an int is most commonly 4 bytes, but when compiling for a 64-bit processor, an int may instead be 8 bytes. In general, the int size corresponds to the so-called word size of the target platform, a size of bytes which is most processor efficient to use on that platform. Understand that C has no exception mechanism, and a primary goal of the language is high performance, so the basic math operations in C, such as addition and subtraction, will trigger overflow silently. For example, when adding two int values together, if the result exceeds the range of an int, we get back a value with the most significant bits simply truncated to make the value fit in range of an int. Such results are of course not mathematically accurate, but as a C programmer, it is your responsibility to work around such inaccuracies. It turns out that most programming tasks dealing with integers only need full accuracy within a limited range of values that fit comfortably in the smallest size int. If however you ever do need full precision math, you can create your own special math functions and data types for that purpose, or more likely simply use an already existing library that does this for you. As for floats and doubles, both are floating point number types, with the only difference being that in the terminology of the IEEE floating point standard, a float is single precision while a double is double precision. Single precision has 23 bits of significant, 8 bits of exponent, and 1 sign bit, totaling 32 bits, while double precision has 52 bits of significant, 11 bits of exponent, and 1 sign bit, totaling 64 bits. At least, these are the sizes prescribed by the C99 standard. Among compilers that don't support C99, the precise sizes of floats and doubles can vary. Because C is a static language, we must declare the type of any variable. When creating a variable, we specify the type before the name. Here for example, we have two statements declaring variables. The first declares a variable of type int named monkey. The second declares a variable of type float named zebra. Henceforth, when we assign to these variables, we can only assign ints to monkey and floats to zebra. Notice that like in JavaScript, every statement in C ends with a semicolon. Also because C is a static language, we must declare the types of a function's parameters and the type returned by the function. The general syntax is first we have the return type, followed by the name, followed by a comma-separated list of the parameters in parens, followed by the body of statements in curly braces. We can insert as much white space between these elements as we like. For instance, we could put spaces between the name and the parens. The only white space that is absolutely required here is between the return type and the name, because of course without any white space between them, the compiler could not distinguish the two. Here are two simple C functions. The first function named square takes a single int as argument and returns an int. Its body contains one statement, a return statement returning the value of n times n. The second function named cube also takes a single int as argument and returns an int. Its body contains one statement, a return statement returning the value of n past a square, multiplied by n. Again, because C is statically typed, compilation will fail if either of these functions is called with the wrong number or types of argument. So we cannot say invoke cube with a float value anywhere in this code. Compilation will also fail if a return statement's expression doesn't match the function's declared return type. So say it would not be okay if the expression of the return statement in square were to evaluate into a double. Here we have another function foo, which takes three arguments, an int and two floats, and returns a char. Notice that the parameters are separated by commas. To get type conversions of a value, we have the casting operation. A cast is written as the target type in parens preceding an expression. The cast returns the value of the expression converted into the specific type. The caveat is that some values which we can represent in one data type may of course not be representable in another. So some type conversions can only produce approximate or truncated values. For example, when converting from a float to an int, any fractional component the float might have gets discarded and the float value may get truncated to fit in the range of an int if it's too large. In other cases though, the conversion may preserve the precise value. Here for example we have an int variable x with a value 35. Assuming the function bar here expects a char argument, we can't pass an int as argument. We can however cast the int value of x to a char, and because the value 35 fits within the range of a char, the precise value survives the conversion in this case. If though the value of x were say 460, the cast to char would require truncating the value to fit in char range. Unlike JavaScript and most other modern languages, C has no boolean type. Instead, C's condition expressions and boolean operations treat the number 0 as false and all other number values as true. So for example, the not operator, the exclamation mark, expects a numeric operand. If the operand is 0 it returns 1, but if the operand is anything other than 0 it returns 0. So for example, the not operator used on the numeric values 1, 0.6, 3, or negative 6.5, they all return 0, but the not operator used on the numeric values 0 or 0.0 returns 1. Like in JavaScript, each function in C is its own local scope. Unlike JavaScript, functions in C cannot be nested within other functions, but constructs like if and while constitute their own local scopes. So here in this function, Roger, the variable z declared within the body of the if, only exists in the if's body and not the rest of the function. So these uses of z and the rest of the function trigger compilation errors. To fix this problem, we simply need to move the declaration of z to the outer scope of the function itself, and now it is visible throughout the whole function. You may have noticed that the return type of Roger is void. The void type designates nothing, so this function doesn't return a value, which is why you see no return statements. Here's the hello world program in C. The first line beginning with the number sign is an include directive, which we'll explain later, but in short, this include gives us access to the standard library function printf, which prints string output to the console. The f in printf stands for formatted, the significance of which we'll talk about later. Anyway, our hello world program consists of just one function, a function main that takes no arguments and returns an int. The linker that converts our code into an executable needs to pick one function to invoke at start of execution, and by default, that function is the one called main. So this main function will be implicitly called when the program starts. Inside main, we invoke printf for the string hello world, and then return zero. The reason our main function returns a value at all is that Unix systems expect programs to return a so-called exit code upon completion. What this error code means is entirely up to our program's choosing, but by convention, the exit code zero generally indicates normal successful completion. Values other than zero are generally used to represent some kind of fail state. When our program completes, the exit code is received by the other program, which runs our program, and what that other program does with the information is entirely up to that other program's choosing.