C Programming

This is a collection of notes on C Programming. This is a work in progress and will be updated regularly.

00. Introduction to C Programming

Notes on C Programming

C is a procedural programming language. It was initially developed by Dennis Ritchie in the year 1972. It was mainly developed as a system programming language to write an operating system. The main features of the C language include low-level memory access, a simple set of keywords, and a clean style, these features make C language suitable for system programmings like an operating system or compiler development.

Many later languages have borrowed syntax/features directly or indirectly from the C language. Like syntax of Java, PHP, JavaScript, and many other languages are mainly based on the C language. C++ is nearly a superset of C language (Few programs may compile in C, but not in C++).

01. Arrays in C program

Arrays a kind of data structure that can store a fixed-size sequential collection of elements of the same type.

Collection of variables of the same type.

size and type of an array cannot be changed once it is declared.

Array values are stored in contiguous memory locations

Declaring Arrays

Syntax

type arrayName [ arraySize ];

Example

double balance[10];

Initializing Arrays

double type0[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};
double type1[] = {1000.0, 2.0, 3.4, 7.0, 50.0};
 

Multi-dimensional Arrays

type name[size1][size2]...[sizeN];

Example

int threedim[5][10][4];

Two-dimensional Arrays

A two-dimensional array is, in essence, a list of one-dimensional arrays

Initializing

 
int a[3][4] = {
   {0, 1, 2, 3} ,   /*  initializers for row indexed by 0 */
   {4, 5, 6, 7} ,   /*  initializers for row indexed by 1 */
   {8, 9, 10, 11}   /*  initializers for row indexed by 2 */
};
 

Accessing Two-Dimensional Array Elements

int val = a[2][3];

Change Value of Array elements

a[2][3] = 5;

Passing Arrays as Function Arguments

  1. Parameters as a pointer
 
void myFunction(int *param) {
    // body of the function
}
 
  1. parameters as a sized array
void myFunction(int param[10]) {
    // function body
}
  1. parameters as an unsized array
void myFunction(int param[]) {
    // body of the function
}

Return array from function

Return a pointer to an array by specifying the array's name without an index.

 
int * myFunction() {
    // function body
}
 

Example

#include <stdio.h>
 
/* function to generate and return random numbers */
int * getRandom( ) {
 
   static int  r[10];
   int i;
 
   for ( i = 0; i < 10; ++i) {
      scanf("%d", &r[i]);
      printf( "r[%d] = %d\n", i, r[i]);
   }
 
   return r;
}
 
/* main function to call above defined function */
int main () {
 
   /* a pointer to an int */
   int *p;
   int i;
 
   p = getRandom();
 
   for ( i = 0; i < 10; i++ ) {
      printf( "*(p + %d) : %d\n", i, *(p + i));
   }
 
   return 0;
}

02. C Pointers

Pointers (pointer variables) are used to store addresses rather than values.

Address in C

& gives the address of the variable in memory

#include <stdio.h>
int main()
{
  int var = 5;
  printf("var: %d\n", var);
 
  // Notice the use of & before var
  printf("address of var: %p", &var);
  return 0;
}

You will probably get a different address when you run the above code.

Declaration

int* p;
int *p1;
int * p2;
int* p1, p2;

A pointer points to either no address or a random address. where as, A variable has an address but contains random garbage value.

Assigning addresses to Pointers

int* pc, c;
c = 5;
pc = &c;

Get Value of stored in Pointers

 
int* pc, c;
c = 5;
pc = &c;
printf("%d", *pc);   // Output: 5
 

* is called the dereference operator (when working with pointers). It operates on a pointer and gives the value stored in that pointer.

Changing Value Pointed by Pointers

int* pc, c;
c = 5;
pc = &c;
c = 1;
printf("%d", c);    // Output: 1
printf("%d", *pc);  // Ouptut: 1

or

int* pc, c;
c = 5;
pc = &c;
*pc = 1;
printf("%d", *pc);  // Output: 1
printf("%d", c);    // Output: 1

Pointer arithmetic

  1. Incrementing a Pointer
ptr++;
  1. Decrementing a Pointer
ptr--;

Pointer to array

int arr[10];
int *p[10]=&arr; // Variable p of type pointer is pointing to the address of an integer array arr.

Pointer to a function

void displayValue(int value);
 
// Pointer p is pointing to the address of a function
int *ptr;
void(*p)(int) = &displayValue;
// void(*p)(int) = displayValue;
// returnType (*variableName)(parameters) = &functionName

