Skip to content

1.1 C Basics

1. C89 vs C99 Standards

C89 and C99 refer to different standards of the C programming language, released by the International Organization for Standardization (ISO). Here are the key differences between them:

1. Release Year:

  • C89 (also known as ANSI C or ISO C90): Released in 1989.
  • C99: Released in 1999.

2. Feature Set:

  • C89: It introduced the basic features of the C language, including functions, loops, conditionals, data types, and standard libraries like stdio.h and stdlib.h.
  • C99: It introduced several new features and improvements over C89, such as: — New data types like long long int and bool. — Inline functions. — Variable-length arrays. — Support for one-line comments beginning with //. — New standard library functions like stdint.h, tgmath.h, and stdbool.h. — More flexible declarations, including mixing variable declarations with statements.

3. Complex Numbers:

  • C99 introduced native support for complex numbers and associated mathematical functions through the complex.h header.

4. Designated Initializers:

  • C99 introduced designated initializers, allowing elements of structures and arrays to be initialized by specifying their indices or field names.

5. Flexible Array Members:

  • C99 allows the last member of a structure to be an array of unspecified size, known as a flexible array member. Variable Declarations:

  • C99 allows variable declarations to appear anywhere in a block, whereas C89 requires them to appear only at the beginning of a block.

6. Standardization of Certain Previously Common Extensions:

  • C99 standardized certain features that were previously common extensions in various C compilers, such as inline functions and variable-length arrays.

7. Compatibility:

  • While C99 introduced significant improvements, it also maintained a high level of compatibility with C89. Most valid C89 code should also be valid under C99, though some older compilers may not fully support C99 features.

C99 introduced several new features and improvements over C89, making it a more versatile and expressive language. However, due to the existing codebase and compatibility concerns, adoption of C99 features might vary depending on the specific project and toolchain requirements.

2. Hello World in C

1. Create a New Source File:

  • Open a text editor or an integrated development environment (IDE) like Visual Studio Code, Atom, Sublime Text, or any other of your choice.
  • Create a new file and save it with a .c extension. For example, you could name it hello_world.c
    #include <stdio>
    int main() {
    printf("Hello, World!\n");
    return 0;
    }

2. In the newly created file, write the above C code:

  • This code includes the standard input-output header file <stdio.h> which provides the printf function for printing text to the console.

  • The main() function is the entry point of the program. It’s where the execution of the program begins.

  • Inside main(), printf("Hello, World!\n"); prints “Hello, World!” to the console followed by a newline character \n.

  • return 0; indicates successful completion of the program.

3. Compile the Program:

  • Open a terminal or command prompt.

  • Navigate to the directory where your .c file is located.

  • Compile the program using a C compiler such as gcc (GNU Compiler Collection).

    Terminal window
    gcc -o hello_world hello_world.c

    This command tells the compiler (gcc) to compile the source file hello_world.c and generate an executable file named hello_world.

4. Run the Program:

  • After successful compilation, you’ll have an executable file named hello_world (or whatever name you specified with the -o option).

  • Execute the program by typing its name in the terminal and pressing Enter:

Terminal window
./hello_world
  • You should see the output:
Terminal window
Hello, World!

Congratulations! You’ve successfully created and executed a “Hello, World!” program in C!

3. GCC Flags

Terminal window
gcc -Wall -ansi -pedantic -Werror
  • -Wall = show all warnings
  • -ansi -pedantic = ensures the code is C89 compliant
  • -Werror = treat all warnings as errors!
  • -Werror flag is optional and you may avoid using it since you are expected to know the difference between hard line errors and warnings. If you use -Werror flag, you will not see any warnings since all warnings will be treated as errors. Btw, make sure you fix all your warnings, errors in the code during assignment submissions.

4. Type of Errors

  1. Compile-time Errors/Warnings (syntax errors, etc. detectable during compile-time)
  2. Runtime Errors (Exceptions - Program crash)
  3. Runtime Errors (Logical bugs due to wrong logic)

4.1 Compile-time Errors/Warnings

During compilation you may encounter:

Errors: Remember errors are hardline bugs in your code (i.e. syntax errors) and you will not be able to successfully compile the code with errors. The executable file (output file) will not be created.

