๐C/C++
C Fundamentals
Welcome to the C Fundamentals course. In this course, we will cover the basics of the C programming language, as well as some more advanced topics. We will start by discussing how to create variables, use conditions and loops, and import libraries. By the end of this course, you should have a solid understanding of the basics of C and be ready to start writing your own programs.
Variables
In C, a variable is a way to store a value or a reference to an object. To create a variable, you need to declare it with a specific data type and give it a name, for example:
This creates a variable named x with the data type int
and assigns it the value of 5.
float
is used for floating-point numbers.char
is used for single characters.double
is used for double-precision floating-point numbers.unsigned int
is used for non-negative integers.short int
is used for short integers.long int
is used for long integers.
Vector (C++)
In C++, vectors are dynamic arrays that provide flexibility in managing collections of elements.
push_back
: Appends a new element to the end of the vector.pop_back
: Removes the last element from the end of the vector.insert
: Inserts elements at a specified position in the vector.erase
: Removes elements from the vector at a specified position or within a range.clear
: Removes all elements from the vector, leaving it with a size of 0.size
: Returns the number of elements in the vector.empty
: Checks if the vector is empty.resize
: Changes the size of the vector, optionally filling new elements with a specified value.front
: Returns a reference to the first element in the vector.back
: Returns a reference to the last element in the vector.
Let's look at an example:
Vector Declaration:
std::vector<int> myVector;
declares a vector namedmyVector
that can store integers.Adding Elements:
myVector.push_back(10);
adds the value 10 to the end of the vector. Similarly, we add 20 and 30.Accessing Elements: The
for
loop iterates through the vector using its size and prints each element.
This example demonstrates the basic usage of vectors, including declaration, addition of elements using push_back
, and accessing elements using an index. Vectors in C++ provide dynamic sizing and convenient methods for managing collections.
Conditions
Conditions are used to make decisions in a program. The most common type of condition is the if-else statement. For example:
This code checks if the value of x is greater than 0. If it is, the program will print "x is positive", otherwise it will print "x is not positive".
Loops
Loops are used to repeat a block of code multiple times. The two most common types of loops in C are the for loop and the while loop.
The for loop is used to execute a block of code a fixed number of times. For example:
This code will print the numbers from 0 to 4, because the condition (i < 5) is true for each iteration of the loop.
The while loop is used to execute a block of code as long as a certain condition is true. For example:
This code will print the numbers from 5 down to 1, because the condition (x > 0) is true for each iteration of the loop.
Libraries
C has a large number of libraries that can be imported to add additional functionality to your programs. To import a library, you use the #include
preprocessor directive followed by the name of the library. For example:
This imports the standard input/output library, which provides functions such as printf()
and scanf()
.
Once a library is imported, you can use its functions by referencing them with the library name as a prefix. For example:
This code imports the standard input/output library and then uses the printf() function to print the string "Hello, World!" on the screen.
Pointers
Pointers are one of the most powerful features of C, they allow you to directly manipulate memory and access variables by their memory address. Pointers are declared using the *
operator, for example:
This declares a pointer ptr
that points to the memory address of the variable x
. You can then use the pointer to manipulate the value of the variable it points to, or to allocate and deallocate memory dynamically during runtime.
The first example uses the pointer ptr
to change the value of the variable x
and the second one uses the malloc()
function to dynamically allocate memory for an integer and the free()
function to deallocate the memory once it's no longer needed.
This code demonstrates the use of pointers in C. It defines three functions, each of which takes a pointer as its argument. The first function, edit_int
, takes a pointer to an integer and changes its value to 128
. The second function, edit_char
, takes a pointer to a character and changes its value to Z
. The third function, edit_string
, takes a pointer to a pointer to a character and changes the value of the pointer to a new string Foxtrot
. The main function declares an integer, a character, and a string, and passes pointers to each of them to the corresponding functions. It then prints out the original and modified values of each variable.
Structures
Structures are a way of grouping together different variables of different data types, similar to objects in object-oriented languages. They allow you to create custom data types with several fields, for example:
This defines a new data type named Person
with three fields: a character array named name
, an integer named age
, and a float named salary
.
In this example, the program creates a new Person
structure named person
. The program prompts the user to enter the person's name, age, and salary, and then stores the input in the appropriate fields of the person
structure. Finally, the program prints out the person's information using the printf()
function.
Functions
Functions in C work similarly to how they do in other programming languages, they allow you to define a block of code that can be reused multiple times in your program. Functions in C must be declared before they are used, this is done by writing a function prototype that specifies the return type, name and parameters of the function.
In C, a function is a self-contained block of code that performs a specific task. Functions are used to divide a large program into smaller, manageable parts. Each function has a name, parameters, and a return type, and it can be called (invoked) from other parts of the program.
Function Definition
A function in C is defined with the following syntax:
return_type: Specifies the type of data that the function will return. If a function doesn't return anything, you can use
void
as the return type.function_name: The name of the function, which should be a unique identifier within the program.
parameter_type: The type of each parameter the function accepts.
parameter_name: The name of each parameter used to reference values passed to the function.
Function body: Contains the code that defines what the function does.
return_value: The value to be returned by the function. If the return type is
void
, this part is omitted.
Example: add
Function
add
FunctionLet's look at an example of a simple add
function that takes two integers and returns their sum:
In this example:
int
is the return type, indicating that the function will return an integer.add
is the function name.(int a, int b)
are the parameters. The function takes two integer parameters,a
andb
.The function body calculates the sum of
a
andb
and returns the result (sum
variable) using thereturn
statement.
Function Prototypes
Before you use a function in C, it must be declared or defined. To declare a function, you can provide a function prototype. A function prototype specifies the function's name, return type, and parameters without defining the full function. This allows you to use the function before its actual implementation.
Here's a function prototype for the add
function:
This prototype informs the compiler that there is a function called add
that takes two integers as parameters and returns an integer. You can place function prototypes at the beginning of your source code or include them in header files for use in multiple source files.
Using the add
Function
add
FunctionTo use the add
function in your program, you can call it from the main
function:
In this code, we include the <stdio.h>
header for the printf
function and call the add
function to calculate the sum of 5 and 3.
We've covered the basics of functions in C, including their definition, parameters, return values, and function prototypes. Functions are an essential part of C programming, enabling code organization, reusability, and modularity. They allow you to break down complex tasks into manageable components, making your code more readable and maintainable.
Class (C++)
Classes are an essential part of object-oriented programming, and they allow you to create custom data types and encapsulate both data and behavior into a single unit. We'll use the example code you provided as a starting point to explain various concepts related to C++ classes.
What is a Class?
In C++, a class is a blueprint for creating objects. It defines the structure and behavior of objects that will be created based on it. A class can contain data members (also called attributes or properties) and member functions (methods) that operate on these data members.
Example: Auth Class
Let's start by examining the code you provided. The Auth
class represents a simple authentication system with a predefined username and password. Here's the code with explanations:
In this code, we define a class called Auth
, which contains:
Private Data Members: The
username
andpassword
are private data members of the class, which means they can only be accessed within the class itself. This encapsulates sensitive information, making it inaccessible from outside the class.Public Member Function: The
login
function is a public member function that allows external code to attempt a login. It takes two arguments,usr
(the entered username) andpwd
(the entered password). It compares these values with the stored username and password, and if they match, it returnstrue
, indicating a successful login; otherwise, it returnsfalse
.
Using the Auth Class
The main
function demonstrates how to create an instance of the Auth
class and use it for authentication:
In this main
function, we perform the following steps:
Prompt the user for a username and password.
Create an instance of the
Auth
class namedauth
.Call the
login
method of theauth
instance to attempt authentication.Based on the result of the
login
method, display a message indicating whether the login was successful or not.
Header files
C also allows you to create your own libraries, also called header files, which can be included in your program to reuse code and organize your program in a more modular way. To create a library, you can create a header file with the extension .h
that contains the function prototypes and any global variables or constants. Then, in a separate file with the extension .c
, you can provide the implementation of the functions.
By the end of this course, you should have a good understanding of the C programming language and be able to write programs that make use of variables, conditions, loops, functions, pointers, structures, dynamic memory allocation, and more.
Bitwise operations
C provides a set of bitwise operators such as &
, |
, ^
, ~
, <<
, and >>
that allow you to manipulate individual bits of a variable. These operators can be used to optimize certain types of algorithms, perform low-level operations on hardware, or encode and decode data.
In this example, the &
operator is used to perform a bitwise AND operation on the variables x
and y
, resulting in a new variable z
with the value 2 (binary: 00000010).
typedef
In C, the typedef
keyword is a powerful tool that allows you to create your own custom data types, giving you the ability to enhance code readability and maintainability. This course will explain what typedef
is, how it works, and provide practical examples to help you understand its usage.
What is typedef
?
typedef
?In C, typedef
is a keyword used to define custom data types. It allows you to create aliases or synonyms for existing data types, making your code more readable and expressive.
Defining Custom Data Types
The syntax for creating a custom data type using typedef
is as follows:
existing_data_type
: The data type for which you want to create an alias.new_data_type
: The alias or synonym you want to create for the existing data type.
Using typedef
with Basic Data Types
typedef
with Basic Data TypesExample 1: Creating an Alias for int
int
In this example, we create an alias "Integer" for the int
data type. Now, you can use Integer
instead of int
in your code.
Example 2: Creating an Alias for char
char
Here, we create an alias "Character" for the char
data type.
Creating Complex Custom Types
You can also use typedef
to create complex custom data types. For instance:
Example 3: Creating a Structure Alias
In this example, we define a custom structure Date
and then create an alias MyDate
for it using typedef
.
Benefits of typedef
typedef
Improved Code Readability:
typedef
can make your code more descriptive and easier to understand by using meaningful names for data types.Easy Maintenance: If you need to change the underlying data type, you only have to update it in one place where the
typedef
is defined.Enhanced Portability: Using
typedef
can help make your code more portable since it abstracts the underlying data types, making it easier to adapt to different platforms.
Enum
In C, an enum
is a user-defined data type used to create a set of named integer constants. It provides a way to represent a set of values with meaningful names, making code more readable and maintainable. This course will explain what enum
is, how it works, and provide practical examples to help you understand its usage.
Enums, short for "enumerations," are a data type in C that allow you to create a set of named integral constants. They make your code more readable and maintainable by providing descriptive names for values rather than using raw numbers.
Declaring Enums
In C, you declare an enum using the enum
keyword followed by a list of constant names enclosed in curly braces.
In this example, Days
is the enum type, and the constants SUNDAY
, MONDAY
, etc., are assigned consecutive integer values starting from 0.
Accessing Enum Constants
You can access enum constants by using the enum type name followed by the constant name.
Enum Constants and Values
While the example above assigns integer values to enum constants by default, you can also explicitly set the values.
In this case, RED
will have a value of 1, GREEN
will have 2, and BLUE
will have 4.
Using Enums in Switch Statements
Enums are often used in switch statements for improved code readability.
Benefits of Enums
Readability: Enums make code more readable as constant names are self-explanatory.
Type Safety: You can't assign arbitrary values to an enum; it only accepts values defined within the enum.
Maintenance: When constants change, you only need to update the enum definition.
Compile-Time Constants: Enums are evaluated at compile-time.
Preprocessor Macros
C also provides a preprocessor that allows you to define macros using the #define
directive. Macros are a way to create simple and efficient substitutes for repetitive or complex expressions, or to define constants that can be easily changed later.
In this example, the first macro defines the constant PI as 3.14, and the second macro defines a MIN function that returns the minimum of two values.
Here's another helpful illustration:
In this instance, we are defining custom print and read functions (input
and output
) to simplify content display and input.
You can utilize them as follows:
Conditional Compilation
In C programming, you can instruct the preprocessor whether to include a block of code or not. To do so, conditional directives can be used.
It's similar to a if
statement with one major difference.
The if
statement is tested during the execution time to check whether a block of code should be executed or not whereas, the conditionals are used to include (or skip) a block of code in your program before execution.
Uses of Conditional
use different code depending on the machine, operating system
compile the same source file in two different programs
to exclude certain code from the program but to keep it as a reference for future purposes
How to use conditional?
To use conditional, #ifdef
, #if
, #defined
, #else
and #elif
directives are used.
ifdef Directive
Here, the conditional codes are included in the program only if MACRO
is defined.
#if, #elif and #else Directive
Here, expression is an expression of integer type (can be integers, characters, arithmetic expression, macros, and so on).
The conditional codes are included in the program only if the expression is evaluated to a non-zero value.
The optional #else
directive can be used with #if
directive.
You can also add nested conditional to your #if...#else
using #elif
#define
The special operator #defined is used to test whether a certain macro is defined or not. It's often used with #if directive.
Predefined Macros
Here are some predefined macros in C programming.
__DATE__
A string containing the current date.
__FILE__
A string containing the file name.
__LINE__
An integer representing the current line number.
__STDC__
If follows ANSI standard C, then the value is a nonzero integer.
__TIME__
A string containing the current time.
The following program outputs the current time using __TIME__
macro.
Unions
Unions are a special type of data structure in C that allows you to store different data types in the same memory location. This can be useful for creating efficient and flexible data structures, or for performing type punning.
In this example, a union named Number
is defined that can store an integer, a float, or a double in the same memory location.
File handling
C also provides a standard library for file handling, which allows you to read and write data from files using file streams. File streams are similar to the standard input and output streams, but they operate on files instead of the console.
In this example, the fopen()
function is used to open a file named "example.txt" in write mode, the fprintf()
function is used to write a string to the file, and the fclose()
function is used to close the file.
Pipes
Understanding Pipes
In C, a pipe is a form of interprocess communication (IPC) that allows two processes to communicate with each other. One process writes data to the pipe, while the other process reads the data from the pipe. A pipe can be thought of as a unidirectional data channel.
A pipe is created using the pipe()
function. This function takes an array of two integers as an argument, which represent the read and write ends of the pipe. The pipe()
function returns 0 on success and -1 on failure.
The pipefd
parameter is a two-element array that will be populated with the file descriptors for the read and write ends of the pipe. For example:
This code creates a pipe and stores the read and write file descriptors in pipefd
.
Using Pipes
Once a pipe has been created, the two processes can use it to communicate with each other. The process that wants to write data to the pipe writes to the write end of the pipe, while the process that wants to read data from the pipe reads from the read end of the pipe.
Here is an example of how to write data to a pipe:
This code creates a pipe, forks a child process, and then writes the string "Hello, world!" to the pipe from the child process. The parent process reads the string from the pipe and prints it to the console.
Pipes are an important form of interprocess communication in C. They provide a simple way for two processes to communicate with each other. In this course, we have covered the basics of how pipes work, how to create and use them, and provided some code examples to illustrate their usage. With this knowledge, you can start using pipes in your own C programs to facilitate communication between different processes.
Signals
Understanding Signals
Signals are an important concept in C programming, as they allow a process to be interrupted by the operating system when a certain event occurs. Some common events that can trigger signals include a user pressing Ctrl-C, the process running out of memory, or the process receiving a specific signal from another process.
When a signal is sent to a process, the process is interrupted and the signal handler function is called. The signal handler function is responsible for handling the signal and responding appropriately. This can include terminating the process, ignoring the signal, or performing some other action.
Signal Handling in C
Signal handling in C involves defining a signal handler function that will be called when a signal is received by the process. The signal()
function is used to set up the signal handler function, and takes two arguments: the signal number to handle, and the name of the signal handler function.
In the example above, we define a signal handler function sigint_handler()
that will be called when the SIGINT
signal is received. We then set up the signal handler function using the signal()
function. Finally, we enter an infinite loop that waits for signals to be received.
Sending Signals in C
Signals can also be sent from one process to another using the kill()
function. The kill()
function takes two arguments: the process ID of the receiving process, and the signal number to send.
In the example above, we use the kill()
function to send a signal to a process with a specified process ID. We take the process ID and signal number as command line arguments.
Handling Multiple Signals
It is possible to handle multiple signals in a single signal handler function using the sigaction()
function. The sigaction()
function allows us to specify a structure that contains information about how to handle the signal, including a pointer to the signal handler function.
In the example above, we define a signal handler function sig_handler()
that will be called when either the SIGINT
or SIGTERM
signal is received. We then use the sigaction()
function to set up the signal handler function for both signals.
Signals are an important mechanism for interprocess communication and handling events in C. By understanding how signals work, how to send and receive signals, and how to handle signals, you can write robust and reliable C programs that respond appropriately to events and signals sent by the operating system.
In this course, we have covered the basics of signals in C, including how to handle single and multiple signals, and how to send signals to other processes. We encourage you to explore further and experiment with signals in your own C programs.
Semaphore
Introduction
Semaphore is a synchronization primitive in operating systems that allows multiple processes/threads to access shared resources in a mutually exclusive manner. Semaphore can be used to implement locks, mutual exclusion, and coordination between multiple processes/threads.
In this course, we will learn about semaphores in C programming language, including their definition, use, and implementation using code examples.
Definition
A semaphore is an integer value that is used to control access to a shared resource in a concurrent system. It consists of two operations:
Wait (also known as
P
ordown
): The wait operation decrements the value of the semaphore by 1. If the resulting value is negative, the process/thread is blocked until the semaphore value becomes positive again.Signal (also known as
V
orup
): The signal operation increments the value of the semaphore by 1. If there are any processes/threads waiting for the semaphore, one of them is unblocked.
Semaphore implementation in C
In C programming language, semaphores can be implemented using the sem_t
data type, which is defined in the semaphore.h
header file.
Creating a semaphore
To create a semaphore, we use the sem_init()
function, which takes three arguments:
sem
: A pointer to the semaphore variable that is to be initialized.pshared
: A flag that indicates whether the semaphore should be shared between multiple processes or not. A value of0
means that the semaphore is shared between threads of the same process, while a value of1
means that the semaphore is shared between multiple processes.value
: The initial value of the semaphore.
Here's an example:
In this example, we create a semaphore my_sem
with an initial value of 1
, which means that the first process/thread that tries to access the shared resource will be able to do so.
Waiting and signaling
To perform the wait and signal operations on a semaphore, we use the sem_wait()
and sem_post()
functions, respectively. Both functions take a pointer to the semaphore variable as their argument.
Here's an example that demonstrates the use of sem_wait()
and sem_post()
:
In this example, we create a semaphore my_sem
with an initial value of 1
. We then create a worker thread that waits for the semaphore using sem_wait()
, performs some work, and then signals the semaphore using sem_post()
. The main thread also waits for the semaphore using sem_wait()
, performs some work, and then signals the semaphore using sem_post()
. Both the main thread and the worker thread will be able to access the shared resource in a mutually exclusive manner.
Error handling
When working with semaphores, it is important to handle errors that may occur during initialization or operation. The sem_init()
, sem_wait()
, and sem_post()
functions all return 0
on success and -1
on failure, so we can use this to check for errors.
Here's an example:
In this example, we use the perror()
function to print an error message if sem_init()
, sem_wait()
, or sem_post()
fails. The errno
variable contains the error code that caused the failure.
In this course, we learned about semaphores in C programming language, including their definition, use, and implementation using code examples. Semaphores are a powerful synchronization primitive that can be used to implement locks, mutual exclusion, and coordination between multiple processes/threads. By understanding semaphores, you will be better equipped to design and implement concurrent systems that are correct, efficient, and reliable.
goto
In this chapter, we'll explore the goto
statement in C/C++. The goto
statement allows altering the flow of control in a program by transferring the execution to a labeled statement within the same function. However, it's essential to use goto
judiciously as its misuse can lead to less readable and more complex code.
Syntax
The syntax for goto
statement is straightforward:
Where label_name
is an identifier followed by a colon :
that marks the label in the code.
Example
Consider the following example:
Explanation
count
is initialized to 0.The
start
label is declared just before theprintf
statement.It prints the value of
count
, incrementscount
by 1, and checks ifcount
is less than 5.If
count
is less than 5, the program usesgoto start;
to jump back to thestart
label and repeats the process.Once
count
is not less than 5, the loop ends, and "End of the loop" is printed.
Output
Best Practices and Caution
Use sparingly: While
goto
can be useful in certain cases, overuse can lead to code that is hard to follow and maintain.Prefer other control structures: In most scenarios, loops (
for
,while
,do-while
) and conditional statements (if-else
) are more readable and maintainable thangoto
.
The goto
statement is a powerful control flow tool in C/C++ programming. However, it should be used cautiously and sparingly to ensure code readability and maintainability.
Conclusion
C is a powerful and versatile language that is widely used in systems programming, embedded systems, and high-performance computing. It's a great choice for low-level programming, and its popularity and wide availability make it an excellent choice for learning the fundamentals of programming. With this course, you should have a solid understanding of the basics of C and be ready to start writing your own programs and experimenting with advanced features of the language.
Last updated