Unlike normal pointers, a function pointer points to code, not data. Typically a function pointer stores the start of executable code. Unlike normal pointers, we do not allocate de-allocate memory using function pointers. A function’s name can also be used to get functions’ address.

Pointer to Pointer

Pointer contains the address of another pointer

NULL Pointers

A pointer that is assigned NULL is called a null pointer.

#include <stdio.h>
 
int main () {
   int  *ptr = NULL;
   printf("The value of ptr is : %x\n", ptr  );
   return 0;
}

Void Pointer

The void pointer in C is a pointer which is not associated with any data types

void *ptr;
  1. Pointer arithmetic is not possible with void pointer due to its concrete size.

  2. It can’t be used as dereferenced.

Near pointer

Used to store 16 bit addresses.

The limitation is that we can only access 64kb of data at a time.

Far pointer

Used to store 32 bit addresses.

Dangling Pointers

A pointer pointing to a memory location that has been deleted (or freed) is called dangling pointer.

  1. De-allocation of memory
#include <stdlib.h>
#include <stdio.h>
int main()
{
	int *ptr = (int *)malloc(sizeof(int));
	free(ptr);
  // No ptr is a dangling pointer
 
	// No more a dangling pointer
	ptr = NULL;
}
  1. Variable goes out of scope
void main()
{
   int *ptr;
   .....
   .....
   {
       int ch;
       ptr = &ch;
   }
   .....
   // Here ptr is dangling pointer
}

Advantage of pointer

  1. Pointer reduces the code and improves the performance

  2. We can return multiple values from a function using the pointer.

  3. It makes you able to access any memory location in the computer's memory.

Usage of pointer

There are many applications of pointers in c language.

  1. Dynamic memory allocation using malloc() and calloc() functions.

  2. Arrays, Functions, and Structures

Dynamic memory allocation

The concept of dynamic memory allocation in c language enables the C programmer to allocate memory at runtime.

4 functions of stdlib.h header file.

  1. malloc()
  2. calloc()
  3. realloc()
  4. free()

malloc() function

The malloc() function allocates single block of requested memory.

Initialize memory at execution time, so it has garbage value initially.

It returns NULL if memory is not sufficient.

ptr=(cast-type*)malloc(byte-size)

calloc() function

The calloc() function allocates multiple block of requested memory.

It initially initialize all bytes to zero.

It returns NULL if memory is not sufficient.

The syntax of calloc() function is given below:

ptr=(cast-type*)calloc(number, byte-size)

Deference between malloc() and calloc()

Initialization: malloc() - doesn't clear and initialize the allocated memory. calloc() - initializes the allocated memory by zero.

Speed: malloc() is fast. calloc() is slower than malloc().

Arguments & Syntax: malloc() takes 1 argument

  1. The number of bytes to be allocated

calloc() takes 2 arguments:

  1. length the number of blocks of memory to be allocated

  2. bytes the number of bytes to be allocated at each block of memory

   void *malloc(size_t bytes);
   void *calloc(size_t length, size_t bytes);

Meaning on name: The name malloc means "memory allocation". The name calloc means "contiguous allocation".

03. Conditional statements

Conditionals with if, else

Decisions are based on conditions

Is raining -> take raincoat

Computer programs also make decisions, using Boolean expressions (true/false) inside conditionals (if/else).

Example

simple conditions
if(raining){
    printf("hello world");
}

Syntax

if (<condition>) {
    // instructions to be executed if the test expression is true
} else {
    // instructions to be executed if the test expression is false
}

The condition is a Boolean expression: an expression that evaluates to either true or false.

How if statement works?

The if statement evaluates the test expression inside the parenthesis ().

  • If the expression is evaluated to true,

    1. statements inside the body of if are executed.
    2. statements inside the body of else are skipped from execution.
  • If the expression is evaluated to false,

    1. statements inside the body of if are not executed.
    2. statements inside the body of else are executed
  • Also called as branching
  • Also called as control statements (controls the flow of execution of a program.)

Comparison operators

| operator | Greater | True Expressions | | -------- | --------------------- | ---------------- | | > | Greater than | 60 > 32 | | >= | Greater than or equal | 60 >= 32 | | < | Less than | 20 < 32 | | <= | Less than or equal | 20 <= 32 | | === | Strict equality | 32 === 32 | | == | Equality | 32 == 32 | | !== | Strict inequality | 30 !== 32 | | != | Inequality | 30 != 32 |

