C_Notes-1
C_Notes-1
Why Use C?
1. High-level Language so programmer doesn't have to worry about machine code.
2. It's machine independent. (Different machine doesn't cause any error to translate "written code" into "machine code")
3. It's a well structured and readable to human.
Importance of C :
1. Has the capabilities of assembly language with the features of high level language.
2. Highly Portable (machine independent)
3. Well suited for structured programming (Because of it's various functions and procedures)
4. Has the ability to extend itself.
Why does we call C a Structured Programming Language?
C is a structured programming language as it breaks down a complex problem into smaller parts called functions or procedures. Each
function has a specific role, and together they make up the program that addresses the overall problem.
Comparison about the Machine code vs Assembly language vs Any High level language (C, C++ , Java etc.). As we can see, High
level language is more human friendly.
What is a Compiler ?
In short, compiler is just a translator for us to make our human readable code into machine codes (binary 0s and 1s)
Lifetime of a Program
Below figure demonstrates how our how a code is executed in our machine.
1. Header Files
2. Library functions
3. main() function
Header files
C main() function:
C Library Functions:
Pre-defined functions: Simplify coding by providing common operations like input/output ( printf , scanf ), character handling
( getchar , putchar ), and more.
HelloWorld.c
#include <stdio.h> //Header File
int main() //main() function
{ // start of a block
printf("Hello World"); //program statements
return 0; //return value
} // end of a block
1. #include <stdio.h> : This is a header file. It's a pre-processor directive which basically means that, it imports a file named
stdio.h which has a function written named printf() , scanf() , getchar() , putchar() etc. We can use this inside our
program.
2. int main() is our a key function that MUST be present inside a C program. This is the very first function that is called when a
program is run. Keep in mind that , there's only ONE main() in a program.
#include <stdio.h>
int another_function()
{
printf("Hello World");
return 0;
}
int main()
printf("Hello World");
return 0;
}
For the sake of understanding, a another_function() is added here. But the C program will never call this function on it's own. Because
it's user defined function . We added it on our own. It's not a requirement. (More about functions later...)
3. int main() has another fundamental property that must be added. It's the int before main() . This int basically indicates what the
function will return. Will it be a 1 or 0 ? That's why we add a return 0; meaning, we successfully executed the program.
4. printf() is a function that prints anything that's passed inside () .
5. return 0 returns a zero denoting it's has run successfully.
Preprocessor directives
Before a C program is compiled, it is first edited by a preprocessor. Commands
intended for the preprocessor are called directives.
This directive states that the information in <stdio.h> is to be “ included ” into
the program before it is compiled.
Feature Description
Macro substitution ( #define ) Enables code reusability and customization by replacing macro names with their corresponding
code.
File inclusion ( #include ) Incorporates header files containing function declarations and other definitions, promoting
modularity and code sharing.
Conditional compilation Allows selective compilation of code based on conditions like compiler type or operating system,
( #ifdef, #else ) facilitating platform-specific code.
More on it later .
Our code will go under through some preprocessing which will filter a lot of information, such as those { } brackets .
Then it will start compiling the Pre-processed file into Machine Code. It will produce an object file. This object file is not ready for
execution however. Meaning, we cannot run it yet!
A linker will come in and add some necessary codes (e.g. printf ) to it which will help our code and lastly is finishes the job by creating
an executable file ( .exe ) for us to run.
The compiler does it ALL .
--file structure
script.c // source code
script.exe // executable file
C - Token
Let's know a bit about what actually token is. In short - these are smallest individual element of the C programming language that is
meaningful to the compiler. These are:
1. Keyword
2. Identifier
3. Constant
4. String literal
5. Special Symbol
6. Operator
Keyword
These are the basic building blocks of program statements. It's system defined. Meaning, the compiler has explicitly defined and assigned
a action for the word.
keywords
auto break case char const continue _Imaginary
default do double else enum extern
float for goto if inline int
long register restrict return short signed
sizeof static struct switch typedef union
unsigned void volatile while _Bool _Complex
Notice there are int , float , if , else , char etc. These are keywords we already know more or less. We cannot just go ahead and
name a int variable int or float . It will throw an error.
Identifiers
As we’re writing a program, we’ll have to choose names for variables, functions,
macros, and other entities. These names are called identifiers.
These are user-defined. Meaning we have to implement these. Unlike Keywords, which are defined or implemented by the compiler. We
decide what the identifier will do.
This will essentially help us to identify the word we wrote (identifier) and what it does. So we can use it accordingly.
Yes, printf() is also an identifier. It's not us who created it but at it's root, it's created by someone and implemented in the C library
functions. We're just reusing it.
Constants
By putting the word const before any type of variable definition or initialization, will result in the variable being a constant variable.
Once's a variable is declared constant, we cannot just simply change it within anywhere in the code.
int a = 5;
const int b = 6;
a = 7 //acceptable
b = 5 //error
It's also important to understand that, the data-types int , float , char are also constant data types. You've already seen the numbers
and the size they represent in a memory.
Backslash character constants, also known as escape sequences, are a special way to represent non-printable characters or characters
with special meanings in C strings. They use a backslash \ followed by one or more additional characters to define the desired output.
Escape sequences are often used within printf statements to control the formatting and output of strings.
Using backslash character constants allows you to include characters that would otherwise be interpreted specially by the compiler.
printf("HELLO WORLD\nHOW ARE YOU?");
HELLO WORLD
HOW ARE YOU?
Notice the \n usage here. It's basically adding a new line. If it was just simply print it out.
String Literal:
A string literal in C is a sequence of characters enclosed within double quotation marks ( " ). It represents a constant array of characters.
Here, "Hello, World!" is a string literal assigned to the character array greeting .
Special Symbols:
Special symbols in C include characters that are not letters or digits and have a specific meaning in the language. Some common special
symbols include:
int main() {
// Curly braces define the scope of the main function
int x = 5; // Semicolon terminates the statement
printf("The value of x is %d\n", x); // Parentheses used for function call
return 0;
}
Operators:
Operators in C are symbols that represent computations or operations on variables or values.
Common types of operators in C include:
Arithmetic Operators ( +, -, *, /, % )
Relational Operators ( ==, !=, <, >, <=, >= )
Logical Operators ( &&, ||, ! )
Assignment Operators ( =, +=, -=, *=, /=, %= )
Bitwise Operators ( &, |, ^, ~, <<, >> )
Increment/Decrement Operators ( ++, -- )
int a = 10, b = 5;
int sum = a + b; // Addition operator
int difference = a - b; // Subtraction operator
int product = a * b; // Multiplication operator
int quotient = a / b; // Division operator
int remainder = a % b; // Modulus operator
We will talk more about Special symbols and Operators on a separate section.
The printf() function is used to print formatted output to the standard output (usually the console).
It allows the printing of variables, literals, and expressions using format specifiers.
#include <stdio.h>
int main() {
int num = 42;
printf("The value of num is: %d\n", num);
return 0;
}
The scanf() function is used to read formatted input from the standard input (usually the keyboard).
It takes format specifiers to specify the type of data to be read and the corresponding variables to store the values.
#include <stdio.h>
int main() {
int num;
printf("Enter a number: ");
scanf("%d", &num);
printf("You entered: %d\n", num);
return 0;
}
The gets() and puts() functions in C are used for handling strings. However, it's important to note that using gets() is considered
unsafe due to the potential for buffer overflow. As a result, it's generally recommended to use safer alternatives like fgets() for input.
The gets() function is used to read a line from the standard input (usually keyboard) and stores it into the provided character array.
It reads characters until a newline character ( '\n' ) is encountered or until the maximum size of the array is reached.
The absence of a buffer size check makes it prone to buffer overflow, which can lead to unpredictable behavior. More about data overflow
will be discussed in separate topic.
#include <stdio.h>
int main() {
char input[50];
printf("Enter a string: ");
gets(input);
printf("You entered: %s\n", input);
return 0;
}
#include <stdio.h>
int main() {
char message[] = "Hello world!";
puts(message); // Outputs the string with a newline character
return 0;
}
Hello world!
#include <stdio.h>
int main() {
char input[50];
printf("Enter a string: ");
gets(input); // Unsafe: potential for buffer overflow
puts(input); // Outputs the entered string
return 0;
}
Note:
While puts() is generally safe for output, it's crucial to avoid using gets() due to its lack of buffer size checking. Instead, prefer
functions like fgets() for safer string input operations.
In modern C programming, it's recommended to use fgets() for input and printf() or fputs() for output to ensure safer
handling of strings.
gets() vs scanf()
Usage Reads a line of text from standard input Reads formatted data from standard input.
(unsafe).
Input Format Reads characters until newline or EOF is Allows for more specific formatting using format specifiers.
encountered.
Example gets(input); scanf("%s", input);
Handling White Does not stop reading at white spaces, Stops reading at white spaces by default unless specified
Spaces includes spaces. otherwise in format specifiers.
Buffer Overflow High risk due to lack o buffer size checking. Risk can be mitigated by specifying field width and using proper
Risk format specifiers.
Safe Alternative fgets() is a safer alternative for string fgets() can also be used for safer string input with buffer size
input. checking.
#include <stdio.h>
int main() {
char ch;
printf("Enter a character: ");
ch = getchar(); //storing the value in ch
putchar(ch); // printing the value of ch
return 0;
}
Data Types - I
Primary Derived User Defined
Integer Function Class
Character Array Structure
Floating Point Pointer Union
Double Floating Reference Enum
Void Typedef
Primitive Types
Below figure is an overview of the memory size each Data Type uses. Each Box represents 1 Byte (8bits).
Integers Numbers
Data Type Size (bytes) Signed Range Unsigned Range Format Specifier
int 4 -2,147,483,648 to 2,147,483,647 0 to 4,294,967,295 %d
Data Type Size (bytes) Signed Range Unsigned Range Format Specifier
short 2 -32,768 to 32,767 0 to 65,535 %hd
#include <stdio.h>
int main() {
float x = 0.125;
double y = 111111.1111111;
printf("float: %zu, double: %zu", sizeof(x), sizeof(y));
return 0;
}
float: 4, double: 8
Char Type
keyword : char
Data Type Size (bytes) Signed Range Unsigned Range Format Specifier
char 1 -128 to 127 (default signed) 0 to 255 %c
The char data type is typically 1 byte (8 bits) in size on almost every architecture.
It can be signed or unsigned, with the default being signed.
The signed range is from -128 to 127 .
The unsigned range is from 0 to 255 .
The char type is intended to represent a single character and stores its ASCII number. For example, the character 'A' has the ASCII
number 65.
output : -1
Overflow occurs as 4294967295 exceeds the maximum value for a 32-bit signed integer (2147483647), resulting in wrapping to the
minimum value of -2147483648.
However, when using unsigned the issue doesn't happen. It correctly represents the value:
output : 4294967295
Example overview
#include <stdio.h>
int main() {
int a = 123;
float b = 34.6;
char c = 'A';
double pi = 2.01E6; // E6 = 10^6
double pi2 = 2.1416;
return 0;
}
block-A
{
element b;//Local variable
element a - accessible
element b - accessible
}
block-B
{
block-C
{
element c; //Local variable
element c - accessible
}
element a - accessible
element b - not accessible
element c - not accessible
}
1. Global Scope:
Variables or functions declared outside any function or block have global scope.
They can be accessed from anywhere in the program, both from within functions and outside of them.
#include <stdio.h>
int globalVariable = 10; // Global variable - Outside all function
void exampleFunction() {
printf("Accessing global variable: %d\n", globalVariable); //ACCEPTABLE
}
int main() {
exampleFunction();
printf("Accessing global variable from main: %d\n", globalVariable);//ACCEPTABLE
return 0;
}
2. Local Scope:
Variables declared within a function or a block have local scope.
They are only accessible within the block where they are declared.
Example:
#include <stdio.h>
void exampleFunction() {
int localVariable = 5; // Local variable
printf("Local variable: %d\n", localVariable); //ACCEPTABLE
}
int main() {
printf("Trying to access local variable: %d\n", localVariable); // ERROR
exampleFunction();
return 0;
}
Initialization in C:
Knowing about initialization is important. It essentially involves assigning an initial value to a variable at the time of its declaration. It's a
good practice to initialize variables when they are declared to avoid using undefined values.
int y; // Declaration
y = 20; // Initialization after declaration
3. Dynamic Initialization:
Variables, especially arrays and pointers, can be dynamically initialized at runtime using functions like malloc() or calloc()
for memory allocation.
#include <stdlib.h>
int *dynamicArray = (int*)malloc(5 * sizeof(int)); // Dynamic initialization of an array
Syntax:
Example:
#include <stdio.h>
typedef int newname; // Define a typedef for int
int main() {
newname num = 42; // Using the typedef
int num2 = 45;
printf("Numbers: %d %d", num, num2);
return 0;
}
Numbers: 42 45
Notice how we created an alias for int naming it newname . Now we can use both.
Enumeration in C
Enumeration, or enum , is a user-defined data type used to assign names to integral constants. The enum keyword is employed to define
an enumerated data type.
Syntax:
Here, type_name is the name of the enumerated data type, and value1 , value2 , ..., valueN are the constant values associated with it.
By default, the constants are assigned sequential integer values starting from 0.
Custom Initialization:
Example:
#include <stdio.h>
enum Weekdays { MON = 1, TUE, WED, THU, FRI, SAT, SUN };
int main() {
enum Weekdays today = WED;
printf("Today is day %d of the week.", today);
return 0;
}
In this example, an enumeration named Weekdays is defined with custom values. The program then uses it to declare a variable today
and prints the corresponding day.
More examples:
#include<stdio.h>
enum year{Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};
int main() {
int i;
for (i=Jan; i<=Dec; i++)
printf("%d ", i);
return 0;
}
Output: 0 1 2 3 4 5 6 7 8 9 10 11
Even if you don't understand the for (...) yet, it's easy to understand what's enum actually doing.
#include <stdio.h>
enum week{ sunday=8, monday=4, tuesday=64, wednesday=84, thursday, friday, saturday};
int main(){
enum week today;
today=sunday;
printf("%d day\n",today);
today=wednesday;
printf("%d day\n",today);
today=thursday;
printf("%d day\n",today);
return 0;
}
Output:
8 day
84 day
85 day
Symbolic Constants in C
Symbolic constants in C are named identifiers representing fixed values that cannot be altered during the program's execution. Symbolic
constants can represent numeric constants, character constants, or strings.
Here, CONSTANT_NAME is the name of the symbolic constant, and value is its corresponding constant value. When the program is
compiled, each occurrence of the symbolic constant is replaced with its defined value.
Example:
#include <stdio.h>
#define PI 3.1416 // preprocessor directive define
#define MAX_SIZE 100
#define GREETING "Hello, World!"
int main() {
double radius = 5.0;
double area = PI * radius * radius;
printf("The area of the circle with radius %lf is %lf\n", radius, area);
printf("Max size allowed: %d\n", MAX_SIZE);
printf("Greeting: %s\n", GREETING);
return 0;
}
Note : Unlike a variable definition, which reserves storage, a symbolic constant does not use any storage.
Example:
#include <stdio.h>
int main() {
int x = 10; // Operand
int y = 5; // Operand
int result = x + y; // Expression with operator '+'
printf("The result of the expression x + y is: %d\n", result);
return 0;
}
In this example, x and y are operands, and + is the operator, forming an expression x + y . The result of this expression is assigned to
the variable result and then printed.
printf("Hello World!\n");
Here, the function printf() is an Operator which is essentially a function call and
"Hello world!\n" is the operand, the parameter . More on those on another topic regarding functions.
If-else Statements in C
The if and else statements are used for conditional execution of code. These statements allow the program to make decisions based
on certain conditions.
Basic Syntax:
if (condition) {
// Code to be executed if the condition is true
} else {
// Code to be executed if the condition is false
}
Example:
#include <stdio.h>
int main() {
int number = 10;
if (number > 0) {
printf("The number is positive.\n");
} else {
printf("The number is not positive.\n");
}
return 0;
}
In this example, the if statement checks if the variable number is greater than 0. If the condition is true, it executes the code inside the
first block. If the condition is false, the code inside the else block is executed.
Multiple Conditions:
You can also use multiple if and else statements to check for multiple conditions:
#include <stdio.h>
int main() {
int score = 75;
if (score >= 90) {
printf("Excellent!\n"); //score(75) is not greater or equal than 90
} else if (score >= 70) {
printf("Good job!\n"); //score(75) is greater or equal than 70. This will execute.
} else {
printf("Try harder.\n");
}
return 0;
}
Good job!
In this example, the program checks the value of the score variable against different conditions. Depending on the value of score , it
prints different messages.
Operators in C
Operators in C are symbols that represent computations or actions to be performed on operands.
Arithmetic Operators:
Relational Operators:
Logical Operators:
Certainly! Here's your code formatted with proper indentation and the corresponding output:
#include <stdio.h>
int main() {
int a = 21;
int b = 10;
if (a == b) {
printf("Line 1 - a is equal to b\n");
} else {
printf("Line 1 - a is not equal to b\n");
}
if (a < b) {
printf("Line 2 - a is less than b\n");
} else {
printf("Line 2 - a is not less than b\n");
}
if (a > b) {
printf("Line 3 - a is greater than b\n");
} else {
printf("Line 3 - a is not greater than b\n");
}
// Change values of a and b
a = 5;
b = 20;
if (a <= b) {
printf("Line 4 - a is either less than or equal to b\n");
}
if (b >= a) {
printf("Line 5 - b is either greater than or equal to a\n");
}
return 0;
}
Line 1 - a is not equal to b
Line 2 - a is not less than b
Line 3 - a is greater than b
Line 4 - a is either less than or equal to b
Line 5 - b is either greater than or equal to a
Assignment Operators:
+= Addition assignment x += 3; 8
-= Subtraction assignment x -= 2; 6
*= Multiplication assignment x *= 2; 12
/= Division assignment x /= 3; 4
%= Modulus assignment x %= 3; 1
Increment/Decrement Operators:
Bitwise Operators:
#include<stdio.h>
int main() {
int a, b;
scanf("%d %d", &a, &b); // Input