Skip to content

基本数据类型

约 7249 字大约 24 分钟

2025-06-25

整数型: int、long long

一、知识点

整数型: int、long long

1.1 int 类型

  • 定义:C++中基础的整数类型,用于存储中等范围的整数,属于有符号类型(可表示正、负、零)。
  • 取值范围:通常为 -2³¹ ~ 2³¹ - 1(约 ±21 亿),占用 4 个字节(32 位),具体取决于编译器和操作系统(信奥赛中默认按 32 位处理)。
  • 声明与初始化
C++
int a;          // 仅声明,值为随机(未初始化)
int b = 10;     // 声明并初始化(推荐)
int c = -5;     // 存储负数
const int d = 100;  // 常量,值不可修改

1.2 long long 类型

  • 定义:用于存储大范围整数的类型,同样为有符号类型,是信奥赛中处理大数的核心类型。
  • 取值范围:通常为 -2⁶³ ~ 2⁶³ - 1(约 ±9×10¹⁸),占用 8 个字节(64 位),覆盖绝大多数信奥赛题目中的整数需求。
  • 声明与初始化
C++
long long x;            // 仅声明
long long y = 1e18;     // 声明并初始化大数(10¹⁸)
long long z = -12345678901234;  // 存储大负数
const long long MOD = 1e9 + 7;  // 信奥赛常用取模常量

1.3 两者核心区别

类型占用字节取值范围(约)适用场景
int4±21 亿小范围整数(如循环变量、小规模计数)
long long8±9×10¹⁸大范围整数(如大数运算、取模计算)

二、信奥赛核心应用

信奥赛核心应用

2.1 int 类型的核心场景

  • 循环控制:作为循环变量(如 for (int i = 0; i < 1e5; i++)),1e5 远小于 int 上限,无需担心溢出。
  • 小规模数据存储:存储题目中明确的小范围数据(如学生年龄、数组长度 ≤ 1e5)、简单计算结果(如两数之和 ≤ 2e9)。
  • 数组下标:数组下标默认使用 int 类型(如 arr[i],i 为 int 变量),因数组长度通常不超过 int 范围。

2.2 long long 类型的核心场景

  • 大数运算:处理超过 int 范围的计算(如两数相乘:1e9 × 1e9 = 1e18,需用 long long 存储结果)。
  • 取模运算:信奥赛中高频的取模场景(如 (a * b) % MOD,a、b 可能为 1e9,乘积 1e18 需 long long 避免溢出)。
  • 统计与计数:大规模数据的计数(如统计 1e6 个元素的总和,总和可能超过 21 亿)。
  • 算法场景:动态规划(DP)中的状态值、图论中的距离(如最短路径可能为 1e18)、组合数学中的大数(如阶乘、排列数)。

三、信奥赛避坑指南

信奥赛避坑指南

3.1 溢出问题(高频陷阱)

  • ❌ int 存储超范围值:当计算结果超过 int 上限(如 1e9 + 1e9 = 2e9 > 2¹⁰ - 1),会出现“溢出”,结果变为负数或随机值。
    解决:提前将变量声明为 long long,或计算时强制转换(如 (long long)a * b)。
C++
// 错误示例:int 溢出
int a = 1e9, b = 2;
int c = a * b;  // 结果为 -2147483648(溢出)

// 正确示例:用 long long 或强制转换
long long d = (long long)a * b;  // 结果为 2e9
  • ❌ long long 初始化遗漏后缀:直接写 long long x = 1e18 虽可行,但部分编译器可能将 1e18 视为浮点型,存在精度损失风险。
    解决:用整数常量初始化,或加 LL 后缀(如 long long x = 1000000000000000000LL)。

3.2 类型不匹配

  • ❌ 混合运算隐式转换:int 与 long long 混合运算时,int 会隐式转为 long long,但需注意赋值目标类型。
    错误示例
C++
long long a = 1e18;
int b = a;  // 错误:a 超出 int 范围,赋值后结果错误