The else statement

To execute a different set of instructions when the condition is false, then we can use an else statement.

Example

 
if (password === "TOPSECRET") {
   println("You got it!");
} else {
   println("Try again!");
}
 

Nested conditionals

When a program selects one of many paths, it can use nested or chained conditionals.

nested conditions
int number = 10;
char[10] numberSign;
 
if (number > 0) {
  numberSign = "positive";
} else {
  if (number < 0) {
    numberSign = "negative";
  } else {
    numberSign = "neutral";
  }
}
 

Pay attention to the syntax and formatting of your nested conditionals.

Chained conditionals (The if-else Ladder)

To check possible values of a single variable.

 
char[10] numberSign;
 
if (number > 0) {
  numberSign = "positive";
} else if (number < 0) {
  numberSign = "negative";
} else {
  numberSign = "neutral";
}

Compound Booleans with logical operators

To make shorter and more expressive code by combining simple Boolean expressions using logical operators (and, or, not) to create compound Boolean expressions.

The OR operator

either of two conditions are true.

 
if (temperature < 25) {
   printf("Wear a jacket!");
}
if (weather === "rain") {
   printf("Wear a jacket!");
}
 

or

 
if (temperature < 25 || weather === "rain") {
   printf("Wear a jacket!");
}
 

DRY: Don't Repeat Yourself

The AND operator

both of the conditions are true

 
if(weather === "rain"){
    if(transportMode === "walking"){
        printf("Take an umbrella!");
    }
}
 
 
if (weather === "rain" && transportMode === "walking") {
   printf("Take an umbrella!");
}

The NOT operator

Reverse the value of the expression

 
if (temperature < 70 || weather === "rain") {
    // do nothing
}else {
   printf("Gardening day!");
}
 
if (!(temperature < 70 || weather === "rain")) {
   println("Gardening day!");
}

Example:

#include<stdio.h>
#include<string.h>
#include <ctype.h>
 
int allChars(const char *str){
   size_t i;
   for(i=0;str[i];i++)
     if(!isalpha(str[i]))
        return 0;
   return 1;
}
 
int main(){
    char password[20];
    int verification_code;
    printf("Enter the password: ");
    scanf("%s", password);
    printf("Enter the verification code: ");
    scanf("%d", &verification_code);
 
    if(strlen(password) < 8){
        printf("Your password is weak\n");
    } else if(allChars(password) || !strcmp(password, "password@123")){
        printf("Your password is weak \n");
        printf("Your password can be easily hacked \n");
    } else {
        printf("Welcome user\n");
        if(!strcmp(password, "root@123") && verification_code == 5){
            printf("You are an admin\n");
        } else {
            printf("You are a user\n");
        }
    }
}
 

Referrals

https://www.khanacademy.org/computing/ap-computer-science-principles/programming-101/boolean-logic/a/conditionals-with-if-else-and-booleans

04. Errors

Core Dump (Segmentation fault) in C

Core Dump/Segmentation fault is a specific kind of error caused by accessing memory that “does not belong to you."

  • When a piece of code tries to do read and write operation in a read only location in memory or freed block of memory, it is known as core dump.
  • It is an error indicating memory corruption.
  1. Modifying a string literal :
int main()
{
char *str;
 
/* Stored in read only part of data segment */
str = "GfG";
 
/* Problem: trying to modify read only memory */
*(str+1) = 'n';
return 0;
}
  1. Accessing an address that is freed :
// C program to illustrate
// Core Dump/Segmentation fault
#include <stdio.h>
#include<alloc.h>
int main(void)
{
	// allocating memory to p
	int* p = malloc(8);
	*p = 100;
 
	// deallocated the space allocated to p
	free(p);
 
	// core dump/segmentation fault
	// as now this statement is illegal
	*p = 110;
 
	return 0;
}
  1. Accessing out of array index bounds

  2. Improper use of scanf()

05. Functions

A function is a block of code that performs a specific task.

A function is a set of statements that take inputs, do some specific computation and produces output.

Uses of functions

  • To improve readability
  • Reusability
  • Easy to Debug
  • Reduce the size of the code

Parameter and Arguments

Parameter: Is a variable in the declaration and definition of the function.

Arguments: Is the actual value of the parameter that gets passed to the function.

Function prototype or Declaration

Declaration of a function that specifies function's name, parameters and return type. It doesn't contain function body.

