Press Release

My friend Garrett Weindorf wrote this press release for the Kindle book, I think it’s pretty good:

Big Al’s C: Standard C

It Just Makes Sense!

Save yourself the time and hassle of endlessly searching online for answers to your fundamental questions on the C programming language.

Whether you’re a student learning C for the first time, or a seasoned programmer just looking to brush up, Big Al’s C: Standard C is the go-to C language primer for the Amazon Kindle.

For a mere $2.99 – less than a gallon of gas or a latte at Starbucks – this easy to understand guide walks you through everything you need to know about the fundamentals of the C language. Other books offering the equivalent information cost ten times more.

Big Al’s C is newly revised and updated, and is custom-formatted for viewing on your Amazon Kindle.

Simply put, it just makes sense.

Available now for Kindle at:

http://www.amazon.com/Big-Als-Standard-ebook/dp/B00A4JGE0M

Symbolic Constants in C

The value of Pi is a constant, it never changes. The only question we really have with Pi is, “How precise do we want to be?” We need to insure a uniform amount of precision throughout the program, so that the value will not be changed by mistake. This means that we do not want the value of Pi to vary from function to function.

After all, the whole point of variables is that they are mutable. If we store Pi in a variable, there is nothing to insure that the value won’t be modified by accident.

A symbolic constant is a constant that is represented by a symbol in our program. Whenever we need the symbolic constant’s value in our program, we can its name just as we would use a variable’s name.

There are two ways to implement symbolic constants in C. Our first option here is to define Pi as a symbol that will be replaced in the program by a specified value during compilation. In this case, Pi wouldn’t be a variable at all, it would more like an alias or stand-in for the value it represents. We do this using what is know as a #define directive.

#include <stdio.h>

#define PI 3.14159

int main(void){
 
  double diameter = 5.5;
  double radius = diameter / 2.0;
 
  double circumference = 2.0*radius*PI;
 
  double area = PI*radius*radius;
 
  printf("The diameter of the circle is %.2f\n", diameter);
  printf("The radius of the circle is %.2f\n", radius);
  printf("The circumference of the circle is %.3f\n", circumference);
  printf("The area of the circle is %.3f\n", area);
 
  return 0;
 
 
}

Note that by convention identifiers that appear in a #define statement are written in capital letters.

All #define directives should be grouped together near the beginning of the file and before the main() function.

#include <stdio.h>

#define GRAMS_PER_POUND 454
#define METERS_PER_FOOT .3048

int main(void){
 
    int pounds1 = 115;
    int pounds2 = 175;
    
    int feet1 = 6;
    int feet2 = 300;
    
    printf("%d pounds = %d grams\n", pounds1, pounds1 * GRAMS_PER_POUND);
    printf("%d pounds = %d grams\n", pounds2, pounds2 * GRAMS_PER_POUND);
    
    printf("%d feet = %f meters\n", feet1, METERS_PER_FOOT * (double)feet1);
    printf("%d feet = %f meters\n", feet2, METERS_PER_FOOT * (double)feet2);
    
    return 0;
    
}

The second way to define a symbolic constant is with the const keyword. We can make the value of any variable immutable by prefixing the type name with the keyword const when we declare the variable. A value is initialized at the time of declaration and is then prohibited from being changed. Any code that attempts to change its value will be flagged as an error and the compilation will fail.

#include <stdio.h>


int main(void){
 
  const double Pi = 3.14159;
 
  double radius = 11.11;
  double circumference = radius * 2.0 * Pi;
  double area = radius * radius * Pi;
 
 
  printf("The radius of the circle is %f\n", radius);
  printf("The circumference of the circle is %f\n", circumference);
  printf("The area of the circle is %f\n", area);
 
  return 0;
 
}

Note that many functions in the standard library use const in their parameter declarations.

The header file <limits.h> defines symbolic constants that represent values for the limits of each integer data type.

#include <stdio.h>
#include <limits.h>


int main(void){
 
  printf("The char type stores values from %d to %d\n", CHAR_MIN, CHAR_MAX);
  printf("The int type stores values from %d to %d\n", INT_MIN, INT_MAX);
  printf("The unsigned int type stores values from 0 to %u\n", UINT_MAX);
  printf("The long long int type stores values form %lld to %lld\n", LLONG_MIN, LLONG_MAX);
 
 
  return 0;
 
}

 