解决:确保赋值目标类型与计算结果类型一致(优先用 long long)。

  • ❌ 函数参数/返回值类型错误:如函数返回值为 int,但实际结果超过 int 范围,导致结果截断。
    正确示例
C++
// 计算两数乘积,返回 long long
long long multiply(int a, int b) {
    return (long long)a * b;  // 强制转换后返回
}

3.3 输入输出格式错误

  • ❌ long long 用错 scanf/printf 格式符:scanf("%d", &x) 用于 int,long long 需用 %lld 格式符(Windows 下部分编译器用 %I64d,信奥赛中默认 %lld)。
    错误示例
C++
long long x;
scanf("%d", &x);  // 错误:格式符与类型不匹配,读取结果错误

正确示例

C++
scanf("%lld", &x);  // 读取 long long
printf("%lld\n", x);  // 输出 long long

四、信奥赛实战

信奥赛实战

4.1 实战 1:int 处理小规模数据(统计数组和)

C++

4.2 实战 2:long long 处理大数乘法与取模

C++

4.3 实战 3:long long 解决溢出问题(阶乘计算)

C++

4.4 实战 4:混合类型运算的强制转换

C++

实数型:float、double

一、知识点

实数型:float、double

1.1 float 类型

  • 定义:C++中基础的单精度浮点类型,用于存储带小数部分的数值,属于实数型。
  • 存储特性:占用4个字节(32位),由符号位、指数位和尾数位组成,有效精度约67位十进制数字(即小数点后最多准确表示67位)。
  • 取值范围:约 ±1.175×10⁻³⁸ ~ ±3.403×10³⁸,可表示较大或较小的实数,但精度有限。
  • 声明与初始化
C++
float a;          // 仅声明,值为随机(未初始化)
float b = 3.14f;  // 声明并初始化,后缀f表示float类型(否则默认double)
float c = 1e3f;   // 科学计数法,1e3f = 1000.0f

1.2 double 类型

  • 定义:双精度浮点类型,是信奥赛中处理实数的核心类型,精度高于float。
  • 存储特性:占用8个字节(64位),有效精度约15~17位十进制数字,能更准确地表示带小数的数值,减少精度误差。
  • 取值范围:约 ±2.225×10⁻³⁰⁸ ~ ±1.798×10³⁰⁸,覆盖几乎所有信奥赛题目中的实数需求。
  • 声明与初始化
C++
double x;            // 仅声明
double y = 3.1415926535;  // 声明并初始化,默认double类型,无需后缀
double z = 1.23e-5;  // 科学计数法,1.23e-5 = 0.0000123
const double PI = acos(-1.0);  // 信奥赛常用π的精确表示(利用数学函数)

1.3 两者核心区别

类型占用字节有效精度(十进制位数)取值范围(约)适用场景
float46~7±1e-38 ~ ±3e38对精度要求低、内存受限的场景(极少用)
double815~17±2e-308 ~ ±1.8e308信奥赛中所有实数场景(优先选择)

二、信奥赛核心应用

信奥赛核心应用

2.1 float 类型的应用场景(极少)

  • 特殊场景:仅当题目明确要求使用float(如硬件限制、数据量极大且精度要求极低),否则几乎不用,因精度不足易导致错误。
  • 示例:存储大规模但无需精确的传感器数据(如温度 ±0.1℃ 误差可接受),但信奥赛中此类场景罕见。

2.2 double 类型的核心场景

  • 几何计算:处理坐标、距离、面积、体积等(如两点间距离计算 sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)),需double保证精度)。
C++
double x1=1.2, y1=3.4, x2=5.6, y2=7.8;
double dist = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));  // 两点间距离
  • 科学计算:涉及小数的公式计算(如物理公式、概率统计、平均值计算)。
C++
int n = 5;
double sum = 12.5 + 13.8 + 11.2 + 14.1 + 15.3;
double avg = sum / n;  // 计算平均值,用double保证精度
  • 高精度比较:题目中需判断实数是否相等(如二分查找的终止条件 abs(l - r) < 1e-8),double的高精度可减少误判。
  • 函数返回值:数学函数(如 sincoslogsqrt)的返回值默认是double类型,需用double接收结果。

