C++ Data Types
Introduction
Data types are a fundamental concept in any programming language. In C++, data types define the kind of data a variable can hold, how much memory it occupies, and what operations can be performed on it. Understanding data types is essential because they determine how your data is stored, processed, and interpreted by the computer.
In this guide, we'll explore the various data types available in C++, their characteristics, and how to use them effectively in your programs.
Basic Data Types in C++
C++ offers several built-in data types that can be categorized into three main groups:
- Primitive Data Types: Basic building blocks
- Derived Data Types: Built using primitive types
- User-defined Data Types: Created by the programmer
Let's start by exploring the primitive data types.
Primitive Data Types
Integer Types
Integer types store whole numbers without decimal points.
Type | Size (typical) | Value Range |
---|---|---|
short | 2 bytes | -32,768 to 32,767 |
int | 4 bytes | -2,147,483,648 to 2,147,483,647 |
long | 4-8 bytes | -2,147,483,648 to 2,147,483,647 (or greater) |
long long | 8 bytes | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 |
#include <iostream>
using namespace std;
int main() {
int age = 25;
short temperature = -5;
long population = 8000000000;
long long veryLargeNumber = 9223372036854775807;
cout << "Age: " << age << endl;
cout << "Temperature: " << temperature << endl;
cout << "World Population: " << population << endl;
cout << "Very Large Number: " << veryLargeNumber << endl;
return 0;
}
Output:
Age: 25
Temperature: -5
World Population: 8000000000
Very Large Number: 9223372036854775807
Floating-Point Types
Floating-point types store numbers with decimal points.
Type | Size | Precision |
---|---|---|
float | 4 bytes | 7 decimal digits |
double | 8 bytes | 15 decimal digits |
long double | 12-16 bytes | 19+ decimal digits |
#include <iostream>
#include <iomanip> // For setprecision
using namespace std;
int main() {
float pi_approx = 3.14159f; // Note the 'f' suffix for float
double pi_more_precise = 3.1415926535897932;
long double pi_even_more = 3.1415926535897932384626433832795L; // Note the 'L' suffix
cout << fixed << setprecision(7);
cout << "Pi (float): " << pi_approx << endl;
cout << fixed << setprecision(15);
cout << "Pi (double): " << pi_more_precise << endl;
cout << fixed << setprecision(20);
cout << "Pi (long double): " << pi_even_more << endl;
return 0;
}
Output:
Pi (float): 3.1415901
Pi (double): 3.141592653589793
Pi (long double): 3.14159265358979323846
Character Types
Character types store single characters.
Type | Description | Size |
---|---|---|
char | Standard character | 1 byte |
wchar_t | Wide character | 2 or 4 bytes |
char16_t (C++11) | UTF-16 character | 2 bytes |
char32_t (C++11) | UTF-32 character | 4 bytes |
#include <iostream>
using namespace std;
int main() {
char grade = 'A';
char newline = '\n'; // Special escape character
wchar_t wide_char = L'Ω'; // Wide character with L prefix
char16_t utf16_char = u'Ω'; // UTF-16 character with u prefix
char32_t utf32_char = U'Ω'; // UTF-32 character with U prefix
cout << "Grade: " << grade << endl;
cout << "This is line 1." << newline << "This is line 2." << endl;
// Note: Printing wide and UTF characters correctly requires special handling
// This is a simplified example
cout << "Wide character code: " << static_cast<int>(wide_char) << endl;
return 0;
}
Output:
Grade: A
This is line 1.
This is line 2.
Wide character code: 937
Boolean Type
The boolean type stores logical values: true or false.
#include <iostream>
using namespace std;
int main() {
bool isProgrammingFun = true;
bool isBoringSometimes = false;
cout << "Is programming fun? " << (isProgrammingFun ? "Yes" : "No") << endl;
cout << "Is it boring sometimes? " << (isBoringSometimes ? "Yes" : "No") << endl;
// Booleans print as 1 (true) or 0 (false) by default
cout << "isProgrammingFun value: " << isProgrammingFun << endl;
cout << "isBoringSometimes value: " << isBoringSometimes << endl;
// You can change this behavior
cout << boolalpha; // Makes bool print as true/false
cout << "isProgrammingFun value: " << isProgrammingFun << endl;
cout << "isBoringSometimes value: " << isBoringSometimes << endl;
return 0;
}
Output:
Is programming fun? Yes
Is it boring sometimes? No
isProgrammingFun value: 1
isBoringSometimes value: 0
isProgrammingFun value: true
isBoringSometimes value: false
Type Modifiers
C++ allows you to modify the basic types using the following modifiers:
signed
(default for numeric types)unsigned
(only positive values)short
(reduces size)long
(increases size)
#include <iostream>
#include <limits>
using namespace std;
int main() {
// Unsigned types can only store positive values but have a larger range
unsigned int positiveOnly = 4294967295; // Maximum value for unsigned int
// Signed types can store both positive and negative values
signed int withSign = -2147483648; // Minimum value for signed int
cout << "Unsigned int max: " << positiveOnly << endl;
cout << "Signed int min: " << withSign << endl;
// Showing ranges
cout << "Unsigned int range: 0 to " << numeric_limits<unsigned int>::max() << endl;
cout << "Signed int range: " << numeric_limits<int>::min() << " to "
<< numeric_limits<int>::max() << endl;
return 0;
}
Output:
Unsigned int max: 4294967295
Signed int min: -2147483648
Unsigned int range: 0 to 4294967295
Signed int range: -2147483648 to 2147483647
Type Sizes and sizeof
Operator
C++ provides the sizeof
operator to check the size of a data type or variable in bytes.
#include <iostream>
using namespace std;
int main() {
cout << "Size of fundamental data types:\n";
cout << "========================\n";
cout << "char: " << sizeof(char) << " bytes\n";
cout << "short: " << sizeof(short) << " bytes\n";
cout << "int: " << sizeof(int) << " bytes\n";
cout << "long: " << sizeof(long) << " bytes\n";
cout << "long long: " << sizeof(long long) << " bytes\n";
cout << "float: " << sizeof(float) << " bytes\n";
cout << "double: " << sizeof(double) << " bytes\n";
cout << "long double: " << sizeof(long double) << " bytes\n";
cout << "bool: " << sizeof(bool) << " bytes\n";
return 0;
}
Output (may vary by system):
Size of fundamental data types:
========================
char: 1 bytes
short: 2 bytes
int: 4 bytes
long: 8 bytes
long long: 8 bytes
float: 4 bytes
double: 8 bytes
long double: 16 bytes
bool: 1 bytes
Derived Data Types
Arrays
Arrays store collections of a single data type.
#include <iostream>
using namespace std;
int main() {
// Array declaration and initialization
int scores[5] = {95, 89, 76, 92, 88};
cout << "Student scores:\n";
for (int i = 0; i < 5; i++) {
cout << "Student " << (i + 1) << ": " << scores[i] << endl;
}
// Calculate average
int sum = 0;
for (int i = 0; i < 5; i++) {
sum += scores[i];
}
double average = static_cast<double>(sum) / 5;
cout << "Class average: " << average << endl;
return 0;
}
Output:
Student scores:
Student 1: 95
Student 2: 89
Student 3: 76
Student 4: 92
Student 5: 88
Class average: 88
Pointers
Pointers store memory addresses of other variables.
#include <iostream>
using namespace std;
int main() {
int number = 42;
int* ptr = &number; // Pointer to number
cout << "Value of number: " << number << endl;
cout << "Address of number: " << &number << endl;
cout << "Value stored in ptr: " << ptr << endl;
cout << "Value pointed to by ptr: " << *ptr << endl;
// Modifying the value through the pointer
*ptr = 100;
cout << "After modification, number = " << number << endl;
return 0;
}
Output:
Value of number: 42
Address of number: 0x7ffd4c2a9b1c
Value stored in ptr: 0x7ffd4c2a9b1c
Value pointed to by ptr: 42
After modification, number = 100
References
References provide an alias to an existing variable.
#include <iostream>
using namespace std;
int main() {
int original = 10;
int& ref = original; // Reference to original
cout << "Original: " << original << endl;
cout << "Reference: " << ref << endl;
// Changing through reference
ref = 20;
cout << "After changing reference, original = " << original << endl;
// Changing the original
original = 30;
cout << "After changing original, reference = " << ref << endl;
return 0;
}
Output:
Original: 10
Reference: 10
After changing reference, original = 20
After changing original, reference = 30
User-Defined Data Types
Enumerations (enum)
Enumerations allow you to create your own symbolic constants.
#include <iostream>
using namespace std;
int main() {
// Basic enum
enum Color {RED, GREEN, BLUE};
Color myColor = BLUE;
cout << "My color code: " << myColor << endl;
// Enum with custom values
enum HttpStatus {
OK = 200,
BAD_REQUEST = 400,
NOT_FOUND = 404,
SERVER_ERROR = 500
};
HttpStatus response = NOT_FOUND;
cout << "HTTP Status: " << response << endl;
if (response == OK) {
cout << "Request successful!" << endl;
} else {
cout << "Error occurred. Status code: " << response << endl;
}
return 0;
}
Output:
My color code: 2
HTTP Status: 404
Error occurred. Status code: 404
Structures (struct)
Structures allow you to group different data types under a single name.
#include <iostream>
#include <string>
using namespace std;
struct Student {
string name;
int id;
double gpa;
};
int main() {
// Create and initialize a Student structure
Student alice = {"Alice Smith", 12345, 3.75};
// Access and print structure members
cout << "Student Information:\n";
cout << "Name: " << alice.name << endl;
cout << "ID: " << alice.id << endl;
cout << "GPA: " << alice.gpa << endl;
// Modify a structure member
alice.gpa = 3.9;
cout << "Updated GPA: " << alice.gpa << endl;
// Array of structures
Student class_roster[3] = {
{"Bob Johnson", 23456, 3.45},
{"Carol Williams", 34567, 4.0},
{"Dave Brown", 45678, 3.2}
};
cout << "\nClass Roster:\n";
for (int i = 0; i < 3; i++) {
cout << class_roster[i].name << " (ID: " << class_roster[i].id
<< ") - GPA: " << class_roster[i].gpa << endl;
}
return 0;
}
Output:
Student Information:
Name: Alice Smith
ID: 12345
GPA: 3.75
Updated GPA: 3.9
Class Roster:
Bob Johnson (ID: 23456) - GPA: 3.45
Carol Williams (ID: 34567) - GPA: 4
Dave Brown (ID: 45678) - GPA: 3.2
Classes (class)
Classes are similar to structures but with additional features including access control.
#include <iostream>
#include <string>
using namespace std;
class BankAccount {
private:
string accountHolder;
double balance;
string accountNumber;
public:
// Constructor
BankAccount(string holder, string accNum, double initialBalance) {
accountHolder = holder;
accountNumber = accNum;
balance = initialBalance;
}
// Methods
void deposit(double amount) {
if (amount > 0) {
balance += amount;
cout << "Deposited $" << amount << endl;
}
}
void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
cout << "Withdrew $" << amount << endl;
} else {
cout << "Insufficient funds or invalid amount!" << endl;
}
}
void displayInfo() {
cout << "Account Information:\n";
cout << "Holder: " << accountHolder << endl;
cout << "Account Number: " << accountNumber << endl;
cout << "Balance: $" << balance << endl;
}
};
int main() {
// Create a bank account object
BankAccount myAccount("John Doe", "C0001", 1000.00);
// Display initial information
myAccount.displayInfo();
// Perform some transactions
myAccount.deposit(500.00);
myAccount.withdraw(200.00);
myAccount.withdraw(2000.00); // Should fail
// Display updated information
myAccount.displayInfo();
return 0;
}
Output:
Account Information:
Holder: John Doe
Account Number: C0001
Balance: $1000
Deposited $500
Withdrew $200
Insufficient funds or invalid amount!
Account Information:
Holder: John Doe
Account Number: C0001
Balance: $1300
Type Conversion
C++ offers multiple ways to convert between data types.
Implicit Type Conversion (Automatic)
The compiler automatically converts one data type to another if needed.
#include <iostream>
using namespace std;
int main() {
int i = 10;
double d = i; // Implicit conversion from int to double
cout << "Integer value: " << i << endl;
cout << "Double value after conversion: " << d << endl;
char c = 'A';
int ascii = c; // Char is converted to its ASCII value
cout << "Character: " << c << endl;
cout << "ASCII value: " << ascii << endl;
// Be careful with implicit conversions that might lose data
double pi = 3.14159;
int rounded = pi; // Decimal part is truncated!
cout << "Original double: " << pi << endl;
cout << "Converted to int: " << rounded << " (Notice the lost precision)" << endl;
return 0;
}
Output:
Integer value: 10
Double value after conversion: 10
Character: A
ASCII value: 65
Original double: 3.14159
Converted to int: 3 (Notice the lost precision)
Explicit Type Conversion (Casting)
You can explicitly convert data types using different casting methods.
#include <iostream>
using namespace std;
int main() {
// C-style casting
double x = 3.14159;
int y = (int)x; // C-style cast
cout << "Original double: " << x << endl;
cout << "After C-style cast to int: " << y << endl;
// C++ style static_cast
double pi = 3.14159;
int rounded = static_cast<int>(pi);
cout << "Original double: " << pi << endl;
cout << "After static_cast to int: " << rounded << endl;
// Converting numeric values to bool
int zero = 0;
int nonZero = 42;
bool boolFromZero = static_cast<bool>(zero);
bool boolFromNonZero = static_cast<bool>(nonZero);
cout << boolalpha; // Print bool as true/false
cout << "Bool from 0: " << boolFromZero << endl;
cout << "Bool from 42: " << boolFromNonZero << endl;
return 0;
}
Output:
Original double: 3.14159
After C-style cast to int: 3
Original double: 3.14159
After static_cast to int: 3
Bool from 0: false
Bool from 42: true
Real-World Application: Temperature Converter
Let's create a practical example that uses various data types to convert temperatures between Celsius and Fahrenheit.
#include <iostream>
#include <string>
#include <limits>
using namespace std;
// Define a structure to store temperature values in different units
struct Temperature {
double celsius;
double fahrenheit;
double kelvin;
};
// Function to convert between temperature units
Temperature convertTemperature(double value, char unit) {
Temperature result;
switch (unit) {
case 'C':
case 'c':
result.celsius = value;
result.fahrenheit = (value * 9.0/5.0) + 32.0;
result.kelvin = value + 273.15;
break;
case 'F':
case 'f':
result.fahrenheit = value;
result.celsius = (value - 32.0) * 5.0/9.0;
result.kelvin = result.celsius + 273.15;
break;
case 'K':
case 'k':
result.kelvin = value;
result.celsius = value - 273.15;
result.fahrenheit = (result.celsius * 9.0/5.0) + 32.0;
break;
default:
// Invalid unit, set all to NaN (not a number)
result.celsius = numeric_limits<double>::quiet_NaN();
result.fahrenheit = numeric_limits<double>::quiet_NaN();
result.kelvin = numeric_limits<double>::quiet_NaN();
}
return result;
}
int main() {
double value;
char unit;
bool continueConversion = true;
while (continueConversion) {
cout << "\nTemperature Converter\n";
cout << "=====================\n";
cout << "Enter a temperature value: ";
cin >> value;
cout << "Enter the unit (C for Celsius, F for Fahrenheit, K for Kelvin): ";
cin >> unit;
Temperature converted = convertTemperature(value, unit);
if (isnan(converted.celsius)) {
cout << "Invalid unit entered. Please use C, F, or K." << endl;
} else {
cout << "\nConversion Results:\n";
cout << "Celsius: " << converted.celsius << " °C\n";
cout << "Fahrenheit: " << converted.fahrenheit << " °F\n";
cout << "Kelvin: " << converted.kelvin << " K\n";
// Determine the state of water at this temperature (Celsius)
string waterState;
if (converted.celsius <= 0) {
waterState = "solid (ice)";
} else if (converted.celsius < 100) {
waterState = "liquid (water)";
} else {
waterState = "gas (steam)";
}
cout << "\nAt " << converted.celsius << " °C, water would be in a "
<< waterState << " state." << endl;
}
char answer;
cout << "\nWould you like to convert another temperature? (y/n): ";
cin >> answer;
continueConversion = (answer == 'y' || answer == 'Y');
}
cout << "\nThank you for using the Temperature Converter!\n";
return 0;
}
Example Output:
Temperature Converter
=====================
Enter a temperature value: 25
Enter the unit (C for Celsius, F for Fahrenheit, K for Kelvin): C
Conversion Results:
Celsius: 25 °C
Fahrenheit: 77 °F
Kelvin: 298.15 K
At 25 °C, water would be in a liquid (water) state.
Would you like to convert another temperature? (y/n): y
Temperature Converter
=====================
Enter a temperature value: 32
Enter the unit (C for Celsius, F for Fahrenheit, K for Kelvin): F
Conversion Results:
Celsius: 0 °C
Fahrenheit: 32 °F
Kelvin: 273.15 K
At 0 °C, water would be in a solid (ice) state.
Would you like to convert another temperature? (y/n): n
Thank you for using the Temperature Converter!
Summary
In this guide, we've explored the various data types available in C++:
-
Primitive Data Types:
- Integer types:
short
,int
,long
,long long
- Floating-point types:
float
,double
,long double
- Character types:
char
,wchar_t
,char16_t
,char32_t
- Boolean type:
bool
- Integer types:
-
Type Modifiers:
signed
,unsigned
,short
,long
-
Derived Data Types:
- Arrays
- Pointers
- References
-
User-Defined Data Types:
- Enumerations (
enum
) - Structures (
struct
) - Classes (
class
)
- Enumerations (
-
Type Conversion:
- Implicit (automatic) conversion
- Explicit conversion (casting)
Understanding data types is fundamental to writing effective C++ code. Choosing the right data type for your variables not only makes your code more efficient but also helps prevent bugs and unexpected behavior.
Exercises
-
Create a program that calculates the average of 5 student grades stored in different data types (int, float, double) and compares the precision of the results.
-
Write a program that demonstrates how integer overflow works in both signed and unsigned integers.
-
Create a structure to represent a 2D point with x and y coordinates, then write functions to calculate the distance between two points.
-
Implement a simple bank account system using a class that includes data members of different types (strings for names, integers for account numbers, doubles for balances).
-
Write a program that converts distances between different units (meters, feet, inches, etc.) using explicit type casting where appropriate.
Additional Resources
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)