YouTip LogoYouTip

Cpp Data Types

When programming with a programming language, you need to use various variables to store different kinds of information. A variable reserves a memory location for the value it stores. This means that when you create a variable, some space is reserved in memory. You may need to store information of various data types (such as character, wide character, integer, floating-point, double-precision floating-point, boolean, etc.). The operating system allocates memory and decides what to store in the reserved memory based on the variable's data type. C++ provides programmers with a rich set of built-in data types and user-defined data types. The following table lists seven basic C++ data types: | Type | Keyword | | --- | --- | | Boolean | bool | | Character | char | | Integer | int | | Floating-point | float | | Double-precision floating-point | double | | Void | void | | Wide character | wchar_t | Actually, `wchar_t` is defined like this: ```cpp typedef short int wchar_t; So `wchar_t` actually occupies the same space as `short int`. Some basic types can be modified using one or more type modifiers: | Modifier | Description | Example | | --- | --- | --- | | `signed` | Indicates a signed type (default) | `signed int x = -10;` | | `unsigned` | Indicates an unsigned type | `unsigned int y = 10;` | | `short` | Indicates a short integer | `short int z = 100;` | | `long` | Indicates a long integer | `long int a = 100000;` | | `const` | Indicates a constant, whose value cannot be modified | `const int b = 5;` | | `volatile` | Indicates that the variable may be modified unexpectedly, disabling compiler optimization | `volatile int c = 10;` | | `mutable` | Indicates that a class member can be modified in a `const` object | `mutable int counter;` | The following table shows the memory required to store values of various variable types, as well as the maximum and minimum values that variables of these types can store. **Note:** There may be differences across systems; one byte is 8 bits. **Note:** By default, `int`, `short`, and `long` are signed, i.e., `signed`. **Note:** `long int` is 8 bytes, `int` is 4 bytes. Early C compilers defined `long int` as 4 bytes and `int` as 2 bytes. Newer C/C++ standards are compatible with this earlier setting. | Data Type | Description | Size (bytes) | Range/Value Example | | --- | --- | --- | --- | | `bool` | Boolean type, represents true or false | 1 | `true` or `false` | | `char` | Character type, typically used to store ASCII characters | 1 | -128 to 127 or 0 to 255 | | `signed char` | Signed character type | 1 | -128 to 127 | | `unsigned char` | Unsigned character type | 1 | 0 to 255 | | `wchar_t` | Wide character type, used to store Unicode characters | 2 or 4 | Depends on platform | | `char16_t` | 16-bit Unicode character type (introduced in C++11) | 2 | 0 to 65,535 | | `char32_t` | 32-bit Unicode character type (introduced in C++11) | 4 | 0 to 4,294,967,295 | | `short` | Short integer | 2 | -32,768 to 32,767 | | `unsigned short` | Unsigned short integer | 2 | 0 to 65,535 | | `int` | Integer | 4 | -2,147,483,648 to 2,147,483,647 | | `unsigned int` | Unsigned integer | 4 | 0 to 4,294,967,295 | | `long` | Long integer | 4 or 8 | Depends on platform | | `unsigned long` | Unsigned long integer | 4 or 8 | Depends on platform | | `long long` | Long long integer (introduced in C++11) | 8 | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 | | `unsigned long long` | Unsigned long long integer (introduced in C++11) | 8 | 0 to 18,446,744,073,709,551,615 | | `float` | Single-precision floating-point | 4 | Approximately Β±3.4eΒ±38 (6-7 significant digits) | | `double` | Double-precision floating-point | 8 | Approximately Β±1.7eΒ±308 (15 significant digits) | | `long double` | Extended-precision floating-point | 8, 12, or 16 | Depends on platform | ### New Types in C++11 | Data Type | Description | Example | | --- | --- | --- | | `auto` | Automatic type deduction | `auto x = 10;` | | `decltype` | Get the type of an expression | `decltype(x) y = 20;` | | `nullptr` | Null pointer constant | `int* ptr = nullptr;` | | `std::initializer_list` | Initializer list type | `std::initializer_list list = {1, 2, 3};` | | `std::tuple` | Tuple type, can store multiple values of different types | `std::tuple t(1, 2.0, 'a');` | > Note: The storage size of various types is related to the system's bitness, but currently 64-bit systems are the most common. > > > The following lists the differences in storage size between 32-bit and 64-bit systems (the same for Windows): > > > !(#) From the table above, it can be seen that the size of a variable may vary depending on the compiler and the computer being used. The following example will output the size of various data types on your computer. ## Example ```cpp #include #include using namespace std; int main() { cout<<"type: tt"<<" ************size************** "<<endl; cout<<"bool: tt"<<"Bytes occupied:"<<sizeof(bool); cout<<"tMaximum:"<<(numeric_limits::max)(); cout<<"ttMinimum:"<<(numeric_limits::min)()<<endl; cout<<"char: tt"<<"Bytes occupied:"<<sizeof(char); cout<<"tMaximum:"<<(numeric_limits::max)(); cout<<"ttMinimum:"<<(numeric_limits::min)()<<endl; cout<<"signed char: t"<<"Bytes occupied:"<<sizeof(signed char); cout<<"tMaximum:"<<(numeric_limits::max)(); cout<<"ttMinimum:"<<(numeric_limits::min)()<<endl; cout<<"unsigned char: t"<<"Bytes occupied:"<<sizeof(unsigned char); cout<<"tMaximum:"<<(numeric_limits::max)(); cout<<"ttMinimum:"<<(numeric_limits::min)()<<endl; cout<<"wchar_t: t"<<"Bytes occupied:"<<sizeof(wchar_t); cout<<"tMaximum:"<<(numeric_limits::max)(); cout<<"ttMinimum:"<<(numeric_limits::min)()<<endl; cout<<"short: tt"<<"Bytes occupied:"<<sizeof(short); cout<<"tMaximum:"<<(numeric_limits::max)(); cout<<"ttMinimum:"<<(numeric_limits::min)()<<endl; cout<<"int: tt"<<"Bytes occupied:"<<sizeof(int); cout<<"tMaximum:"<<(numeric_limits::max)(); cout<<"tMinimum:"<<(numeric_limits::min)()<<endl; cout<<"unsigned: t"<<"Bytes occupied:"<<sizeof(unsigned); cout<<"tMaximum:"<<(numeric_limits::max)(); cout<<"tMinimum:"<<(numeric_limits::min)()<<endl; cout<<"long: tt"<<"Bytes occupied:"<<sizeof(long); cout<<"tMaximum:"<<(numeric_limits::max)(); cout<<"tMinimum:"<<(numeric_limits::min)()<<endl; cout<<"unsigned long: t"<<"Bytes occupied:"<<sizeof(unsigned long); cout<<"tMaximum:"<<(numeric_limits::max)(); cout<<"tMinimum:"<<(numeric_limits::min)()<<endl; cout<<"double: t"<<"Bytes occupied:"<<sizeof(double); cout<<"tMaximum:"<<(numeric_limits::max)(); cout<<"tMinimum:"<<(numeric_limits::min)()<<endl; cout<<"long double: t"<<"Bytes occupied:"<<sizeof(long double); cout<<"tMaximum:"<<(numeric_limits::max)(); cout<<"tMinimum:"<<(numeric_limits::min)()<<endl; cout<<"float: tt"<<"Bytes occupied:"<<sizeof(float); cout<<"tMaximum:"<<(numeric_limits::max)(); cout<<"tMinimum:"<<(numeric_limits::min)()<<endl; cout<<"size_t: t"<<"Bytes occupied:"<<sizeof(size_t); cout<<"tMaximum:"<<(numeric_limits::max)(); cout<<"tMinimum:"<<(numeric_limits::min)()<<endl; cout<<"string: t"<<"Bytes occupied:"<<sizeof(string)<<endl; cout<<"type: tt"<<" ************size************** "<<endl; return 0; } This example uses **endl**, which inserts a newline character after each line. The `<<` operator is used to pass multiple values to the screen, and the **sizeof()** operator is used to get the size of various data types. When the above code is compiled and executed, it will produce the following result (the result will vary depending on the computer used): type: \t\t ************size************** bool: \t\tBytes occupied: 1\tMaximum:1\t\tMinimum: 0 char: \t\tBytes occupied: 1\tMaximum: \t\tMinimum:? signed char: \tBytes occupied: 1\tMaximum: \t\tMinimum:? unsigned char: \tBytes occupied: 1\tMaximum:?\t\tMinimum: wchar_t: \tBytes occupied: 4\tMaximum:2147483647\tMinimum: -2147483648 short: \t\tBytes occupied: 2\tMaximum:32767\t\tMinimum:-32768 int: \t\tBytes occupied: 4\tMaximum:2147483647\tMinimum: -2147483648 unsigned: \tBytes occupied: 4\tMaximum:4294967295\tMinimum: 0 long: \t\tBytes occupied: 8\tMaximum: 9223372036854775807\tMinimum: -9223372036854775808 unsigned long: \tBytes occupied: 8\tMaximum:18446744073709551615\tMinimum: 0 double: \tBytes occupied: 8\tMaximum:1.79769e+308\tMinimum: 2.22507e-308 long double: \tBytes occupied: 16\tMaximum:1.18973e+4932\tMinimum: 3.3621e-4932 float: \t\tBytes occupied: 4\tMaximum:3.40282e+38\tMinimum: 1.17549e-38 size_t: \tBytes occupied: 8\tMaximum:18446744073709551615\tMinimum: 0 string: \tBytes occupied: 24 type: \t\t ************size************** ### Derived Data Types | Data Type | Description | Example | | --- | --- | --- | | `Array` | A collection of elements of the same type | `int arr = {1, 2, 3, 4, 5};` | | `Pointer` | A type that stores the memory address of a variable | `int* ptr = &x;` | | `Reference` | An alias for a variable | `int& ref = x;` | | `Function` | A function type, representing the signature of a function | `int func(int a, int b);` | | `Structure` | A user-defined data type that can contain multiple members of different types | `struct Point { int x; int y; };` | | `Class` | A user-defined data type that supports encapsulation, inheritance, and polymorphism | `class MyClass { ... };` | | `Union` | Multiple members share the same block of memory | `union Data { int i; float f; };` | | `Enumeration` | A user-defined set of integer constants | `enum Color { RED, GREEN, BLUE };` | ### Type Aliases | Alias | Description | Example | | --- | --- | --- | | `typedef` | Defines an alias for an existing type | `typedef int MyInt;` | | `using` | Defines an alias for an existing type (introduced in C++11) | `using MyInt = int;` | ### Standard Library Types | Data Type | Description | Example | | --- | --- | --- | | `std::string` | String type | `std::string s = "Hello";` | | `std::vector` | Dynamic array | `std::vector v = {1, 2, 3};` | | `std::array` | Fixed-size array (introduced in C++11) | `std::array a = {1, 2, 3};` | | `std::pair` | Container that stores two values | `std::pair p(1, 2.0);` | | `std::map` | Key-value pair container | `std::map m;` | | `std::set` | Set of unique values | `std::set s = {1, 2, 3};` | You can use **typedef** to give a new name to an existing type. Here is the syntax for defining a new type using typedef: ```cpp typedef type newname; For example, the following statement tells the compiler that `feet` is another name for `int`: ```cpp typedef int feet; Now, the following declaration is perfectly legal and creates an integer variable `distance`: ```cpp feet distance; The enumeration type is a derived data type in C++, which is a collection of several enumeration constants defined by the user. If a variable can only have a few possible values, it can be defined as an enumeration type. "Enumeration" means listing the values of the variable one by one, and the variable's value can only be within the range of the listed values. To create an enumeration, you need to use the keyword **enum**. The general form of an enumeration type is: ```cpp enum enum_name { identifier, identifier, ... identifier } enumeration_variable; If the enumeration is not initialized, i.e., "= integer_constant" is omitted, then it starts from the first identifier. For example, the following code defines a color enumeration, and the variable `c` is of type `color`. Finally, `c` is assigned the value "blue". ```cpp enum color { red, green, blue } c; c = blue; By default, the value of the first name is 0, the second is 1, the third is 2, and so on. However, you can also assign a special value to a name by adding an initial value. For example, in the following enumeration, the value of **green** is 5. ```cpp enum color { red, green=5, blue }; Here, the value of **blue** is 6, because by default, each name is one greater than the previous one, but the value of `red` is still 0. ## Type Casting Type casting is the process of converting a value from one data type to another. There are four types of casting in C++: static cast, dynamic cast, const cast, and reinterpret cast. ### Static Cast Static cast is used to force the conversion of a value from one data type to another. Static cast is typically used for conversions between objects of similar types, such as converting an `int` to a `float`. Static cast does not perform any runtime type checking, so it may lead to runtime errors. ## Example ```cpp int i = 10; float f = static_cast(i); ### Dynamic Cast Dynamic cast (`dynamic_cast`) is a mechanism in C++ used for downcasting within an inheritance hierarchy. Dynamic cast is typically used to convert a base class pointer or reference to a derived class pointer or reference. Dynamic cast performs type checking at runtime. If the conversion fails, it returns `nullptr` for pointer types and throws a `std::bad_cast` exception for reference types. **Syntax:** ```cpp dynamic_cast(expression) * **target_type**: Must be a pointer or reference type. * **expression**: The base class pointer or reference to be converted. ## Example: Dynamic Cast for Pointer Types ```cpp #include class Base{ public: virtual ~Base() = default; }; class Derived : public Base{ public: void show(){ std::cout<<"Derived class method"<<std::endl; } }; int main(){ Base* ptr_base = new Derived; Derived* ptr_derived = dynamic_cast(ptr_base); if(ptr_derived){ ptr_derived->show(); }else{ std::cout<<"Dynamic cast failed!"<<std::endl; } delete ptr_base; return 0; } Output: Derived class method ## Example: Dynamic Cast for Reference Types ```cpp #include #include class Base { public: virtual ~Base()=default;// Base class must have virtual functions }; class Derived :public Base { public: void show(){ std::cout<<"Derived class method"<< std::endl; } }; int main(){ Derived derived_obj; Base& ref_base = derived_obj;// Base class reference bound to derived class object try{ // Convert base class reference to derived class reference Derived& ref_derived =dynamic_cast(ref_base); ref_derived.show();// Conversion successful, call derived class method }catch(const std::bad_cast& e){ std::cout<<"Dynamic cast failed: "<< e.what()<< std::endl; } return 0; } Output: Derived class method | Feature | Pointer Type | Reference Type | | --- | --- | --- | | **Return Value on Conversion Failure** | Returns `nullptr` | Throws `std::bad_cast` exception | | **Applicable Scenarios** | Downcasting, runtime type checking | Downcasting, runtime type checking | | **Performance Overhead** | High | High | | **Base Class Requirement** | Must have virtual functions | Must have virtual functions | ### Const Cast Const cast is used to convert a `const` type object to a non-`const` type object. Const cast can only be used to remove the `const` attribute; it cannot change the type of the object. ## Example ```cpp const int i = 10; int&r = const_cast(i); ### Reinterpret Cast Reinterpret cast reinterprets the value of one data type as the value of another data type, typically used for conversions between different data types. Reinterpret cast does not perform any type checking, so it may lead to undefined behavior. ## Example ```cpp int i = 10; float f = reinterpret_cast(i);
← C Exercise Example101Md Advance β†’