三、信奥赛避坑指南

信奥赛避坑指南

3.1 精度误差陷阱(高频错误)

  • ❌ 用float处理高精度需求:float仅6~7位精度,复杂计算后误差会累积(如 0.1f + 0.2f = 0.30000001f,而非0.3)。
    解决:信奥赛中所有实数计算统一用double,避免float。
  • ❌ 直接用 == 比较实数:由于精度误差,两个理论相等的实数可能实际存储值不同(如 0.1 + 0.2 == 0.3 结果为false)。
    解决:判断两者差值的绝对值是否小于极小值(如 abs(a - b) < 1e-8,1e-8为“精度阈值”,可根据题目调整)。
C++
double a = 0.1 + 0.2;
double b = 0.3;
// if (a == b)  // 错误:结果为false
if (abs(a - b) < 1e-8)  // 正确:认为a和b相等
    cout << "相等" << endl;

3.2 类型声明与初始化陷阱

  • ❌ 实数常量未加float后缀却赋值给float:C++中默认实数常量(如3.14)是double类型,赋值给float会触发“精度截断”警告。
    解决:float变量初始化时加 f 后缀(如 float x = 3.14f),或直接用double。
  • ❌ 整数除法结果赋值给实数:如 int a=1, b=2; double c = a / b;,a/b先按整数除法得0,再转为double 0.0,而非0.5。
    解决:将其中一个操作数强制转为double(如 double c = (double)a / bdouble c = 1.0 * a / b)。

3.3 输入输出格式陷阱

  • ❌ scanf/printf格式符错误:float用 %f,double用 %lf(printf中double也可简化为 %f,但scanf必须用 %lf,否则读取数据错误)。
    错误示例
C++
double x;
scanf("%f", &x);  // 错误:%f用于float,double需%lf
// printf("%lf", x);  // 正确,或简化为printf("%f", x)

正确示例

C++
double x;
scanf("%lf", &x);  // 读取double
printf("x = %.6f\n", x);  // 输出,保留6位小数(.6f控制格式)

3.4 计算逻辑陷阱

  • ❌ 大数与小数相加:当一个极大的数和一个极小的数相加时,小数可能被“忽略”(如 1e18 + 1.0 = 1e18,因double无法精确表示1e18+1)。
    解决:调整计算顺序,先加小数部分,再加大数(如 (a + b) + c 改为 (b + c) + a,若b、c为小数)。
  • ❌ 分母为0的实数运算:如 double x = 1.0 / 0.0,会得到 inf(无穷大),导致后续计算错误。
    解决:计算前判断分母是否接近0(如 if (abs(denominator) < 1e-8) { /* 处理分母为0的情况 */ })。

四、信奥赛实战

信奥赛实战

4.1 实战 1:double 计算两点间距离

C++

输入1.2 3.4 5.6 7.8
输出两点间距离:6.2225

4.2 实战 2:实数比较(二分查找实数解)

C++

4.3 实战 3:避免整数除法误差

C++

说明:若写 sum += 1 / i,则1/i按整数除法得0,总和为0.0,错误;1.0 / i 强制转为实数除法,结果正确。

4.4 实战 4:double 存储π并计算圆面积

C++

输入2.5
输出圆面积:19.634954085

字符型:char

一、知识点

字符型:char

1.1 char 类型的定义与存储

  • 定义:C++中用于存储单个字符的基本数据类型,本质是通过ASCII码(美国信息交换标准代码)表示字符,属于整数型的特殊子集。
  • 存储特性:占用1个字节(8位),取值范围通常为 -128 ~ 127(有符号)或 0 ~ 255(无符号,需显式声明 unsigned char),每个字符对应唯一的ASCII码值(如 'A' 对应65,'0' 对应48)。
  • 声明与初始化
