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.cThis 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:
./hello_world
- You should see the output:
Hello, World!
Congratulations! You’ve successfully created and executed a “Hello, World!” program in C!
3. GCC Flags
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
- Compile-time Errors/Warnings (syntax errors, etc. detectable during compile-time)
- Runtime Errors (Exceptions - Program crash)
- 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 theredability of the code and avoid being into some nasty logical issuesin 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 */
{ int num1, num2; scanf("%d %d", &num1, &num2);
if (num2 != 0) printf("Division: %f", num1 / num2);
return 0;}
/* This program will successfully compile but will not 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. */
int main(){ int num1, num2; scanf("%d %d", &num1, &num2); printf("Addition: %d", num1 + num2); /* FIXED */ return 0;}
5. Essential Terminology
5.1 Variable Related
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 Function Related
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.