Syntax

returnType functionName(type1 argument1, type2 argument2, ...);

return_type: Return type can be of any data type such as int, double, char, void, short etc.

function_name: A name that convies the purpose of function.

argument list: Input variables names along with their data types.

Block of code: Statements which will be executed whenever a call will be made to the function.

Calling a function

Control of the program is transferred to the user-defined function by calling it.

Syntax

functionName(argument1, argument2, ...);

Passing arguments to a function

passing arguments to function

Pass by value:

values of actual parameters are copied to function’s formal parameters and the two types of parameters are stored in different memory locations.

Pass by reference:

Both actual and formal parameters refer to same locations, so any changes made inside the function are actually reflected in actual parameters of caller.

Function definition

Function definition contains the block of code to perform a specific task.

Return Statement

Syntax

returnType functionName(type1 argument1, type2 argument2, ...)
{
    //body of the function
    return (expression);
}
return statement from function

Types of functions

  • Standard library functions
  • User defined functions

Classification of function based on return values and arguments

  1. Function with arguments and with return value
  2. Function with arguments and without return value
  3. Function without arguments and without return value
  4. Function without arguments and with return value

Standard library functions

The standard library functions are built-in functions in C programming.

  • printf() is a standard library function to send formatted output to the screen. The function is defined in stdio.h header file

  • The sqrt() function calculates the square root of a number. The function is defined in the math.h header file.

Advantages of using library functions

  1. They work
  2. Optimized for performance
  3. Saves development time
  4. Portable
  5. Provides abstraction

User-defined function

User created functions

How functions work in C

how functions work

Every C program has a function called main() that is called by operating system when a user runs the program.

In C, functions can return any type except arrays and functions.

A function can call itself and it is known as “Recursion“.

Example:

 
#include<stdio.h>
 
int multiply(int a, int b);     // function declaration
 
int main()
{
    int i, j, result;
    printf("Please enter 2 numbers you want to multiply...");
    scanf("%d%d", &i, &j);
 
    result = multiply(i, j);        // function call
    printf("The result of muliplication is: %d", result);
 
    return 0;
}
 
int multiply(int a, int b)
{
    return (a*b);       // function defintion, this can be done in one line
}
 

06. Looping

World is full of repetition

Loops are used to repeat a set of instructions a specific number of times.

While Loop

A while loop is a way to repeat code until some condition is false It is a entry controlled or pre checking loop

 
while(<condition>){
    <instructions>
}
 

Example

 
int y = 40;
 
while(y < 400){
    y = y + 20;
}
 

If condition inside the parenthesis never become false it will lead to Infinite Loops

Example for infinite loops are while(true) or for(;;)

Do While loop

Condition is executed after the body of the loop. Also called as exist controlled loop.

Syntax:

 
do{
    <instructions>
} while(<condition>)

Example:

 
do {
    // statements
} while (expression)
 

Example :

 
int y = 40;
 
do {
    y = y + 20;
} while(y < 200);
 

For Loop

For loop starts with a 3 part header inside the parenthesis It is a entry controlled or pre checking loop

for(initialization; condition; increment/decrement)
  • Initialization of the for loop is performed only once
  • Condition check is done on every start of every iteration. If the test expression is evaluated to false, the for loop is terminated.
  • Incrementation/ Decrementation happens at the end of each iteration

Example:

int i;
for(i =0; i< 13; i++ ){
    printf(9*1);
}
 
for flowchart

Various forms of for loop in C

  1. Initialization part can be skipped from the loop
int num=10;
for (;num<20;num++)

Note: Even though we can skip initialization part but semicolon (;) before condition is must, without which you will get compilation error.

  1. You can also skip the increment. Semicolon (;) is must after condition logic.
for (num=10; num<20; )
{
      //Statements
      num++;
}
  1. The counter variable is initialized before the loop and incremented inside the loop.
int num=10;
for (;num<20;)
{
      //Statements
      num++;
}
  1. for(;;) is valid infinite loop

Nested Loops

Allows us to repeat along two dimensions

 int i, j;
 for(i=0;i<10: i++){
     for(j=1;j<10;j++){
         printf(i * j);
     }
 }
 

Break Statement

Used to exist the loop

Continue statement

Skip to next iteration without existing out of the loop

Example

 
#include<stdio.h>
 