C++
char c1;          // 仅声明,值为随机(未初始化)
char c2 = 'A';    // 用单引号包裹单个字符初始化(必须单引号,双引号为字符串)
char c3 = 65;     // 用ASCII码值初始化,等价于 c3 = 'A'
const char c4 = 'z';  // 常量字符,值不可修改

1.2 char 类型的核心属性

  • ASCII码映射:字符与整数直接对应,可参与整数运算(如 'A' + 32 = 'a',利用ASCII码差值实现大小写转换)。
  • 特殊字符
    • 转义字符:以 \ 开头的特殊字符,如 '\n'(换行)、'\t'(制表符)、'\0'(空字符,字符串结束标志)、'\\'(表示单个 \)。
    • 可打印字符:如字母(a-z、A-Z)、数字(0-9)、符号(+、-、= 等),ASCII码范围 32 ~ 126。
    • 不可打印字符:如控制字符('\n''\r'),ASCII码范围 0 ~ 31 和 127。

二、信奥赛核心应用

信奥赛核心应用

2.1 字符输入输出

  • 单个字符输入
    • cin >> c:读取单个字符,自动跳过空格、换行、制表符(不读取空白字符)。
    • cin.get(c)getchar():读取包括空白字符在内的所有单个字符(需处理换行残留)。
  • 单个字符输出
    • cout << c:直接输出字符(如 cout << 'A' 输出 'A')。
    • putchar(c):C风格输出,效率略高(如 putchar('0') 输出 '0')。
C++
char c;
cin.get(c);  // 读取包括空格的单个字符
cout << "你输入的字符是:" << c << endl;

2.2 字符判断与转换

  • 判断字符类型:利用 <cctype> 头文件中的函数(信奥赛高频):
    • isalpha(c):判断是否为字母(a-z、A-Z)。
    • isdigit(c):判断是否为数字(0-9)。
    • islower(c)/isupper(c):判断是否为小写/大写字母。
    • isspace(c):判断是否为空白字符(空格、换行、制表符等)。
  • 字符转换
    • tolower(c):将大写字母转为小写(如 'A' → 'a',非字母不变)。
    • toupper(c):将小写字母转为大写(如 'b' → 'B',非字母不变)。
C++
#include <cctype>
char c = 'B';
if (isalpha(c)) {  // 判断是字母
    c = tolower(c);  // 转为小写
    cout << c;  // 输出 'b'
}

2.3 构建C风格字符串

  • 定义:以 '\0'(空字符,ASCII码0)结尾的字符数组,本质是多个char的连续存储(如 "hello" 存储为 'h' 'e' 'l' 'l' 'o' '\0')。
  • 应用:存储短文本、处理输入的字符串(如读入单词、句子),信奥赛中常与 <cstring> 头文件函数配合使用(如 strlen 求长度、strcpy 复制字符串)。
C++
#include <cstring>
char str[10] = "abc";  // 自动添加 '\0',数组存储为 'a' 'b' 'c' '\0' ...
cout << strlen(str);  // 输出3(仅统计 '\0' 前的字符数)

三、信奥赛避坑指南

信奥赛避坑指南

3.1 字符与字符串混淆(高频错误)

  • ❌ 用双引号初始化单个char:char c = "A"; 错误,双引号表示字符串(地址),单引号才表示单个字符,正确写法为 char c = 'A';
  • ❌ 字符数组未加 '\0':构建C风格字符串时,若未手动添加 '\0',使用 strlencout 等会导致“越界访问”(读取到随机字符直到遇到 '\0')。
    解决:初始化时显式添加或利用字符串常量自动添加(如 char str[] = "test"; 自动包含 '\0')。
C++
// 错误示例:无 '\0',strlen结果不确定
char str1[3] = {'a', 'b', 'c'};
// 正确示例:添加 '\0'
char str2[4] = {'a', 'b', 'c', '\0'};

