Identifying Constants in Pseudocode
Identifying Constants in Pseudocode
Progress)
Contact Person:
1
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
2
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Table of Contents
★ Prerequisites -
➢ Abstract Data Type (ADT)
➢ Array
➢ Pointer
➢ Recursion
➢ Segmentation fault
➢ Unix error code
➢ Time and space complexity
➢ Introduction to data structure
1. Linked list
1.1. Singly linked lists.
1.2. Doubly linked lists.
1.3. Circular linked lists.
1.4. Circular doubly linked lists
2.Stack
Subset of General Linked List LIFO
3.Queue
Subset of General Linked List FIFO
4.Tree
binary Tree
5.Sorting
5.1. Quick sort
5.2. Merge sort
6.Graph
7.Hashmap
8.Dictionary
3
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Variables
A variable in a program has a name and can vary in value. The compiler and linker handle this by
assigning a specific block of memory within the computer to hold the value of that variable.
The size of that block depends on the range over which the variable is allowed to vary. For example, on
a 32-bit PC, the size of an integer variable is 4 bytes. On older 16-bit PCs, integers were 2 bytes. In C,
the size of a variable type, such as an integer, does not need to be the same on all types of machines.
We have integers, long integers, and short integers, which you can read up on in any basic text on C.
This document assumes a 32-bit system with 4-byte integers.
When we declare a variable, we inform the compiler of two things: the variable's name
and the variable's type.
Variables in C are used to access a single location of memory, and the memory size depends on
the size of the data types.
Therefore, a variable MUST be declared before being used. When you declare a variable, the
compiler automatically allocates memory for it.
Example:
data_type variable_name;
Whether we start or are heading to work on something new in programming, remember to “Try”
to understand the semantics of the new thing, how to use it in your program, and what inherent
things you need to capture in your memory.
Remember that nothing needs to be memorized. If you need to memorize something, you have
some logic gaps. If you cannot find your gaps, consult your friends and teachers.
4
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Syntax:
Same purpose
Some logic:
true ; otherwise ;
5
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Variables
A variable in a program is something with a name, the value of which can vary.
The compiler and linker handle this by assigning a specific block of memory
within the computer to hold the value of that variable. The size of that block
depends on the range over which the variable is allowed to vary. For example, on
32-bit PC's, the size of an integer variable is 4 bytes. On older 16-bit PCs,
integers were 2 bytes. In C, the size of a variable type, such as an integer, does
not need to be the same on all kinds of machines. We have integers, long
integers, and short integers, which you can read up on in any introductory text on
C. This document assumes a 32-bit system with 4-byte integers. When we
declare a variable, we inform the compiler of two things: the variable's name and
the variable's type.
Variables in C are used to access a single location of memory, and the memory size
depends on the size of data types. Therefore, a variable MUST be declared before
using it. When you declare a variable, the compiler automatically allocates memory for
that variable.
Arrays can be considered as the collection of variables where the base address of the
array is the first element of the array. An array in C Programming can be defined as a
number of memory locations, each storing the same data type and referenced using the
same variable name.
6
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Arrays and pointers are synonymous in how they are used to access memory. But, the
vital difference between them is that a pointer variable can take different addresses
as values, whereas it is fixed in the case of an array. In C, the name of the array always
points to the first element of an array.
Suppose you declared the array of 10 students. For example, students[10]. You can use array
members from student[0] to student[9]. But what if you want to use element student[10],
student[100], etc? In this case, the compiler may not show an error using these elements but
may cause a fatal error during program execution.
Multidimensional Arrays
Just consider each box is the storage of a simple variable. Now you can map the logic of a
variable and an element of Array in Programming.
Row- 2 array[2][5]
When we declare a variable, we inform the compiler of two things: the variable's name and
the variable's type. For example, we declare a variable of type integer with the name k by
writing:
int k;
When it sees the "int" part of this statement, the compiler sets aside 4 bytes of memory to
hold the integer's value. It also sets up a symbol table. That table adds the symbol k and the
relative address in memory where those 4 bytes were set aside.
7
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
k=2
We expect that when this statement is executed at run time, the value 2 (two) will be
placed in that memory location reserved for storing the value of k. In C, we refer to a
variable such as an integer k as an "object."
We define a pointer variable in C by preceding its name with an asterisk. We also give our
pointer a type, which refers to the type of data stored at the address we will be storing in
our pointer. For example, consider the variable declaration:
int *ptr;
ptr is the name of our variable, and the '*' informs the compiler that we want a pointer
variable, i.e., to set aside however many bytes are required to store an address in memory.
The int says that we intend to use our pointer variable to store the address of an integer.
Such a pointer is said to "point to" an integer. A pointer initialized in this manner is called a
"null" pointer.
The actual bit pattern used for a null pointer may or may not be evaluated to zero since no
value is assigned. Thus, setting the value of a pointer using the NULL macro, as with an
assignment statement such as ptr = NULL, guarantees that the pointer has become a null
pointer.
Suppose we now want to store the address of our integer variable k in ptr. To do this, we
use the unary & operator and write:
ptr = &k;
*ptr = 7;
as int A[10];
can be accessed using its pointer representation. The name of the array A is a constant
pointer to the first element of the array. So A can be considered a const int*. Since A is a
constant pointer, A = NULL would be an illegal statement. Arrays and pointers are
synonymous in how they are used to access memory.
8
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
But, the vital difference between them is that a pointer variable can take different
addresses as values, whereas it is fixed in the case of an array.
In C, the name of the array always points to the first element of an array. Here, the
address of the first element of an array is std[0]. Also, std represents the address of the
pointer where it is pointing. Hence, &std[0] is equivalent to std. Note the value inside the
address &std[0] and address age are equal. Value in address &std[0] is std[0], and value in
address std is *std. Hence, std[0] is equivalent to *std.
C arrays can be of any type. We define an array of ints, chars, doubles, etc. We can also
define a variety of pointers as follows. Here is the code to define an array of n char
pointers or an array of strings.
char* array[n];
each cell in the array A[i] is a char*, so it can point to a character. If you want to assign a
string to each A[i], you can do something like this.
Again, this only allocates memory for a string, and you still need to copy the characters into
this string. So if you are building a dynamic dictionary (n words), you need to allocate memory
for n char*’s and then allocate just the right amount for each string.
Pointer Array
9
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
A pointer is a place in memory that keeps Expression a[4] refers to the 5th element
the address of another place inside of the array a.
The pointer can’t be initialized at the Arrays can be initialized at definition. Example
definition
int num[] = { 2, 4, 5}
The pointer is dynamic. The memory They are static. Once memory is
allocation can be resized or freed allocated, it cannot be resized or
later. freed dynamically.
10
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Mapping:
A single location: e.g., int a;
Multiple addresses (Contiguous), but in the case of Array, the first address is randomly
allocated, and the rest of the addresses will be contiguous, and the memory size will be based on your
declaration for the array. Again, note that the first address, index 0 (zero), will be allocated randomly by
the compiler (the base address), and the rest of the address will follow the base address contiguously.
11
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
0 1 …… n
12
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Here are 15 things to remember when you start a C program from scratch.
1. Include <stdio.h> and all other related headers in all your programs.
2. Declare functions and variables before using them
3. It is better to increment and decrement with ++ and -- operators.
4. Better to use x += 5 instead of x = x +5
5. A string is an array of characters ending with a ‘\0”. Don’t ever forget the null
character.
6. An array of size n has indices from 0 to n-1. Although C will allow you to
access A[n] it is hazardous
7. A character can be represented by an integer (ASCII value) and can be used as such.
8. The unary operator & produces an address
9. The unary operator * dereferences a pointer
10. Arguments to functions are always passed by value. But the argument can be addressed
with just a value.
11. For efficiency, pointers can be passed to or return from a function
12. Logical false is zero, and anything else is true
13. You can do things like for(;;) or while(i++) for program efficiency and understanding
14. Use /* .. */ instead of //, it makes the code look better and readable
15. The last and most important one is always compiling your program before submitting
it or showing it to someone. Don’t assume that your code is compilable and contains no
errors.
16. Try using –std=c99, which is the c99 standard. It's better. (Although c11 is also on
its way, it is not a standard at the moment for all machines)
13
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Table Of Contents
Macro
Inline Function
Callback Function
Function Pointer
Bit field in c
Reference: [Link]
14
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Macros
Syntax of a Macro:
#define macro_name macro_value;
Example Program:
#include <stdio.h>
#define MACRO 10 //macro definition
int main(){
printf("the value of a is: %d", MACRO);
return 0;
}
15
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Inline Function
By declaring a function inline, you can direct GCC to make calls to that function
faster. One way GCC can achieve this is by integrating that function's code into the
code for its callers. This makes execution faster by eliminating the function-call
overhead; if any of the actual argument values are constant, their known values permit
simplifications at compile time so that not all of the inline function's code needs to be
included. Depending on the case, the effect on code size is less predictable; object
code may be larger or smaller with function inlining.
A C program can be optimized with two goals: to reduce the Code size or to get the
best performance (time). Usually, these are two opposite ends of the line. To
reduce the code size, the program is optimized so that it compromises
performance to some extent. With a compiler set to optimize for performance in
terms of execution time, the generated binary is usually of higher code size. Since it
can be requirement-dependent, it is usually a trade-off between what fits the
requirement.
Inline functions:
By declaring a function inline, you can direct GCC to make calls to that function
faster. One way GCC can achieve this is by integrating that function's code into the
code for its callers. This makes execution faster by eliminating the function-call
overhead; if any of the actual argument values are constant, their known values permit
simplifications at compile time so that not all of the inline function's code needs to be
included. Depending on the case, the effect on code size is less predictable; object
code may be larger or smaller with function inlining.
So, it tells the compiler to build the function into the code, which is used to improve
execution time.
16
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
When an inline function is not static, then the compiler must assume that there may
be calls from other source files; since a global symbol can be defined only once in any
program, the function must not be defined in the other source files, so the calls
therein cannot be integrated. Therefore, a non-static inline function is always
compiled in the usual fashion.
❖extern inline?
If you specify both inline and extern in the function definition, then the definition is
used only for inlining. The function is not compiled independently, even if you refer to
its address explicitly. Such an address becomes an external reference as if you had
only declared the function and had not defined it.
This combination of inline and extern has almost the effect of a macro. It is used to
put a function definition in a header file with these keywords and put another copy of
the definition (lacking inline and extern) in a library file. The definition in the header
file causes most calls to the function to be inlined. If any uses of the function remain,
they refer to the single copy in the library.
17
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Executive Summary
18
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Callback Function
Reference:
[Link]
ey-implemented
Here, the populate_array function takes a function pointer as its third parameter
and calls it to get the values with which to populate the array. We've written the
callback getNextRandomValue, which returns a random-ish value, and passed a
pointer to populate_array. populate_array will call our callback function 10 times
and assign the returned values to the elements in the given array.
Let's say you want to write some code that allows you to register a callback to be
called when an event occurs.
19
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
event_cb_register(my_event_cb, &my_custom_data); …
In the internals of the event dispatcher, the callback may be stored in a struct
that looks something like this:
struct event_cb *callback; ... /* Get the event_cb that you want to
execute */
callback->cb(event, callback->data):
C-BitFields
20
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Reference:
[Link]
Syntax
struct-declarator:
declarator
type-specifier Declaratoropt : constant-expression
Unnamed bit fields can't be referenced, and their contents at run-time are
unpredictable. They can be used as "dummy" fields for alignment purposes. An
unnamed bit-field whose width is 0 guarantees that storage for the member following
it in the struct-declaration-list begins on an int boundary.
The number of bits in a bit field must be less than or equal to the size of the
underlying type.
21
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
The array contains 2,000 elements. Each element is an individual structure containing
four bit-field members: icon, color, underline, and blink. Each structure is 2 bytes in
size.
Bit fields have the same semantics as the integer type. A bit field is used in
expressions exactly as a variable of the same base type would be used. It doesn't
matter how many bits are in the bit field.
Microsoft Specific
Bit fields defined as int are treated as signed. A Microsoft extension to the ANSI C
standard allows char and long types (both signed and unsigned) for bit fields. Unnamed
bit fields with base type long, short, or char (signed or unsigned) force alignment to a
boundary appropriate to the base type.
Bit fields are allocated within an integer from least significant to most-significant bit.
In the following code:
Since the 8086 family of processors stores the low byte of integer values before the
high byte, the integer 0x01F2 would be stored in physical memory as 0xF2 followed
by 0x01. The ISO C99 standard lets an implementation choose whether a bit field
may straddle two storage instances. Consider this structure, which stores bit fields
that total 64 bits:
A standard C implementation could pack these bit fields into two 32-bit integers. It
might store tricky_bits.may_straddle as 16 bits in one 32-bit integer
and 14 bits in the next 32-bit integer. The Windows ABI convention packs bit
fields into single storage integers and doesn't straddle storage units. The Microsoft
compiler stores each bit field in the above example to fit entirely in a 32-bit integer.
In this case, the first and second are stored in one integer, and may_straddle is
22
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
stored in a second integer, while the last is stored in a third integer. The sizeof
operator returns 12 on an instance of tricky_bits.
ANSI [Link] The padding and alignment of members of structures and whether a
bit-field can straddle a storage-unit boundary
Structure members are stored sequentially in the order in which they are declared:
the first member has the lowest memory address, and the last member the highest.
Every data object has an alignment requirement. The alignment requirement for all
data except structures, unions, and arrays is either the object's size or the current
packing size (specified with either /Zp or the pack pragma, whichever is less). For
structures, unions, and arrays, the alignment requirement is the largest alignment
requirement of its members. Every object is allocated an offset so that
offset % alignment-requirement == 0
Adjacent bit fields are packed into the same 1-, 2-, or 4-byte allocation unit if the
integral types are the same size and if the next bit field fits into the current
allocation unit without crossing the boundary imposed by the common alignment
requirements of the bit fields.
23
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Function Pointers in C
The function name is Nothing but a simple
regular variable
Function pointers in C hold function addresses, allowing direct calls. Declared with an
asterisk and function parameters, they enable callbacks and array integrations. This
article covers their declaration, use, and the concept of functions as memory-resident
entities.
A function pointer in C is helpful to generate function calls to which they point. Hence,
the programmers can pass them as arguments. The function pointers enhance the
code’s readability. You can access many identical functions using a single line of code.
24
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
For example, in the above figure, we have a function add() to add two integer
numbers. Here, the function name points to the function's address, so we are using a
function pointer fptr that stores the address of the beginning of the function
add(a, b), which is 1001 in this case.
25
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
/*
assigning the address of the function (foo)
to function pointer
*/
foo_pointer = foo;
Here, pointer *foo_pointer is a function pointer that stores the memory address of
a function foo, takes two arguments of type int, and returns a value of data type float.
Tricky example
void *(*fp) (int *, int *);
At first glance, this example seems complex, but the trick to understanding such
declarations is to read them inside out. Here, (*fp) is a function pointer like a
regular one as like int *ptr. This function pointer (*fp) can point to functions
with two int * type arguments and has a return type of void *, as we can see from
its declaration where (int *, int *) explains the type and number of arguments
and void * is the return type from the pointed function.
Calling a function using a pointer is similar to calling a function in the usual way using
the function's name.
pointer = areaSquare;
To call the function areaSquare, we can create a function call using any of
the three ways:
26
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
int length = 5;
The effect of calling functions using pointers or their names is the same. It is
not compulsory to call the function with the indirection operator (*) as shown in
the second case. Still, it is good practice to use the indirection operator to clear out
that the function is called using a pointer as (*pointer)() is more readable when
compared to calling function from pointers with parentheses pointer().
Now that we know the syntax for declaring and using function pointers in C to create a
function call, let's see an example of creating a function pointer to call the function
that returns the area of a rectangle.
27
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
#include<stdio.h>
// function declaration
int areaRectangle(int, int);
int main()
{
int length, breadth, area;
Output
5 9
Area of rectangle = 45
Here, we have defined a function areaRectangle() that takes two integer inputs
and returns the area of the rectangle. To store the reference of the function, we use
a function pointer (*fp) that has a declaration similar to the function it points to.
To point the function address to the pointer, we don't need to use the & symbol as
the function name areaRectangle also represents the function's address. To call the
function, we pass parameters inside the parenthesis ((*fp)(length, breadth)), and the
return value is stored in the variable area.
28
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Arrays are data structures that store collections of identical data types. Like any
other data type, we can create an array to store function pointers in C.
Function pointers can be accessed from their indexes like we access normal
array values arr[i]. This way, we create an array of function pointers,
where each array element stores a function pointer pointing to different
functions.
This approach is useful when we do not know in advance which function is called,
as shown in the example.
#include<stdio.h>
int main() {
int a, b;
operation[0] = add;
operation[1] = subtract;
operation[2] = multiply;
operation[3] = divide;
return 0;
}
float add(int a, int b) {
return a + b;
}
float subtract(int a, int b) {
return a - b;
}
float multiply(int a, int b) {
29
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
return a * b;
}
float divide(int a, int b) {
return a / (b * 1.0);
}
Output
30
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Abstraction is generally The process of working with ideas rather than their
implementation.
Abstraction in OOP is one of the essential vital features, which hides its internal and
other implementation details and cleanly separates its interface from the
implementation of the different modules. In other words, the user will have just the
knowledge of what an entity is doing instead of its internal workings.
In OOP, we can achieve Data Abstraction using Abstract classes and interfaces.
Interfaces allow 100% abstraction (complete abstraction). Interfaces will enable you to
abstract the implementation thoroughly.
Abstract classes allow 0 to 100% abstraction (partial to complete abstraction) because
they can contain concrete methods whose implementation results in a partial
abstraction.
Abstract Classes:
31
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
1. List ADT
The List Abstract Data Type is a type of list that contains similar elements in sequential
order. The list ADT is a collection of elements that have a linear relationship with each
other. A linear relationship means that each list element has a unique successor.
The List ADT is an interface; other classes give the actual implementation of the data
type. For example, Array Data Structure internally implements the ArrayList class,
while List Data Structure internally implements the LinkedList class.
32
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
❖ get(int index): Returns an element at the specified index from the list.
❖ insert(): Inserts an element at any position.
❖ remove(): Removes the first occurrence of any component from a list.
❖ removeAt(): Removes the element at a predefined area from a non-empty list.
❖ Replace(): Replaces an element with another element.
❖ size(): Returns the number of elements of the list.
❖ isEmpty(): Returns true if the list is empty; otherwise, it returns false.
❖ isFull(): Returns true if the list is full; else, returns false.
Stack ADT
A stack is a LIFO (“Last In, First Out”) data structure with similar elements arranged in
an ordered sequence. All the operations in the stack take place at the top of the stack.
33
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
The below diagram shows the whole structure of the Stack ADT:
Queue ADT
A Queue is a FIFO (“First In, First Out”) data structure containing similar elements
arranged sequentially. We can perform the operations on a queue at both ends; insertion
takes place at the rear end, and deletion takes place at the front end.
Queue ADT is a collection in which the arrangement of the elements of the same type is
sequential.
❖ The Queue abstract data type (ADT) design is the same as the basic design of the
Stack ADT.
❖ Each node of the queue contains a void pointer to the data and a link pointer to the
next element of the queue. The program allocates the memory for storing the data.
34
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
We must choose good operations to design an abstract data type and determine how
they should behave. Here are a few rules for developing an ADT.
❖ Combining simple and few operations in powerful ways rather than many complex
operations is better.
❖ Each operation in an Abstract Data Type should have a clear purpose and logical
behavior rather than a range of exceptional cases. All the special cases would make
the operation difficult to understand and use.
❖ The set of operations should be adequate so that there are enough kinds of
computations that users likely want to do.
❖ The type may be either generic, such as a graph, list, or set, or domain-specific,
such as an employee database, a street map, a phone book, etc. However, it should
not combine generic and domain-specific features.
Prerequisite:
❖Arrays have 0 as the first index, not 1. In this example, array[0] is the first element.
Array[0] = 2, 2 is the value of the 1st index.
❖If the size of an array is n, to access the last element, the n-1 index is used. In this
example, our array size is 6, but the last element is array[5]
35
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
❖Suppose the starting address of Array[0] is 2120d. Then, the address of the array[1]
will be 2124d. Similarly, the address of Array[2] will be 2128d, and so on.
This is because the size of an int is 4 bytes. (address according to the data type)
// Program to take 5 values from the user and store them in an array
// Print the elements stored in the array
#include <stdio.h>
int main() {
int values[5];
printf("Enter 5 integers: ");
// taking input and storing it in an array
for(int i = 0; i < 5; ++i) {
scanf("%d", &values[i]);
}
printf("Displaying integers: ");
// printing elements of an array
for(int i = 0; i < 5; ++i) {
printf("%d\n", values[i]);
}
return 0;
}
Output:
36
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Pointer:
A pointer is a programming concept used in computer science to reference or point to a memory
location that stores a value or an object. It is a variable that stores the memory address of
another variable or data structure rather than storing the data itself.
#include <stdio.h>
int main(){
int var; // initialization of a variable.
var =5; // declaration of a variable.
printf("value of the variable = %d \n",var);
printf("address of the variable = %d \n",&var);
return 0;
}
Output:
After initializing, int *ptr; (ptr is a pointer variable which points to an address which
holds the value of type integer)
ptr -> ptr is a pointer variable that holds the address. ptr == &var
*ptr -> This holds the value of the pointing address. *ptr == var
* -> The * operator denotes the pointer's underlying value. This is known as
"dereferencing" or "indirect"
37
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
#include <stdio.h>
int main()
{
//We can declare pointers in various ways, such as
int *ptr;
int var;
ptr = &var; //correct assigning.
Output:
We can change the value of a variable, and after changing, the pointer will still show the
correct value, as the pointer (ptr) only takes and stores the address of the variable.
38
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
#include <stdio.h>
int main()
{
//We can declare pointers in various ways, such as
int *ptr, var;
var = 5; ptr = &var;
Output:
We can change the value of a variable through the pointer as *ptr holds the value.
int *ptr;
int var;
var = 5;
ptr = &var;
39
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Output:
#include <stdio.h>
int main()
{
int *ptr, var;
var = 20;
ptr = &var;
printf ("value of the variable = %d \n",*ptr);
++*ptr; //incrementing the value of the variable.
printf ("value of the variable after incrementation = %d \n",*ptr);
40
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Linked List
41
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
A linked list is like a chain, where each link (or node) holds an item and a reference (or link)
to the next item in the list. This allows you to connect many items together in a sequence,
making it easy to add, remove, or rearrange them as needed.
IM – intermediate
Each node points to the next and the previous node, traversing quickly in both
directions.
The last node connects to the first node, creating a closed loop.
42
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Sample:
struct student
{
uint32_t id;
struct student *next;
struct student *prev;
};
struct student *head, *std, *tail;
std = (struct
student*)malloc(sizeof(struct
student));
head = std;
head -> id = 1;
head -> next = NULL;
head -> prev = NULL;
1. Addition
43
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
To add a new node after the list we have to make the node tail, as it’s now the last element of
the list.
To add a new node before the list, we have to make the node head, as it’s now the first element
of the list.
44
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
We must connect the node with its previous and next nodes to add a new node in the middle of
the list.
*Some information will be provided on where to add the new node(index or after a value). *
45
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
To delete a new node in the middle of the list, we have to make the node’s previous and next
nodes connect with each other’s.
*Some information will be provided on where to delete the node (index or after a value).
Curr = head ; //then traverse through the list and reach the target
curr->prev->next = curr->next;
//now the node before the deleted node will point the node after the deleted
node.
curr->next->prev = curr->prev;
free(curr);
Binary tree:
A binary tree is a tree data structure in which each parent node can have at most two children.
Each node of a binary tree consists of three items:
❖ data item
❖ address of the left child
❖ address of the right child
A full Binary tree is a particular type of binary tree in which every parent node/internal
node has two or no children.
46
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
A perfect binary tree is one in which every internal node has exactly two child nodes, and all
the leaf nodes are at the same level.
A complete binary tree is just like a full binary tree but with two significant differences.
47
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
A skewed binary tree is a pathological/degenerate tree in which the left or right nodes
dominate the tree. Thus, there are two skewed binary trees: left-skewed binary trees
and right-skewed binary trees.
It is a binary tree in which the difference between the height of the left and the right
subtree for each node is 0 or 1.
48
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
struct binarytree {
int item;
struct binarytree* left; //pointer to keep track of left items
struct binarytree* right; //pointer to keep track of left items
};
49
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
int main() {
struct binarytree* root = createNode(1);
insertLeft(root, 2);
insertRight(root, 3);
insertLeft(root->left, 4);
Output:
// Inorder traversal
void inorderTraversal(struct binarytree* root) {
if (root == NULL) return;
inorderTraversal(root->left);
printf("%d ->", root->item);
inorderTraversal(root->right);}
Output:
50
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
2. Traverse root to left child till leaf, then last right child till leaf
// Preorder traversal
preorderTraversal(root->left);
preorderTraversal(root->right);
}
Output:
3. Traverse the last left child(leaf) to root, then the last right child(leaf) to root, and
print the root at the end.
// Postorder traversal
51
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Output:
52
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Graph Theory
Directed graph:
In mathematics, and more specifically in graph theory, A directed graph (or digraph) is a graph
made up of vertices connected by directed edges, often called arcs.
53
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Graph Traversal:
Graph Traversal means visiting every vertex and edge exactly once in a well-defined
order. When using specific graph algorithms, this must be ensured. The order in which
the vertices are visited is essential and may depend upon the algorithm or question.
Tracking which vertices have been visited during a traversal is necessary. The most
common way of tracking vertices is to mark them.
54
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
❖ First, move horizontally and visit all the nodes of the current layer.
❖ Move to the next layer.
Unlike trees, Graphs may contain cycles so we may return to the same node. We divide
the vertices into two categories to avoid processing a node more than once.
❖Visited and
❖Non visited
A boolean visited array is used to mark the visited vertices.
Pseudo Code:
55
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Analysis:
Simulation of BFS:
Here is the illustration drawn with the help of a queue and visited array.
56
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
using std::vector;
#define MAX_VERTICES 20
/*!
Structure for creating Queue
*/
struct Q_Node
{
int v;
struct Q_Node *next;
};
int s = 0;
/*!
Declaring vector and array to store the graph and keep track to the visited
status.
*/
vector<int> v[MAX_VERTICES];
int level[MAX_VERTICES];
bool vis[MAX_VERTICES];
vector<int> visList;
/*!
57
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
while (!isEmpty()){
int p = peek();
dequeue();
for (int i = 0; i < v[p].size(); ++i){
if (vis[v[p][i]] == false){
level[v[p][i]] = level[p] + 1;
enqueue(v[p][i]);
vis[v[p][i]] = true;
visList.push_back(v[p][i]);
}
}
}
}
int main()
{
v[0].push_back(1);
v[0].push_back(2);
v[0].push_back(3);
v[0].push_back(4);
v[1].push_back(11);
v[1].push_back(12);
v[1].push_back(0);
v[2].push_back(5);
v[2].push_back(6);
v[2].push_back(0);
v[3].push_back(9);
v[3].push_back(10);
v[3].push_back(0);
v[4].push_back(7);
v[4].push_back(8);
v[4].push_back(0);
v[11].push_back(1);
v[12].push_back(1);
v[5].push_back(2);
v[6].push_back(2);
v[9].push_back(3);
v[10].push_back(3);
58
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
v[7].push_back(4);
v[8].push_back(4);
v[7].push_back(15);
v[15].push_back(7);
BFS(0);
printf("Visited List Order : ");
59
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
}
/*!
Returns the value of the first element of the queue
*/
int peek()
{
return head->v;
}
/*!
Returns the size of the queue
*/
int sizee()
{
return s;
}
/*!
Returns status of the queue Emptiness
*/
bool isEmpty()
{
if (s == 0)
{
return true;
}
else
{
return false;
}
}
Output:
60
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
DFS Pseudocode:
DFS (G, u)
[Link] = true
for each v ∈ [Link][u]
if [Link] == false
DFS(G,v)
Init () {
For each u ∈ G
[Link] = false
For each u ∈ G
DFS (G, u)
}
61
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Table Of Contents
Macro
Inline Function
Callback Function
Function Pointer
Bit field in c
Reference: [Link]
62
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Macros
Syntax of a Macro:
#define macro_name macro_value;
Example Program:
#include <stdio.h>
#define MACRO 10 //macro definition
int main(){
printf("the value of a is: %d", MACRO);
return 0;
}
63
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Inline Function
By declaring a function inline, you can direct GCC to make calls to that function
faster. One way GCC can achieve this is by integrating that function's code into the code
for its callers. This makes execution faster by eliminating the function-call overhead; if
any of the actual argument values are constant, their known values permit simplifications
at compile time so that not all of the inline function's code needs to be included.
Depending on the case, the effect on code size is less predictable; object code may be
larger or smaller with function inlining.
A C program can be optimized with two goals: to reduce the Code size or to get the
best performance (time). Usually, these are two opposite ends of the line. To
reduce the code size, the program is optimized so that it compromises performance
to an extent. With a compiler set to optimize for performance in terms of execution
time, the generated binary is usually of higher code size. Since it can be
requirement-dependent, it is usually a trade-off between what fits the requirement.
inline functions:
By declaring a function inline, you can direct GCC to make calls to that function faster.
One way GCC can achieve this is by integrating that function's code into the code for its
callers. This makes execution faster by eliminating the function-call overhead; if any of
the actual argument values are constant, their known values permit simplifications at
compile time so that not all of the inline function's code needs to be included. Depending
on the case, the effect on code size is less predictable; object code may be larger or
smaller with function inlining.
So, it tells the compiler to build the function into the code where it is used to improve
execution time.
64
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
If you declare small functions like setting/clearing a flag or some bit toggle
performed repeatedly inline, it can make a significant performance difference with
respect to time, but at the cost of code size.
When an inline function is not static, then the compiler must assume that there may be
calls from other source files; since a global symbol can be defined only once in any
program, the function must not be defined in the other source files, so the calls therein
cannot be integrated. Therefore, a non-static inline function is always compiled in the
usual fashion.
❖ extern inline?
If you specify both inline and extern in the function definition, then the definition is
used only for inlining. The function is not compiled independently, even if you refer to its
address explicitly. Such an address becomes an external reference as if you had only
declared the function and had not defined it.
This combination of inline and extern has almost the effect of a macro. It is used to put
a function definition in a header file with these keywords and put another copy of the
definition (lacking inline and extern) in a library file. The definition in the header file
causes most calls to the function to be inlined. If any uses of the function remain, they
refer to the single copy in the library.
Executive Summary
65
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
1. For inline void f(void){}, inline definition is only valid in the
current translation unit.
2. For static inline void f(void) {} Since the storage class is static,
the identifier has internal linkage, and the inline definition is invisible in other
translation units.
3. For extern inline void f(void), Since the storage class is extern, the
identifier has external linkage, and the inline definition also provides the
external definition.
66
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Callback Function
[Link]
mplemented
Here, the populate_array function takes a function pointer as its third parameter, and
calls it to get the values to populate the array with. We've written the callback
getNextRandomValue, which returns a random-ish value, and passed a pointer to it to
populate_array. populate_array will call our callback function 10 times and assign the
returned values to the elements in the given array.
You want to write some code that allows registering callback to be called when some event
occurs. First, define the type of function used for the callback:
This is what the code would look like that registers a callback
67
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
event_cb_register(my_event_cb, &my_custom_data); …
In the internals of the event dispatcher, the callback may be stored in a struct that
looks something like this:
struct event_cb *callback; ... /* Get the event_cb that you want to
execute */
callback->cb(event, callback->data):
68
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
C-BitFields
Reference: [Link]
Syntax
struct-declarator:
declarator
type-specifier Declaratoropt : constant-expression
The constant-expression specifies the width of the field in bits. The type-specifier
for the declarator must be unsigned int, signed int, or int, and the constant-expression must be
a nonnegative integer value. If the value is zero, the declaration has no declarator. Arrays of
bit fields, pointers to bit fields, and functions returning bit fields aren't allowed. The optional
declarator names the bit field. Bit fields can only be declared as part of a structure. The
address-of operator (&) can't be applied to bit-field components.
Unnamed bitfields can't be referenced, and their contents at run-time are unpredictable.
They can be used as "dummy" fields for alignment purposes. An unnamed bit-field whose width
is 0 guarantees that storage for the member following it in the struct-declaration-list
begins on an int boundary.
The number of bits in a bit field must be less than or equal to the size of the
underlying type.
The array contains 2,000 elements. Each element is an individual structure containing four
bit-field members: icon, color, underline, and blink. Each structure is 2 bytes in size.
69
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Bit fields have the same semantics as the integer type. A bit field is used in expressions
exactly as a variable of the same base type would be used. It doesn't matter how many bits are
in the bit field.
Microsoft Specific
Bit fields defined as int are treated as signed. A Microsoft extension to the ANSI C standard
allows char and long types (both signed and unsigned) for bit fields. Unnamed bit fields with
base type long, short, or char (signed or unsigned) force alignment to a boundary appropriate to
the base type.
Bit fields are allocated within an integer from least-significant to most-significant bit. In the
following code:
Since the 8086 family of processors stores the low byte of integer values before the high
byte, the integer 0x01F2 would be stored in physical memory as 0xF2 followed by 0x01. The
ISO C99 standard lets an implementation choose whether a bit field may straddle two storage
instances. Consider this structure, which stores bit fields that total 64 bits:
A standard C implementation could pack these bit fields into two 32-bit integers. It might
store tricky_bits.may_straddle as 16 bits in one 32-bit integer and 14
bits in the next 32-bit integer. The Windows ABI convention packs bit fields into
single storage integers and doesn't straddle storage units. The Microsoft compiler stores
each bit field in the above example to fit entirely in a 32-bit integer. In this case, the
first and second are stored in one integer, may_straddle is stored in a second integer, and
the last is stored in a third integer. The sizeof operator returns 12 on an instance of
tricky_bits.
70
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
ANSI [Link] The padding and alignment of members of structures and whether a bit-field can
straddle a storage-unit boundary
Structure members are stored sequentially in the order in which they are declared: the first
member has the lowest memory address, and the last member has the highest.
Every data object has an alignment requirement. The alignment requirement for all data except
structures, unions, and arrays is either the object's or the current packing size (specified with
either /Zp or the pack pragma, whichever is less). For structures, unions, and arrays, the
alignment requirement is the largest alignment requirement of its members. Every object is
allocated an offset so that
offset % alignment-requirement == 0
Adjacent bit fields are packed into the same 1-, 2-, or 4-byte allocation unit if the integral
types are the same size and if the following bit field fits into the current allocation unit
without crossing the boundary imposed by the standard alignment requirements of the bit
fields.
71
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Function Pointers in C
The function name is Nothing but a simple regular
variable
Function pointers in C hold function addresses, allowing direct calls. Declared with an asterisk
and function parameters, they enable callbacks and array integrations. This article covers their
declaration, use, and the concept of functions as memory-resident entities.
A function pointer in C is a variable that stores the address of a function. It allows you to
refer to a function by using its pointer and later call the function using that function pointer.
This provides flexibility in calling functions dynamically and can be useful in scenarios where
you want to select and call different functions based on certain conditions or requirements.
The function pointers in C are declared using the asterisk (*) operator to obtain the value
saved in an address.
A function pointer in C helps generate function calls to which they point. Hence, the
programmers can pass them as arguments. The function pointers enhance the code’s
readability. You can access many identical functions using a single line of code.
72
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
For example, in the above figure, we have a function add() to add two integer numbers. Here,
the function name points to the function's address, so we use a function pointer fptr that
stores the address of the beginning of the function add(a, b), which is 1001 in this case.
73
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
/*
assigning the address of the function (foo)
to function pointer
*/
foo_pointer = foo;
Here, pointer *foo_pointer is a function pointer that stores the memory address of a
function foo, takes two arguments of type int, and returns a value of data type float.
Tricky example
void *(*fp) (int *, int *);
At first glance, this example seems complex, but the trick to understanding such declarations
is to read them inside out. Here, (*fp) is a function pointer like a normal C pointer, like int
*ptr. This function pointer (*fp) can point to functions with two int * type arguments
and has a return type of void *, as we can see from its declaration where (int *, int *)
explains the type and number of arguments and void * is the return type from the pointed
function.
Calling a function using a pointer is similar to calling a function in the usual way using the
function's name.
pointer = areaSquare;
To call the function areaSquare, we can create a function call using any of the three
ways:
74
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
int length = 5;
The effect of calling functions using pointers or their names is the same. It is not
compulsory to call the function with the indirection operator (*), as shown in the second
case. Still, it is good practice to use the indirection operator to clear out that the function is
called using a pointer as (*pointer)() is more readable when compared to calling function
from pointers with parentheses pointer().
Now that we know the syntax of how function pointers in C are declared and used to create a
function call. Let us see an example where we are creating a function pointer to call the
function that returns the area of a rectangle.
75
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
#include<stdio.h>
// function declaration
int areaRectangle(int, int);
int main()
{
int length, breadth, area;
Output
5 9
Area of rectangle = 45
Here, we have defined a function areaRectangle() that takes two integer inputs and returns
the area of the rectangle. To store the reference of the function, we use a function
pointer (*fp) that has a declaration similar to the function it points to. To point the
function address to the pointer, we don't need to use & symbol as the function name
areaRectangle also represents the function's address. To call the function, we pass parameters
inside the parenthesis ((*fp)(length, breadth)), and the return value is stored in the variable
area.
76
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Arrays are data structures that store collections of identical data types. Like any other data
type we can create an array to store function pointers in C. Function pointers can be
accessed from their indexes like we access normal array values arr[i]. This way, we
create an array of function pointers, where each array element stores a function
pointer pointing to different functions.
This approach is useful when we do not know in advance which function is called, as shown
in the example.
#include<stdio.h>
int main() {
int a, b;
operation[0] = add;
operation[1] = subtract;
operation[2] = multiply;
operation[3] = divide;
return 0;
}
77
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
Output
To be continued … …
DStructCSD Compiler
78
Towards the Core of Computer Science:
Storing, organizing and retrieving the data from the memory
79