Data Type Conversion in C

In an assignment statement if the type of the right side is different from the type of the left side the right side is converted into the type of that of the left. This process may be problematic when the type of the left side is smaller than the type of the right side.

#include <stdio.h>

int main(void){
 
  char ch;
  int i;
 
  i = 1984;
  ch = i;
 
 
  printf("%d\n", i);
  printf("%d\n", ch);
 
  return 0;
 
}

Also, when converting from a floating point number to an integer number the fractional part is lost.

#include <stdio.h>

int main(void){

 int i;
 double f;
 
 f = 394.4075;
 i = f;
 
 printf("%f \t %d\n", f, i);
 
 return 0;
 
}

If we perform a binary operation on two different data types, the compiler will convert the more restrictive data type to the less restrictive data type. The simplest conversion is the integer promotion. For instance, in a mathematical operation involving a char and an int, the char is automatically converted to the larger, less restrictive int data type. Likewise, if one operand is of type int and the other is of type unsigned int, the first operand is promoted to the unsigned type.

#include <stdio.h>

int main(void){
 
 int a = 6809;
 char b = 73;
 int sum;

 unsigned c = 26007800;
 
 unsigned usum = c + a;
 
 sum = a + b;
 
 printf("%d + %d = %d\n", a, b, sum);
 printf("%d + %u = %u\n", a, c, usum);
 
 return 0;
 
 
}

Often it is necessary to temporarily change the type of a variable so that it can be used differently. This is known as performing a type cast. A type cast in no way permanently changes the variable’s type or the value it stores; a type cast causes only a temporary type change.

 The cast operator is what is known as a unary prefix operator, it consists of a type name inside parentheses placed in front of the variable name.

#include <stdio.h>


int main(void){

  int d = 1999;
  int e = -1492;
 
  printf("d = %d\n", d);
  printf("d = %d (whoops)\n", (char)d);
  printf("d = %f\n", (float)d);
  printf("e = %d\n", e);
  printf("e = %f\n", (float)e);
  printf("e = %u (whoops)\n", (unsigned)e);
 
 
 return 0;
 
}

The value of any variable can be cast to any type, but the results may not always be desirable.

Type casts are very useful when working with functions that require arguments of a different data type than that of the variable we wish to use. For instance, the sqrt() library function requires a single argument of type double, and returns a double value. We must convert any argument we send to the sqrt() function to the double type.

#include <stdio.h>
#include <math.h>

int main(void){
    
  int i = 7800;
 
  printf("square root of %d = %f\n", i, sqrt((double)i));
 
  i = 121;
 
  printf("square root of %d = %f\n", i, sqrt((double)i));
 
  return 0;
 
}

More on Format Specifiers

We can specify the number of decimal places we want to display in the format specifier. To obtain the output to three decimal places, we would write the format specifier as %.3f. To get ten places, we would write %.10f.

#include <stdio.h>

int main(void){
 
    double num = 2.0 / 7.0;
    
    
    /*
     * specify the number of
     * decimal places
     * in the format specifier
     */
    printf("%.3f\n", num);
    printf("%f\n", num);
    printf("%.9f\n", num);
    printf("%.12f\n", num);
    
    
 
    return 0;
    
}

The field width for the output, which is the total number of characters used to display the value, is determined automatically by the printf() function. However, it is possible to determine the field width ourselves; this is useful is we want to output columns of data so that they line up. To specify a width value, place an integer before the format character.

 #include <stdio.h>

int main(void){
 
 
 
  unsigned int a = 8675309;
  int b = 73;
  double c = 27.408;
 
  printf("a = %7u\n", a);
  printf("b = %7d\n", b);
  printf("c = %7.3f\n", c);
 
  return 0;
 
}

When we specify a field width, the value will by default be right-aligned. We can left-align the field by putting a minus sign following the %.

#include <stdio.h>


int main(void){
 
  long long int a = 3135920017035;
  double b = 1138.1337;
  long double c = 3.141592653;
  char d = 112;
 
  printf("a = %-20lld", a);
  printf("b = %-20.4f\n", b);
  printf("c = %-20.9Lf", c);
  printf("d = %-20c\n", d);
  return 0;
 
}

 

Conversion Specifications with the printf() Function

