【C++基础与提高】第二章:C++数据类型系统------构建程序的基础砖石
(持续更新中,欢迎关注!)
文章目录
- 【C++基础与提高】第二章:C++数据类型系统------构建程序的基础砖石
-
-
- [2.1 数据类型概述------为什么需要不同类型?](#2.1 数据类型概述——为什么需要不同类型?)
- [2.2 基本数据类型------C++的原子构件](#2.2 基本数据类型——C++的原子构件)
-
- [2.2.1 整数类型详解](#2.2.1 整数类型详解)
- [2.2.2 浮点类型------处理小数的利器](#2.2.2 浮点类型——处理小数的利器)
- [2.2.3 字符类型------文字世界的通行证](#2.2.3 字符类型——文字世界的通行证)
- [2.2.4 布尔类型------逻辑判断的核心](#2.2.4 布尔类型——逻辑判断的核心)
- [2.3 复合数据类型------构建复杂数据结构](#2.3 复合数据类型——构建复杂数据结构)
-
- [2.3.1 数组------有序数据集合](#2.3.1 数组——有序数据集合)
- [2.3.2 结构体------自定义数据类型](#2.3.2 结构体——自定义数据类型)
- [2.4 类型修饰符------精细化控制内存使用](#2.4 类型修饰符——精细化控制内存使用)
- [2.5 类型推导------让编译器帮你思考](#2.5 类型推导——让编译器帮你思考)
- [2.6 类型转换------不同类型间的桥梁](#2.6 类型转换——不同类型间的桥梁)
-
- [2.6.1 隐式类型转换](#2.6.1 隐式类型转换)
- [2.6.2 显式类型转换](#2.6.2 显式类型转换)
- [2.7 内存占用与对齐------深入了解底层机制](#2.7 内存占用与对齐——深入了解底层机制)
- [2.8 最佳实践建议](#2.8 最佳实践建议)
- [2.9 本章小结](#2.9 本章小结)
-
2.1 数据类型概述------为什么需要不同类型?
在现实世界中,我们需要不同的容器来存储不同类型的物品:用水杯装水,用书包装书,用钱包装钱。同样,在编程世界里,我们也需要不同类型的数据类型来存储和处理各种信息。
C++的数据类型就像程序员的工具箱,每种工具都有其特定用途:
- 整数类型用于计数和索引
- 浮点类型用于科学计算
- 字符类型用于文本处理
- 布尔类型用于逻辑判断
2.2 基本数据类型------C++的原子构件
2.2.1 整数类型详解
整数类型是C++中最常用的类型之一,用于存储没有小数部分的数值。
cpp
#include <iostream>
#include <climits> // 包含整数类型范围常量
int main() {
// 不同大小的整数类型
short s = 32767; // 通常16位,范围:-32768到32767
int i = 2147483647; // 通常32位,范围:-2,147,483,648到2,147,483,647
long l = 2147483647L; // 至少32位
long long ll = 9223372036854775807LL; // 至少64位
std::cout << "short最大值: " << SHRT_MAX << std::endl;
std::cout << "int最大值: " << INT_MAX << std::endl;
std::cout << "long最大值: " << LONG_MAX << std::endl;
std::cout << "long long最大值: " << LLONG_MAX << std::endl;
return 0;
}
有符号 vs 无符号整数:
cpp
// 有符号整数(可正可负)
int signed_num = -100;
// 无符号整数(只能为正,包括0)
unsigned int unsigned_num = 100U;
std::cout << "有符号数: " << signed_num << std::endl; // 输出: -100
std::cout << "无符号数: " << unsigned_num << std::endl; // 输出: 100
2.2.2 浮点类型------处理小数的利器
浮点类型用于表示带有小数部分的实数:
cpp
#include <iostream>
#include <iomanip> // 用于控制输出格式
int main() {
float f = 3.14159f; // 单精度浮点数,约7位有效数字
double d = 3.141592653589793; // 双精度浮点数,约15位有效数字
long double ld = 3.141592653589793238L; // 扩展精度浮点数
std::cout << std::fixed << std::setprecision(10);
std::cout << "float: " << f << std::endl;
std::cout << "double: " << d << std::endl;
std::cout << "long double: " << ld << std::endl;
return 0;
}
2.2.3 字符类型------文字世界的通行证
字符类型用于存储单个字符:
cpp
#include <iostream>
int main() {
char c1 = 'A'; // 普通字符
char c2 = 65; // ASCII码值
char c3 = '\n'; // 转义字符(换行)
wchar_t wc = L'中'; // 宽字符,支持Unicode
std::cout << "字符1: " << c1 << std::endl; // 输出: A
std::cout << "字符2: " << c2 << std::endl; // 输出: A
std::cout << "换行前";
std::cout << c3; // 换行
std::cout << "换行后" << std::endl;
return 0;
}
常见转义字符:
\n- 换行\t- 制表符-
\\\](file://f:\\华为攻城狮带你10天搞定C++\\c++基础与提高.pdf) - 反斜杠
\"- 双引号
2.2.4 布尔类型------逻辑判断的核心
布尔类型只有两个值:true(真)和false(假):
cpp
#include <iostream>
int main() {
bool is_raining = true;
bool is_sunny = false;
std::cout << std::boolalpha; // 以文字形式输出布尔值
std::cout << "今天下雨吗? " << is_raining << std::endl; // 输出: true
std::cout << "今天晴天吗? " << is_sunny << std::endl; // 输出: false
// 布尔表达式
int a = 10, b = 20;
std::cout << "a > b ? " << (a > b) << std::endl; // 输出: false
std::cout << "a < b ? " << (a < b) << std::endl; // 输出: true
return 0;
}
2.3 复合数据类型------构建复杂数据结构
2.3.1 数组------有序数据集合
数组是一系列相同类型元素的集合:
cpp
#include <iostream>
int main() {
// 声明和初始化数组
int numbers[5] = {1, 2, 3, 4, 5}; // 固定大小数组
char name[] = "C++"; // 字符数组(字符串)
// 访问数组元素(索引从0开始)
std::cout << "第一个数字: " << numbers[0] << std::endl; // 输出: 1
std::cout << "最后一个数字: " << numbers[4] << std::endl; // 输出: 5
// 修改数组元素
numbers[2] = 100;
std::cout << "修改后的第三个数字: " << numbers[2] << std::endl; // 输出: 100
// 遍历数组
for(int i = 0; i < 5; i++) {
std::cout << "numbers[" << i << "] = " << numbers[i] << std::endl;
}
return 0;
}
2.3.2 结构体------自定义数据类型
结构体允许我们将不同类型的数据组合在一起:
cpp
#include <iostream>
#include <string>
// 定义结构体
struct Student {
std::string name;
int age;
double score;
bool is_graduate;
};
int main() {
// 创建结构体变量
Student stu1 = {"张三", 20, 85.5, false};
// 访问结构体成员
std::cout << "学生姓名: " << stu1.name << std::endl;
std::cout << "学生年龄: " << stu1.age << std::endl;
std::cout << "学生成绩: " << stu1.score << std::endl;
std::cout << "是否毕业: " << (stu1.is_graduate ? "是" : "否") << std::endl;
// 修改结构体成员
stu1.age = 21;
std::cout << "一年后年龄: " << stu1.age << std::endl;
return 0;
}
2.4 类型修饰符------精细化控制内存使用
C++提供了多种类型修饰符来更精确地控制数据存储:
cpp
#include <iostream>
int main() {
// signed - 有符号(默认)
signed int si = -100;
// unsigned - 无符号
unsigned int ui = 100U;
// short - 短整型
short sh = 32767;
// long - 长整型
long lo = 2147483647L;
// long long - 更长整型
long long ll = 9223372036854775807LL;
std::cout << "sizeof(short): " << sizeof(sh) << " bytes" << std::endl;
std::cout << "sizeof(int): " << sizeof(si) << " bytes" << std::endl;
std::cout << "sizeof(long): " << sizeof(lo) << " bytes" << std::endl;
std::cout << "sizeof(long long): " << sizeof(ll) << " bytes" << std::endl;
return 0;
}
2.5 类型推导------让编译器帮你思考
现代C++引入了自动类型推导功能,简化代码编写:
cpp
#include <iostream>
#include <typeinfo> // 用于获取类型信息
int main() {
// auto关键字 - 自动推导类型
auto x = 42; // 推导为int
auto y = 3.14; // 推导为double
auto z = "Hello"; // 推导为const char*
std::cout << "x的类型: " << typeid(x).name() << std::endl;
std::cout << "y的类型: " << typeid(y).name() << std::endl;
std::cout << "z的类型: " << typeid(z).name() << std::endl;
// decltype关键字 - 获取表达式的类型
int a = 10;
decltype(a) b = 20; // b的类型与a相同,都是int
std::cout << "a + b = " << (a + b) << std::endl;
return 0;
}
2.6 类型转换------不同类型间的桥梁
2.6.1 隐式类型转换
cpp
#include <iostream>
int main() {
int i = 100;
double d = i; // int自动转换为double
std::cout << "int to double: " << d << std::endl; // 输出: 100
// 混合运算中的类型转换
int a = 10;
double b = 3.0;
double result = a / b; // int先转换为double再运算
std::cout << "10 / 3.0 = " << result << std::endl; // 输出: 3.33333
return 0;
}
2.6.2 显式类型转换
cpp
#include <iostream>
int main() {
// C风格强制类型转换
double pi = 3.14159;
int int_pi = (int)pi; // 转换为整数,丢失小数部分
// C++风格强制类型转换
int int_pi2 = static_cast<int>(pi);
std::cout << "原始值: " << pi << std::endl; // 输出: 3.14159
std::cout << "转换后: " << int_pi << std::endl; // 输出: 3
// 注意潜在的问题
unsigned int large_uint = 4000000000U;
int negative_int = static_cast<int>(large_uint);
std::cout << "大无符号数: " << large_uint << std::endl;
std::cout << "转换为有符号: " << negative_int << std::endl;
return 0;
}
2.7 内存占用与对齐------深入了解底层机制
不同类型在内存中的占用情况:
cpp
#include <iostream>
struct Example1 {
char c; // 1字节
int i; // 4字节
short s; // 2字节
};
struct Example2 {
char c; // 1字节
short s; // 2字节
int i; // 4字节
};
int main() {
std::cout << "char大小: " << sizeof(char) << " 字节" << std::endl;
std::cout << "int大小: " << sizeof(int) << " 字节" << std::endl;
std::cout << "double大小: " << sizeof(double) << " 字节" << std::endl;
std::cout << "Example1大小: " << sizeof(Example1) << " 字节" << std::endl;
std::cout << "Example2大小: " << sizeof(Example2) << " 字节" << std::endl;
return 0;
}
2.8 最佳实践建议
-
选择合适的数据类型
- 根据数据范围选择合适的整数类型
- 对于财务计算优先使用整数避免浮点误差
- 字符串处理优先考虑std::string而非字符数组
-
注意边界条件
cpp// 错误示例:溢出风险 short small_num = 32767; small_num++; // 溢出! // 正确做法:选择合适类型 int larger_num = 32767; larger_num++; -
合理使用类型推导
cpp// 清晰明确的情况 auto result = calculate_something(); // 可能引起混淆的情况,建议显式声明 auto value = get_unknown_type(); // 不推荐 SpecificType value = get_unknown_type(); // 推荐
2.9 本章小结
本章详细介绍了C++的数据类型系统,涵盖了:
- 基本数据类型的特点和使用场景
- 复合数据类型的定义和操作
- 类型修饰符的作用和应用
- 类型推导和转换机制
- 内存布局和对齐原则
掌握这些基础知识对于编写高效、安全的C++程序至关重要。下一章我们将深入探讨变量和常量的使用,包括作用域、生命周期等重要概念。
专栏预告:第三章将详细介绍变量与常量的概念,探讨作用域、存储类别以及命名规范等内容,帮助读者建立良好的编程习惯。