3.2 输入输出残留问题

  • cin >> c 跳过空白字符导致漏读:如输入 A B(A和B间有空格),第一次 cin >> c 读 'A',第二次读 'B',空格被跳过;若需读取空格,需用 cin.get(c)getchar()
  • ❌ 读取字符后残留换行符:如先用 cin >> n 读整数,再用 cin.get(c) 读字符,此时 c 会读取到 cin >> n 残留的换行符 '\n'
    解决:读取字符前用 cin.ignore() 清除缓冲区残留的换行符。
C++
int n;
cin >> n;
cin.ignore();  // 清除换行符
char c;
cin.get(c);  // 正确读取后续字符

3.3 ASCII码使用陷阱

  • ❌ 混淆字符与数字的ASCII码:如 char c = '5' 对应的ASCII码是53,而非整数5,直接参与运算会出错(如 '5' + 1 = 54,而非6)。
    解决:字符转整数需减去 '0'(如 int num = c - '0'),整数转字符需加上 '0'(如 char c = num + '0')。
C++
char c = '8';
int num = c - '0';  // 正确:num = 8
char new_c = num + 2 + '0';  // 正确:new_c = '10'?不,num+2=10,10+'0'=58,对应 ':',需注意数字范围

3.4 无符号char的误用

  • ❌ 未声明 unsigned char 却存储超过127的值:默认char为有符号(-128127),若存储128255的ASCII码(如扩展ASCII字符),会显示为负数。
    解决:需显式声明 unsigned char,如 unsigned char c = 200;

四、信奥赛实战

信奥赛实战

4.1 实战1:字符大小写转换

C++

输入B输出转换为小写:b输入3输出输入的不是字母

4.2 实战2:统计字符串中的字母和数字个数

C++

输入Hello 2024!输出字母个数:5数字个数:4

4.3 实战3:用char数组实现字符串逆序

C++

4.4 实战4:读取单个字符处理密码验证(忽略大小写)

C++

输入pass123输出密码正确输入Pass456输出密码错误

布尔型:bool

一、知识点

布尔型:bool

1.1 bool 类型的定义与取值

  • 定义:C++中的布尔型(逻辑型)数据类型,专门用于表示“真”或“假”两种逻辑状态,是信奥赛中处理条件判断、状态标记的核心类型。
  • 取值范围:仅有两个可能值——true(真,对应整数1)和false(假,对应整数0),占用内存大小通常为1字节(部分编译器可能优化为更小空间,但不影响使用)。
  • 声明与初始化
C++
bool flag1;          // 仅声明,未初始化,值为随机(危险,需避免)
bool flag2 = true;   // 初始化为真
bool flag3 = false;  // 初始化为假
bool flag4 = (3 > 2); // 用逻辑表达式初始化(3>2为真,flag4=true)
const bool IS_OK = true; // 布尔型常量,值不可修改

1.2 bool 类型的隐式转换

  • 与整数的转换true 隐式转为整数1,false 隐式转为整数0;反之,非0整数隐式转为true,0转为false
C++
bool b1 = 5;    // 5非0,b1=true
bool b2 = 0;    // 0转为false
int num1 = true; // num1=1
int num2 = false;// num2=0
  • 与表达式的结合:关系表达式(如a > b)、逻辑表达式(如a && b)的返回值默认是bool类型,可直接赋值给bool变量。
C++
int a=3, b=5;
bool isGreater = (a > b); // a>b为假,isGreater=false
bool hasValid = (a != 0) || (b != 0); // 逻辑或为真,hasValid=true

二、信奥赛核心应用

信奥赛核心应用

2.1 条件判断的返回值接收

  • if/else 语句:用bool变量存储条件判断结果,简化复杂条件的逻辑表达。
C++
int score = 85;
bool isPass = (score >= 60); // 判断是否及格,结果存为bool
if (isPass) {
    cout << "及格" << endl;
} else {
    cout << "不及格" << endl;
}

2.2 状态标记与开关控制

  • 标记数据状态:用bool变量标记数据是否满足特定条件(如是否为素数、是否已访问、是否被选中)。