A conversion specification is represented by a two character string that consists of the percent sign followed by a conversion character. The most common conversion characters are c, d, u, f, and s.

The program below uses the %c conversion code to print out single characters.

#include <stdio.h>


int main(void){
 
  printf("My first initial is on the next line:\n");
  printf("%c\n", 'A');
  printf("My second initial is on the next line:\n");
  printf("%c\n", 'B');
  printf("My third initial is on the next line:\n");
  printf("%c\n", 'J');
 
  return 0;

}

Between the % that starts a conversion specification and the conversion character that ends it, we may place an integer. For whole numbers, this specifies the minimum number of spaces the the integer should take up. With floating point numbers, we can place a period followed by a nonnegative integer to specify the number of digits to the right of the decimal point to be displayed.

 #include <stdio.h>


int main(void){
 
  /*
   * use a decimal-controlling modfier
   */
  printf("Today's high was %.1f degrees Celsius\n", 33.2);
  printf("$%.2f\n", 1.05);
 
  /*
   * use a width modifier
   */
  printf("%5d\n", 73);
  printf("%5d\n", 1138);
  printf("%5d\n", 451);
 
  /*
   * use both
   */
  printf("PRICES:\n\n");
  printf("$%7.2f\n", 19.19);
  printf("$%7.2f\n", 1.05);
  printf("$%7.2f\n", 3435.42);
  printf("$%7.2f\n", 2.5);
 
  return 0;
 
}

Using decimal-controlling modifiers with floating point output is quite common, as we rarely want the six decimal places that C produces without modifiers.

Adding a plus flag forces numbers to print with a leading sign.

#include <stdio.h>


int main(void){
 
  printf("%+7.2f\n", 33.0);
  printf("%+7.2f\n", -14.92);
  printf("%+7.2f\n", -7.77);
  printf("%+7.2f\n", 19.99);
  printf("%+7.2f\n", 234.5);
 
  return 0;
 
}

It is also possible to print an integer in hexadecimal and octal format.

#include <stdio.h>


int main(void){
 
  int a = 15;
  int b = 20;
  int c = 25;
  int d = 30;
  int e = 35;
 
  printf("The hex equivalent of %d is %x\n", a, a);
  printf("The hex equivalent of %d is %x\n", b, b);
  printf("The hex equivalent of %d is %x\n", d, d);
 
  printf("The octal equivalent of %d is %o\n", c, c);
  printf("The octal equivalent of %d is %o\n", e, e);
 
  return 0;
 
}

The C language contains a number of escape sequence characters in addition to the newline character, \n, that we have been using so far. Any time we insert an escape sequence within a printf() format string, the C program performs the action described by the escape sequence instead of printing it.

#include <stdio.h>


int main(void){
 
  printf("Ring a bell: \a \n");
  printf("Tabs \t are \t great.\n");
  printf("\"Illegitimi non carborundum\"\n");
 
  return 0;
 
}

Preprocessor Directives

A preprocessor directive is run before the rest of the program is compiled. Lines that begin with a pound sign are preprocessor directives. In this lesson we will look at two of the most common preprocessor directives, #include and #define.

The #include directive tells the preprocessor to read in another file and include it in our program. A file name must always follow the #include directive. This file is called the header file. The header file name must be placed between angled brackets or quotation marks. Header files all end with an .h extension.

All header files should be included before the main() function.

 #include <stdio.h>
/*
 * all the lines from
 * the stdio.h header file
 * will be inserted here
 */

int main(void){

 /*
  *call a function 
  *defined in the stdio.h
  *header file
  */ 

 printf("This statement made possible by the stdio.h header file.\n");

 return 0; 

}

Note that preprocessor directives never end with semicolons because they’re not true C commands. A preprocessor directive is an instruction to the C compiler itself.

The header file we have been using is the stdio.h file. Its file name is an abbreviation for standard input-output header file. It is used whenever we want to get input or print output.

As an example, let’s work a little with another header file, math.h. This file includes a function for getting the value of a number raised to the power of another number.

#include <stdio.h>
#include <math.h>

int main(void){

  int a = 42, b = 3;

  double x = 7.5, y = 2.0;

  /*
   * return the value of 
   * x to the power of y
   */
  printf("7.5^2 = %f\n", pow(x, y));

  return 0; 

}

Note that the pow() function returns a floating-point value.

