Skip to content

Commit 159b8ec

Browse files
committed
2 parents 7a4734b + 5d999c1 commit 159b8ec

17 files changed

+1584
-0
lines changed

_posts/cs/2024-09-14-atoi-in-c.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
Title: atoi in c++
3+
layout: post
4+
title: atoi in c++
5+
---
6+
In C++, `atoi` stands for **ASCII to Integer**. It is a standard library function used to convert a C-style string (a `const char*`) representing a numeric value into an `int`.
7+
8+
### Usage
9+
The function is declared in the header `<cstdlib>` and its syntax is:
10+
11+
```cpp
12+
int atoi(const char *str);
13+
```
14+
15+
- `str`: A C-style string containing the numeric value to be converted.
16+
17+
### Example
18+
Here’s a simple example:
19+
20+
```cpp
21+
#include <iostream>
22+
#include <cstdlib> // for atoi
23+
24+
int main() {
25+
const char* str = "1234";
26+
int number = atoi(str);
27+
28+
std::cout << "The integer is: " << number << std::endl; // Outputs: The integer is: 1234
29+
return 0;
30+
}
31+
```
32+
33+
### Important Notes
34+
- **No Error Checking**: `atoi` does not handle errors well. If the input string is not a valid number, it returns `0`, which can lead to ambiguity if the string itself represents `0`.
35+
- **Safer Alternatives**: For better error handling and conversion, use `std::stoi` (C++11 and later) or functions like `std::strtol`.
36+
37+
### Summary
38+
`atoi` is a simple function for converting a C-style string to an integer but has limited error handling capabilities.
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
---
2+
Title: Understanding the Member Initializer List in C++
3+
layout: post
4+
title: the Member Initializer List in C++
5+
categories: programming
6+
---
7+
### Understanding the Member Initializer List in C++
8+
9+
When creating objects in C++, especially those with complex data members, efficiency matters. One way to make object initialization more efficient is through the **member initializer list**. This feature allows you to initialize class members directly before the constructor body executes, avoiding unnecessary default construction and subsequent assignments.
10+
11+
### What is a Member Initializer List?
12+
13+
A **member initializer list** is a part of the constructor definition that allows you to initialize class data members right after the constructor signature. It is introduced with a colon (`:`) followed by a comma-separated list of members and their values. This method is particularly useful for initializing constant members, references, and complex objects like vectors.
14+
15+
### Why Use a Member Initializer List?
16+
17+
Using a member initializer list provides several benefits:
18+
- **Efficiency**: It avoids unnecessary default construction and later assignment of values, making the process more efficient.
19+
- **Direct Initialization**: Members are initialized directly, which is required for certain types like `const` members or references.
20+
- **Cleaner Code**: Initialization code is separate from the constructor body, improving readability.
21+
22+
### Example 1: Using a Member Initializer List
23+
24+
Here’s a simple example that demonstrates the use of a member initializer list:
25+
26+
```cpp
27+
#include <iostream>
28+
#include <vector>
29+
30+
class Building {
31+
public:
32+
Building(int numberOfFloors)
33+
: floors(numberOfFloors, 0) { // Member initializer list
34+
std::cout << "Creating building with "
35+
<< numberOfFloors << " floors." << std::endl;
36+
}
37+
38+
private:
39+
std::vector<int> floors; // Vector of integers
40+
};
41+
```
42+
43+
In this code:
44+
- The `: floors(numberOfFloors, 0)` part is the member initializer list. It directly initializes the `floors` vector with `numberOfFloors` elements, each initialized to `0`.
45+
- This happens **before** the constructor's body executes, ensuring the vector is efficiently created with the desired size and values.
46+
47+
### Example 2: Without a Member Initializer List
48+
49+
Now, let's see what it looks like if we don't use a member initializer list:
50+
51+
```cpp
52+
#include <iostream>
53+
#include <vector>
54+
55+
class Building {
56+
public:
57+
Building(int numberOfFloors) {
58+
// Initialization in the constructor body
59+
floors = std::vector<int>(numberOfFloors, 0);
60+
61+
std::cout << "Creating building with "
62+
<< numberOfFloors << " floors." << std::endl;
63+
}
64+
65+
private:
66+
std::vector<int> floors; // Vector of integers
67+
};
68+
```
69+
70+
Here’s what happens in this version:
71+
- The `floors` vector is first default-constructed (i.e., it starts as an empty vector).
72+
- Then, in the constructor body, we assign a new vector with `numberOfFloors` elements, each set to `0`.
73+
- This two-step process is less efficient, as it involves creating an empty vector first and then assigning a new vector, potentially involving memory reallocation.
74+
75+
### When to Use a Member Initializer List
76+
77+
- When initializing complex data members like `std::vector`, `std::string`, or other classes.
78+
- For `const` data members and references, which must be initialized at the point of their declaration.
79+
- When you want to avoid unnecessary default construction and assignments for better performance.
80+
81+
### Conclusion
82+
83+
The member initializer list is a powerful tool in C++ that provides an efficient and clean way to initialize class members. By initializing members directly, you save on unnecessary assignments and memory operations, leading to more efficient code. Whenever possible, use a member initializer list to take advantage of direct initialization.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
---
2+
Title: Using ++i vs i++ in C++ For Loops
3+
layout: post
4+
title: Using ++i vs i++ in C++ For Loops
5+
---
6+
7+
## Using `++i` vs `i++` in C++ For Loops
8+
9+
In C++ (and many other programming languages), it's often recommended to use `++i` instead of `i++` in `for` loops to achieve a small but potentially relevant performance optimization. The difference lies in how the two increment operators (`++i` and `i++`) work:
10+
11+
- **`i++` (Post-Increment)**: With this operation, the current value of `i` is used first, and then `i` is incremented by one. This means a temporary copy of the value must be created to return the old value before incrementing `i`.
12+
13+
- **`++i` (Pre-Increment)**: With this operation, the value of `i` is incremented first, and then the new value is returned. No temporary copy is created, which can make the operation potentially more efficient.
14+
15+
In modern C++ compilers, this difference is often negligible as they perform optimizations to balance these differences. However, `++i` is frequently recommended because it is generally slightly more efficient and does not require temporary copies. Here's a typical example of a `for` loop:
16+
17+
```cpp
18+
for (int i = 0; i < n; ++i) {
19+
// Loop content
20+
}
21+
```
22+
23+
In this case, `++i` is often preferred for performance reasons, although the difference is minor in most applications.
24+
25+
The difference becomes more significant with custom types that overload operators. For primitive types like `int`, the difference is minimal, but for more complex types where the post-increment operator might create an additional copy, using `++i` can provide better performance.
26+
27+
Here's the difference between `i++` (Post-Increment) and `++i` (Pre-Increment) illustrated in pseudocode:
28+
29+
### Post-Increment (`i++`)
30+
31+
```plaintext
32+
// Initial state
33+
i = 5
34+
35+
// Post-Increment Operation: i++
36+
// 1. Create a temporary copy of i
37+
temp = i
38+
39+
// 2. Increment i by one
40+
i = i + 1
41+
42+
// 3. Return the temporary copy (before increment)
43+
result = temp
44+
45+
// Result after operation
46+
i = 6
47+
result = 5
48+
```
49+
50+
### Pre-Increment (`++i`)
51+
52+
```plaintext
53+
// Initial state
54+
i = 5
55+
56+
// Pre-Increment Operation: ++i
57+
// 1. Increment i by one
58+
i = i + 1
59+
60+
// 2. Return the new value of i
61+
result = i
62+
63+
// Result after operation
64+
i = 6
65+
result = 6
66+
```
67+
68+
In the post-increment operation, the original value of `i` is saved first before `i` is incremented. In the pre-increment operation, `i` is incremented first, and the new value is returned without creating an additional temporary copy.
69+
70+
---
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
---
2+
Title: "C++: static_cast, dynamic_cast, reinterpret_cast, and const_cast"
3+
layout: post
4+
title: "C++: static_cast, dynamic_cast, reinterpret_cast, and const_cast"
5+
---
6+
In C++, the four cast operators (`static_cast`, `dynamic_cast`, `reinterpret_cast`, and `const_cast`) are used for different types of type conversions. Here’s an explanation of each, along with examples.
7+
8+
### 1. `static_cast`
9+
`static_cast` is used for most type conversions that are known to be valid at compile time. For example, it can be used to convert a pointer from a base class to a derived class or convert primitive data types.
10+
11+
**Example:**
12+
```cpp
13+
#include <iostream>
14+
15+
class Base {
16+
public:
17+
virtual void print() {
18+
std::cout << "Base class" << std::endl;
19+
}
20+
};
21+
22+
class Derived : public Base {
23+
public:
24+
void print() override {
25+
std::cout << "Derived class" << std::endl;
26+
}
27+
};
28+
29+
int main() {
30+
Base* basePtr = new Derived();
31+
32+
// Use static_cast to convert base class pointer to derived class pointer
33+
Derived* derivedPtr = static_cast<Derived*>(basePtr);
34+
derivedPtr->print(); // Outputs "Derived class"
35+
36+
// Conversion between primitive data types
37+
int a = 10;
38+
double b = static_cast<double>(a);
39+
std::cout << "b = " << b << std::endl; // Outputs "b = 10.0"
40+
41+
delete basePtr;
42+
return 0;
43+
}
44+
```
45+
46+
### 2. `dynamic_cast`
47+
`dynamic_cast` is used for type conversions that are checked at runtime. It is primarily used with polymorphic classes (i.e., classes that have at least one virtual function). If the conversion is not valid, `dynamic_cast` returns `nullptr` for pointer conversions.
48+
49+
**Example:**
50+
```cpp
51+
#include <iostream>
52+
53+
class Base {
54+
public:
55+
virtual void print() {
56+
std::cout << "Base class" << std::endl;
57+
}
58+
};
59+
60+
class Derived : public Base {
61+
public:
62+
void print() override {
63+
std::cout << "Derived class" << std::endl;
64+
}
65+
};
66+
67+
int main() {
68+
Base* basePtr = new Derived();
69+
70+
// Use dynamic_cast to convert base class pointer to derived class pointer
71+
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
72+
73+
if (derivedPtr) {
74+
derivedPtr->print(); // Outputs "Derived class"
75+
} else {
76+
std::cout << "Conversion failed!" << std::endl;
77+
}
78+
79+
Base* baseOnly = new Base();
80+
Derived* invalidPtr = dynamic_cast<Derived*>(baseOnly);
81+
82+
if (invalidPtr) {
83+
invalidPtr->print();
84+
} else {
85+
std::cout << "Conversion failed!" << std::endl; // Outputs this
86+
}
87+
88+
delete basePtr;
89+
delete baseOnly;
90+
return 0;
91+
}
92+
```
93+
94+
### 3. `reinterpret_cast`
95+
`reinterpret_cast` performs a low-level, bitwise conversion. It can be used to convert pointers to integers and vice versa. This cast should be used cautiously, as incorrect use can lead to undefined behavior.
96+
97+
**Example:**
98+
```cpp
99+
#include <iostream>
100+
101+
int main() {
102+
int num = 42;
103+
104+
// Convert a pointer to an integer and back
105+
int* ptr = &num;
106+
uintptr_t intPtr = reinterpret_cast<uintptr_t>(ptr);
107+
std::cout << "Integer pointer: " << intPtr << std::endl;
108+
109+
int* newPtr = reinterpret_cast<int*>(intPtr);
110+
std::cout << "Value at pointer: " << *newPtr << std::endl; // Outputs "42"
111+
112+
return 0;
113+
}
114+
```
115+
116+
### 4. `const_cast`
117+
`const_cast` is used to remove the `const` or `volatile` qualifier from a variable. This is useful if you need to modify a variable that was originally declared as `const`. However, changing a value that was originally declared as `const` can lead to undefined behavior.
118+
119+
**Example:**
120+
```cpp
121+
#include <iostream>
122+
123+
void printValue(const int* value) {
124+
// Remove the const qualifier
125+
int* modifiableValue = const_cast<int*>(value);
126+
*modifiableValue = 100;
127+
}
128+
129+
int main() {
130+
int num = 42;
131+
printValue(&num);
132+
std::cout << "New value: " << num << std::endl; // Outputs "New value: 100"
133+
134+
return 0;
135+
}
136+
```
137+
138+
### Summary
139+
- **`static_cast`:** Compile-time conversion, e.g., base class to derived class, primitive data types.
140+
- **`dynamic_cast`:** Runtime-checked conversion, used with polymorphic classes, safely converts base class to derived class.
141+
- **`reinterpret_cast`:** Unsafe bit-level conversion, e.g., between pointers and integers.
142+
- **`const_cast`:** Removes `const` or `volatile` qualifiers, allows modification of `const` declared variables.

0 commit comments

Comments
 (0)