int main(){
    int on = 1;
    int a, b;
    while(on){
        printf("Enter two number a and b: ");
        scanf("%d %d", &a, &b);
        if(a == 0 || b ==0){
            break;
        }
 
        if(a == 1 || b == 1){
            continue;
        }
 
        printf("The output of %d and %d is %d\n", a, b, a+b);
        printf("enter 0 to turn of the calculator: ");
        scanf("%d", &on);
    }
 
    printf("\nThank you!!");
}
 

07. Strings and Character array

String is a sequence of characters terminated by null character '\0'

char c[] = "c string";

Memory allocation

[c][ ][s][t][r][i][n][g][\0]
  • String is not a data type in C
  • A string is one-dimensional array of characters

Declaring string variables

char s[5];

Initializing a string variables

There are different ways to initialize a character array variable.

 
char name[13] = "StudyTonight";       // valid character array initialization
 
char name[10] = {'L','e','s','s','o','n','s','\0'};     // valid initialization
 
char c[] = "c string";  // Valid initialization
 
char ch[3] = "hell";    // Illegal
 

Assigning Values to Strings

char str[4];
str = "hell";   // Illegal

The strcpy() function can be used to copy the string instead.

String Input and Output

Input function scanf() and gets() can be used with %s format specifier to read a string input from the terminal.

  • scanf() terminates its input on the first white space it encounters.
 
#include<stdio.h>
#include<string.h>
 
int main()
{
    char str[20];
    char text[20];
 
    // using gets
    gets(text);
    printf("%s\n", text);
 
    // using scanf
    printf("Enter a string: ");
    scanf("%[^\n]", str);  //scanning the whole string, including the white spaces
    printf("%s\n", str);
}
 

String Handling Functions

C supports a large number of string handling functions in the standard library "string.h"

| Method | Description | | -------- | -------------------------------- | | strcat() | concatenate(combine) two strings | | strlen() | returns length of a string | | strrev() | reverse of a string | | strcpy() | Copies one string into another | | strcmp() | compare two string |

Passing strings to functions

 
#include <stdio.h>
void displayString(char str[]);
 
int main()
{
    char str[50];
    printf("Enter string: ");
    gets(str);
    displayString(str);     // Passing string to function.
    return 0;
}
void displayString(char str[])
{
    printf("String Output: ");
    puts(str);
}
 

08. Structure and Unions

Define structures

A struct (or structure) is a collection of variables (can be of different types) under a single name.

Syntax of struct

struct structureName
{
    dataType member1;
    dataType member2;
};

Example

struct Person
{
    char name[50];
    int citNo;
    float salary;
};

Create struct variables

Creating struct variables allocates the memory

struct Person
{
    char name[50];
    int citNo;
    float salary;
};
 
int main()
{
    struct Person person1, person2, p[20];
    return 0;
}

Another way is

struct Person
{
    char name[50];
    int citNo;
    float salary;
} person1, person2, p[20];

Access members of a structure

  1. . - Member operator
  2. -> - Structure pointer operator

Example

person2.salary;
person2->salary;

Keyword typedef

typedef keyword is used to create an alias name for data types.

struct Distance{
    int feet;
    float inch;
};
 
int main() {
    struct Distance d1, d2;
}

is equivalent to

typedef struct Distance{
    int feet;
    float inch;
} distances;
 
int main() {
    distances d1, d2;
}

Nested Structures

Structures within a structure

struct complex
{
 int image;
 float real;
};
 
struct number
{
   struct complex comp;
   int integers;
} num1, num2;
 
 
num2.comp.image = 11;

Example

// Program to add two distances (feet-inch)
#include <stdio.h>
struct Distance
{
    int feet;
    float inch;
} dist1, dist2, sum;
 
int main()
{
    printf("1st distance\n");
    printf("Enter feet: ");
    scanf("%d", &dist1.feet);
 
    printf("Enter inch: ");
    scanf("%f", &dist1.inch);
    printf("2nd distance\n");
 
    printf("Enter feet: ");
    scanf("%d", &dist2.feet);
 
    printf("Enter inch: ");
    scanf("%f", &dist2.inch);
 
    // adding feet
    sum.feet = dist1.feet + dist2.feet;
    // adding inches
    sum.inch = dist1.inch + dist2.inch;
 
    // changing to feet if inch is greater than 12
    while (sum.inch >= 12)
    {
        ++sum.feet;
        sum.inch = sum.inch - 12;
    }
 
    printf("Sum of distances = %d\'-%.1f\"", sum.feet, sum.inch);
    return 0;
}