Warnings: These are soft errors but not bugs. They have the potential to introduce runtime issues (runtime exceptions and logical bugs). Also, fixing the warnings will help you to improve the readability and the maintainability of the code. i.e.

int main()
{
int num = 1;
/* WARNING: unused variable */
return 0;
}
/* It is always the best to remove unused variables to improve the
redability of the code and avoid being into some nasty logical issues
in the code */

4.2 Runtime Errors (Exceptions) - Program Crash

These are the errors you will encounter during the runtime of the program. You will be able to compile the code successfully, but during the runtime of the program due to not handling some specific condition, you may end up with a program crash! (crash due to an exception). These bugs are harder to detect compared to the compile-time errors since the compiler will not help you to spot them. But fixing some warnings may help you to mitigate some of these nasty runtime issues. gdb debugger can be used to debug the run time errors most of the time. We strongly recommend you to get your hands on gdb debugger from week 3 onwards when writing code. It is taught in detail in Week 07, but you may refer to the following link for quick tips.

Divide by zero is a perfect example of a runtime error. Later, with pointers introduced in week 03, you will encounter a lot of bugs in this category.

int main()
{
int num1, num2;
scanf("%d %d", &num1, &num2);
printf("Division: %f", num1 / num2);
return 0;
}
/* This program will successfully compile but will fail in runtime */

4.3 Runtime Errors (Logical Bugs) - Unexpected behaviours

These are the bugs due to your logic being wrong. No compilation errors, no runtime crashes (hopefully), but your program does not provide the expected output. Hence, your program will show unexpected behaviour where you expect something else. These are worst nightmare grade bugs and there is no way to detect them unless you review the logic of the code from A-Z. gdb debugger can be used to some extent to figure out where the logical bug is, but depending on your experience in coding, it will take few minutes to few hours and few days to troubleshoot the logical bug. The more you code, the more you gain in coding experience so keep it up!

int main()
{
int num1, num2;
scanf("%d %d", &num1, &num2);
printf("Addition: %d", num1 - num2);
return 0;
}
/* This program will successfully compile, no runtime-crashes,
but logically wrong! */
/* Addition does not add two number but taking the difference.
Therefore, you need to fix the logic of the code. */

5. Essential Terminology

5.1.1 Variable Declaration

A variable declaration specifies the type of a variable and its name, but it does not allocate storage or assign a value. Declarations tell the compiler that the variable exists and will be defined later.

Example:

extern int count;

Here, count is declared as an integer, but memory for it is not allocated. It is defined elsewhere in the program.

5.1.2 Variable Definitions

A variable definition allocates memory for a variable and optionally assigns an initial value. Definitions happen only once for each variable.

Example:

int count;

Here, count is defined as an integer, and memory is allocated for it. It does not have an initial value (defaults to 0 if global).

5.1.3 Variable Initializations

Variable initialization assigns an initial value to a variable at the time of its definition.

Example:

int count = 5;

Here, count is defined and initialized with the value 5 in a single statement.

5.1.4 Variable Assignments

Variable assignment refers to giving a value to an already declared variable after its definition.

Example:

count = 10;

Here, the value of count is changed to 10 after it has been defined.

5.2.1 Function Declaration

A function declaration specifies the function’s return type, name, and parameters without providing the function’s body. It is also called a function prototype, telling the compiler about the function’s existence.

Example:

int add(int a, int b);

Here, the function add is declared with two integer parameters, a and b, and it returns an integer. The body of the function is defined elsewhere.

5.2.2 Function Definitions

A function definition includes the function’s full body, specifying how it performs its task. It allocates memory for the function and includes the logic within the function body.

Example:

int add(int a, int b) {
return a + b;
}

Here, add is defined, and its logic adds the two parameters a and b, returning the result.

5.2.3 Function Initializations

There is no concept of function initialization in C. Functions do not require initialization like variables. Instead, they are declared and defined, and they can be invoked or called when needed.

5.2.4 Function Assignments

C does not support direct function assignments (like assigning a function to another function). However, function pointers can be used to store the address of a function and call it through the pointer.

Example:

int (*funcPtr)(int, int) = add;
int result = funcPtr(2, 3); // Calls the add function via funcPtr

Here, funcPtr is a function pointer that holds the address of the add function. The function is called using this pointer.