C++
// 判断一个数是否为素数,用isPrime标记状态
int n = 29;
bool isPrime = true;
for (int i = 2; i * i <= n; i++) {
    if (n % i == 0) {
        isPrime = false; // 能被整除,不是素数
        break;
    }
}
  • 功能开关:控制某个功能是否启用(如调试模式开关、是否显示详细信息)。
C++
bool showDetail = true; // 开关:是否显示详细信息
int sum = 100;
cout << "总和:" << sum;
if (showDetail) {
    cout << "(计算范围:1~20)" << endl; // 开关开启时显示细节
}

2.3 逻辑运算的结果处理

  • 参与逻辑运算(&&逻辑与、||逻辑或、!逻辑非)时,直接使用bool变量可使代码更清晰,避免冗余的表达式书写。
C++
bool hasId = true;    // 是否有身份证
bool hasTicket = false;// 是否有车票
bool canBoard = hasId && hasTicket; // 同时满足才能上车,canBoard=false
bool isBlocked = !(hasId || hasTicket); // 两者都没有则被阻止,isBlocked=false

三、信奥赛避坑指南

信奥赛避坑指南

3.1 未初始化的bool变量(高频危险)

  • ❌ 声明bool变量后未初始化:未初始化的bool变量值为随机(可能是true也可能是false),导致逻辑判断异常。
    解决:声明时必须初始化(至少初始化为false),如 bool flag = false;
C++
// 错误示例:未初始化,flag值随机
bool flag;
if (flag) { /* 逻辑不可控 */ }
  
// 正确示例:初始化
bool flag = false;

3.2 隐式转换的误用

  • ❌ 将非0整数直接视为true却忽略具体值:虽然非0整数转为booltrue,但直接赋值可能掩盖逻辑错误(如误将计算结果“5”当作“真”,而实际需要判断“是否等于5”)。
    解决:明确写出逻辑表达式,避免直接赋值整数,如 bool isFive = (num == 5); 而非 bool isFive = num;(当num=5时结果一致,但num=3时前者false、后者true,易出错)。
  • ❌ 混用bool与整数运算:将bool变量当作整数参与加减乘除,虽语法允许,但逻辑上无意义,且可能导致结果混乱。
    错误示例
C++
bool a = true, b = false;
int res = a + b; // res=1+0=1,语法合法但逻辑冗余,应避免

3.3 逻辑运算的短路特性忽略

  • ❌ 依赖短路运算后的未执行代码:逻辑与(&&)中,若前半部分为false,后半部分不再执行;逻辑或(||)中,若前半部分为true,后半部分不再执行。忽略此特性可能导致预期外的逻辑错误。
    示例
C++
bool hasData = false;
int data = 0;
// 错误:因hasData=false,data++未执行,data仍为0
if (hasData && (data++ > 0)) { /* ... */ }
cout << data; // 输出0,而非1

解决:若需执行后半部分代码,需拆分逻辑,避免依赖短路特性。

3.4 冗余的bool判断

  • ❌ 对bool变量进行多余的等于判断:如 if (isPass == true)if (isPass == false),语法正确但冗余,降低代码可读性。
    解决:直接使用bool变量作为条件,如 if (isPass)(等价于isPass==true)、if (!isPass)(等价于isPass==false)。
C++
bool isPass = true;
// 冗余写法
if (isPass == true) { /* ... */ }
// 简洁写法(推荐)
if (isPass) { /* ... */ }

三、信奥赛实战

信奥赛实战

4.1 实战1:用bool标记素数状态

C++

输入23输出23是素数输入15输出15不是素数

4.2 实战2:用bool控制循环与功能开关

C++

输入3 -5 7 0输出所有正数的和:10

4.3 实战3:bool数组标记访问状态(图论/数组去重)

C++

输出去重后的数组:5 3 7 9 2

4.4 实战4:逻辑运算结合bool判断(复合条件)

C++

输出可以参加竞赛;若score=75,则输出无法参加竞赛