Let’s look at one more function from the math.h header file. The sqrt() function returns the square root of the argument passed to it. Don’t pass the sqrt() function a negative number!

#include <stdio.h>
#include <math.h>

int main(void){

  int a = 16;
  double b = 16.0;

  printf("square root of 2 = %f\n", sqrt(2.0));
  printf("square root of 2 = %f\n", sqrt(2));

  printf("square root of %d = %f\n", a, sqrt(a));
  printf("square root of %f = %f\n", b, sqrt(b));

  return 0;

}

The #define preprocessor directive is used to establish the symbolic constants that are used in a program. If we were to take a look at the stdio.h header file’s source code, we would find a number of #define directives there.

Symbolic constants are used so that we can easily change these values in the future, and have them be implemented throughout the program. This is because a #define directive results in a global substitution of the constants throughout the program in a process referred to as macro substitution. Simply put, macro substitution is the preprocessor substituting one thing for another throughout the entire program.

#include <stdio.h>

#define QUOTE "The map is not the territory."

int main(void){

  printf("Here is a quote: %s\n", QUOTE); 

  return 0;

}

Note that symbolic constants are almost always written in all caps.

When a preprocessor directive is identified, the entire line is treated as a preprocessor line. For this reason, we should place each preprocessor directive on its own separate line.

One a symbolic constant has been defined, it can be used to help define another symbolic constant.

#include <stdio.h>

#define SMALL 6
#define MEDIUM SMALL+2
#define LARGE MEDIUM+2

int main(void){

  printf("Size small = %d\n", SMALL);
  printf("Size medium = %d\n", MEDIUM);
  printf("Size large = %d\n", LARGE);

  return 0;

}

Type Modifiers and Format Specifiers

An unsigned type name is the signed type prefixed with the keyword unsigned. We use unsigned types when using integer values that cannot be negative, like a person’s age or a database record ID number. Because an unsigned type does not have to represent negative numbers, it’s range of positive numbers is twice as large as its corresponding signed type. This is because signed numbers use one bit as a sign bit.

#include <stdio.h>


int main(void){
  
  int x = 90210;
  unsigned int y = 8675309U;
 
  
  /*
   * use %u to display
   * unsigned int
   */
  printf("x = %d\n", x);
  printf("y = %u\n", y);
  
  return 0;
}

To display the value of an unsigned int, use the conversion characters %u. For long integers, add an l modifier prefix to the conversion character, for type long long use two letter ls.

When specifying integer constants as long, we must append an uppercase or lowercase letter L to the numeric value. It’s evident that using an uppercase L is more readable that its lowercase counterpart, because it can’t be confused with the number 1. When specifying integer constants as unsigned, we must append the letter U to the numeric value.

#include <stdio.h>

int main(void){
  
  long int a = 57600000L;
  long long int b = 149600000LL;
  
  printf("long int a = %ld\n", a);
  
  printf("long long int b = %lld\n", b);
  
  
 return 0; 
}

The types unsigned and unsigned int, as well as unsigned long and unsigned long int, are the same; however, it is generally considered best practice to use the more descriptive data type and modifier combination.

#include <stdio.h>

int main(void){
 
  unsigned long long y = 2600ULL; 
  

  printf("y = %llu\n", y);
  
  y = y * y;
  
  printf("y^2 = %llu\n", y);
  
  y = 2600ULL;
  
  y = y * y * y;
  
  printf ("y^3 = %llu\n", y);
  
  y = 2600ULL;
  
  y = y * y * y * y;
  
  printf ("y^3 = %llu\n", y);
  
  return 0;
  
}

Values of type float are known as single precision floating-point numbers; values of type double are known as double precision floating-point numbers. The long double type provides an even greater range and precision than double.

#include <stdio.h>


int main(void){
 
  float piOne = 3.1459f;
  double piTwo = 3.14159265359;
  long double piThree = 3.1415926535897932L;
  
  
  printf("Pi = %f\n", piOne);
  printf("Pi = %f\n", piTwo);
  printf("pi =% Lf\n", piThree);
  
  printf("Wait.... that's:\n");
  
    printf("Pi = %.11f\n", piTwo);
  printf("pi =%.16Lf\n", piThree);
  
  
  return 0;
  
}

We can specify the number of fractional digits to display by including a number after the decimal in the format specifier. By default, the format specifier %f displays six fractional digits.