You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: content/posts/cpp-learn.md
+237-8Lines changed: 237 additions & 8 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -646,29 +646,32 @@ int main()
646
646
647
647
648
648
## 12. Compound Types: References and Pointers
649
+
-`Compound data types` (also called composite data type) are data types that can be constructed from fundamental data types (or other compound data types).
650
+
-
649
651
### 12.1. lvalues and rvalues
650
-
-`lvalues` is an expression that evaluates to an identifiable object or function (or bit-field). Can be accessed via an identifier, reference, or pointer, and typically have a lifetime longer than a single expression or statement.
652
+
-`lvalues` is an expression that evaluates to an identifiable object or function (or bit-field). Can be accessed via an identifier, reference, or pointer, and typically have a lifetime longer than a single `expression` or `statement`.
651
653
-`rvalues` is an expression that evaluate to a value. Only exist within the scope of the expression in which they are used.
652
654
-`lvalues` can be used anywhere an `rvalue` is expected.
653
655
- An **assignment operation** requires its `left` operand to be a modifiable `lvalue` expression. And its `right` operand to be a `rvalue` expression.
654
656
655
657
### 12.2. References
656
-
-`references` is an alias for an existing object/function.
658
+
-**references** is an alias for an existing object/function.
659
+
- Declared as `<type>& reference_name`
657
660
- Any operation on the reference is applied to the object being referenced.
658
661
- All references must be initialized.
659
662
- Cannot be reseated.
660
663
- They aren't objects
661
664
- Can only accept modifiable lvalue arguments (const or non-const)
662
665
663
-
-`pass-by-reference` allows us:
666
+
-**pass-by-reference** allows us:
664
667
- to pass arguments to a function without making copies of those arguments each time the function is called. (class types)
665
668
- to change the value of an argument
666
669
667
-
-`pass-by-const-reference` guaranteeing that the function can not change the value being referenced.
668
-
-`lvalue-reference` just a reference for an existing lvalue.
669
-
-`lvalue-reference-types` determines what type of object it can reference by using a single ampersand `<type>&` .
670
-
-`lvalue-reference-variable` is a variable that acts as a reference to an lvalue.
671
-
-`lvalue-reference-to-const` can bind with const or non-const objects.
670
+
-**pass-by-const-reference** guaranteeing that the function can not change the value being referenced.
671
+
-**lvalue-reference** just a reference for an existing lvalue.
672
+
-**lvalue-reference-types** determines what type of object it can reference by using a single ampersand `<type>&` .
673
+
-**lvalue-reference-variable** is a variable that acts as a reference to an lvalue.
674
+
-**lvalue-reference-to-const** can bind with const or non-const objects.`const <type>& name`
672
675
673
676
- E.g.
674
677
```cpp
@@ -727,5 +730,231 @@ int main() {
727
730
}
728
731
```
729
732
733
+
### 12.3. Pointer
734
+
- **address-of-operator (&<variable>)** returns the memory address of its operand, **but not as an address literal. Instead, it returns a pointer to the operand.** This pointer holds the address value, and when passed to cout, the stream simply prints that value.
735
+
- **dereference-operator (*<address>)** returns the value at a given memory address as an lvalue, used to access the object being pointed at.
736
+
- **pointer** is an object that holds a memory address as its value:
737
+
- declared as `<type>* ptr_name`
738
+
- This allows us to store the address of some other object to use later.
739
+
- we should init the pointers.
740
+
- the size of pointer is allways the same (32 or 64-bit architecture)
741
+
- can assign an invalid pointer a new value, such as `nullptr`
742
+
- `wild pointer`: pointer that has not been initialized is sometimes called a .
743
+
- `dangling pointer`: pointer that is holding the address of an object that is no longer valid
744
+
- **pointer-type** is a type that specifies a pointer (like reference-type) by using an asterisk `(<type>*)`.The type of the pointer has to match the type of the object being pointed at.
745
+
- **null-pointer** (its type is `std::nullptr_t`) means something has no value. It often associated with memory address 0.
746
+
747
+
- **pointer-to-const**: that points to a value that cannot be modified through the pointer, but the pointer itself is not const.
748
+
- declared as `const <type> ptr_name*`.
749
+
- cannot change the value being pointed to, but can make the pointer point to a different address.
750
+
- may also point to non-const variables.
751
+
- **const-pointer**: whose stored address cannot be changed after initialization, but the value at that address can be modified.
752
+
- declared as `<type>* const ptr_name`.
753
+
- fixed to one address, but we can change the value at that address.
754
+
- **const-pointer-to-const**: cannot be reseated (address fixed) and cannot modify the value it points to.
755
+
- declared as `const <type>* const ptr_name`.
756
+
- can only be dereferenced to read the value.
757
+
758
+
- e.g.
759
+
```cpp
760
+
#include <iostream>
761
+
#include <cstdint> // for uintptr_t
762
+
763
+
int main() {
764
+
int x = 42;
765
+
766
+
// address-of operator (&) returns a pointer to x (not an address literal)
767
+
int* ptr = &x;
768
+
769
+
// Printing the pointer: cout prints the stored address value
- to pass arguments to a function without making copies of those arguments each time the function is called. (class types)
853
+
- to change the value of an argument
854
+
- #null checking
855
+
> Pass by reference when you can, pass by address when you must
856
+
857
+
- **!! C++ really passes everything by value**
858
+
859
+
### 12.5. Return by value/reference/address
860
+
- **T returnValue(...)**: returns a copy (or move) of the object. The caller gets its own value.
861
+
- **T& returnReference(...)** returns a reference to an existing object. The caller does not own it, so the object must outlive the reference.
862
+
- **T * returnAddress(...)** returns a pointer (an address) to an object. The caller must handle the pointer carefully (ensure it’s valid and points to a live object).
863
+
864
+
- `return-by-reference`:
865
+
- avoids making a copy of the object.
866
+
- the referenced object must live beyond the scope of the function, otherwise the reference will dangle.
867
+
- never return a non-static local variable or temporary by reference.
868
+
- `return-by-address` works almost identically to return-by-reference.
869
+
- `return-by-value` just make a copy
870
+
> Prefer return by reference over return by address unless the ability to return “no object” (using nullptr) is important.
871
+
872
+
- e.g.
873
+
```cpp
874
+
#include <iostream>
875
+
876
+
int global = 42;
877
+
878
+
// Return by value: makes a copy
879
+
int returnValue() {
880
+
int x = 10;
881
+
return x; // copy returned
882
+
}
883
+
884
+
// Return by reference: must refer to existing object
885
+
int& returnReference() {
886
+
return global; // safe: global outlives the function
887
+
}
888
+
889
+
// Return by address: returns a pointer
890
+
int* returnAddress(bool valid) {
891
+
if (valid)
892
+
return &global; // valid pointer
893
+
else
894
+
return nullptr; // no object
895
+
}
896
+
897
+
int main() {
898
+
int a = returnValue();
899
+
std::cout << "By value: " << a << '\n';
900
+
901
+
int& b = returnReference();
902
+
std::cout << "By reference: " << b << '\n';
903
+
b = 100; // modifies global
904
+
std::cout << "Global after modification: " << global << '\n';
905
+
906
+
int* c = returnAddress(true);
907
+
if (c) std::cout << "By address: " << *c << '\n';
908
+
909
+
int* d = returnAddress(false);
910
+
if (!d) std::cout << "By address: got nullptr\n";
911
+
}
912
+
```
913
+
914
+
### 12.6. In/Out Params
915
+
-`in-parameters`:are typically passed `by value` or `by const reference`
916
+
-`out-parameters`:a function parameter that is used only for the purpose of returning information back to the caller.
917
+
- Avoid out-parameters (except in the rare case where no better options exist).
918
+
- Prefer pass by reference for non-optional out-parameters.
919
+
920
+
- e.g.
921
+
```cpp
922
+
#include<iostream>
923
+
#include<string>
924
+
925
+
// In-parameter by value (cheap to copy)
926
+
voidgreet(std::string name) {
927
+
std::cout << "Hello, " << name << "!\n";
928
+
}
929
+
930
+
// In-parameter by const reference (avoid copy for large objects)
931
+
int length(const std::string& text) {
932
+
return text.size();
933
+
}
934
+
935
+
// Out-parameter by reference (rare case)
936
+
void square(int input, int& output) {
937
+
output = input * input;
938
+
}
939
+
940
+
int main() {
941
+
// in-parameter by value
942
+
greet("Alice");
943
+
944
+
// in-parameter by const reference
945
+
std::string msg = "Hello World";
946
+
std::cout << "Length = " << length(msg) << "\n";
947
+
948
+
// out-parameter by reference (not preferred, but possible)
949
+
int result;
950
+
square(5, result);
951
+
std::cout << "Square = " << result << "\n";
952
+
}
953
+
```
954
+
955
+
### 12.7. Type deduction (auto) with pointers, references, and const
0 commit comments