C++基础(二)——超详细变量与基本数据类型

张开发
2026/4/20 8:25:16 15 分钟阅读

分享文章

C++基础(二)——超详细变量与基本数据类型
在上一篇文章中我们成功地让计算机喊出了那句振聋发聩的“Hello world”正式跨入了C的大门。但如果你只满足于让计算机“喊口号”那就像买了一台顶配游戏电脑却只用来玩扫雷——太浪费了。真正的编程是要让计算机帮我们“记事情”和“算东西”。比如让程序记住你的年龄、计算购物车的总价、判断你输入的密码是否正确。。。而要做到这些你首先得学会在C里创建变量以及搞清楚各种数据类型到底是个什么鬼。别担心虽然“数据类型”听起来像是一本正经的教科书词汇但在本文中我会带你彻底搞懂C的变量和基本数据类型。准备好了吗让我们开始给数据找“家”一、变量一个贴了标签的盒子1.1 变量是什么想象一下你正在搬家把所有东西胡乱堆在房间里显然不是个好主意。聪明的做法是找来各种盒子把书放进一个盒子把衣服放进另一个盒子然后在每个盒子上贴个标签——“书”、“冬装”、“厨具”。。。在C的世界里变量就是这样一个“贴了标签的盒子”。这个盒子用来存放你的数据而标签就是变量名。当你需要用到这些数据的时候直接喊这个标签的名字计算机就知道你要拿哪个盒子里的东西了。用程序员的话说变量是计算机内存中一块被命名的存储空间用来存放特定类型的数据。1.2 创建变量的语法三要素缺一不可在C中创建一个变量你需要告诉计算机三件事1. 数据类型这个盒子准备装什么东西整数小数字符2. 变量名这个盒子叫什么名字方便你以后喊它3. 初始值可选但强烈建议盒子里一开始放什么不放东西的盒子就是个“薛定谔的盒子”——里面的值是随机的语法格式如下数据类型 变量名 初始值;举个例子int age 18; // 创建一个叫age的盒子里面放整数18 double price 99.9; // 创建一个叫price的盒子里面放小数99.9 char grade A; // 创建一个叫grade的盒子里面放字符A bool isPassed true; // 创建一个叫isPassed的盒子里面放“真”是不是很简单接下来我们来详细认识一下这些“数据类型”到底是什么。二、基本数据类型C的基本内置类型可以分为四大类整型、浮点型、字符型和布尔型。这四位各有各的绝活分管不同类型的数据。我们先来一张总览表让你心中有数类型分类具体类型占用空间存什么示例整型short2字节小整数short s 100;整型int4字节普通整数int age 25;整型long4/8字节较大整数long pop 1000000L;整型long long8字节超大整数long long big 123456789LL;浮点型float4字节单精度小数float pi 3.14;浮点型double8字节双精度小数double salary 1234.56;字符型也可作整型char1字节单个字符char ch A;布尔型bool1字节真/假bool ok true;等等你可能会问为什么整型要分这么多种 好问题这涉及到计算机内存的“寸土寸金”。不同整型占用的内存空间不同能表示的数字范围也不同。选对了类型既能省内存又能避免数据溢出。2.1 整型Integer专门装整数的盒子整型是C中最常用的数据类型之一用来存放没有小数部分的整数。C提供了四种“尺寸”的整型盒子从小到大依次是· short短整型占2个字节16位取值范围约-32,768 到 32,767。· int标准整型占4个字节32位取值范围约-21亿 到 21亿。这是最常用的整型。· long长整型在Windows和32位Linux下占4个字节在64位Linux下占8个字节。取值范围因平台而异。· long long长长整型占8个字节64位取值范围约-9百亿亿 到 9百亿亿。这是整型界的“巨无霸”。有符号和无符号每个整型还有一个“双胞胎兄弟”——加上unsigned前缀的无符号版本。无符号整型只能存储0和正数但正数的上限翻倍。· int-2,147,483,648 到 2,147,483,647· unsigned int0 到 4,294,967,295如果你确定某个变量永远不会是负数比如年龄、数量、编号可以用unsigned来获得更大的正数范围。不过注意给无符号变量赋一个负数会得到意想不到的结果——比如unsigned char ch -1结果可能是255。如何知道一个类型占多少字节C提供了一个神奇的运算符sizeof()可以帮你查看任意数据类型或变量占用的字节数#include iostream using namespace std; int main() { cout short 占 sizeof(short) 字节 endl; cout int 占 sizeof(int) 字节 endl; cout long 占 sizeof(long) 字节 endl; cout long long 占 sizeof(long long) 字节 endl; return 0; }运行这段代码你就能看到各种整型在你电脑上的实际大小了。2.2 浮点型Floating-point装小数的盒子生活中不只有整数——比如你的考试成绩是98.5分一杯奶茶是15.8元π约等于3.1415926……这时候就需要浮点型上场了。C提供了三种精度的浮点型· float单精度浮点型占4个字节有效数字约7位。· double双精度浮点型占8个字节有效数字约15~16位。· long double扩展精度浮点型占12或16个字节取决于编译器。选型建议除非你有特别的理由比如嵌入式设备内存极度紧张否则直接用double。double精度更高在现代CPU上的运算速度甚至可能比float还快而且可以避免很多因精度不足导致的“灵异Bug”。重要提醒写float类型的字面量时记得在数字后面加一个f因为C默认把所有带小数点的数字当作double类型处理。float pi 3.14f; // 正确明确告诉编译器这是float float pi 3.14; // 编译器会警告把double塞进float可能丢失精度科学计数法浮点数还支持科学计数法写法非常直观float f1 3e2; // 3 × 10² 300 float f2 3e-2; // 3 × 10⁻² 0.032.3 字符型char装单个字符的盒子字符型char用来存储单个字符——比如A、b、7、。它只占1个字节。几个重要规则· 字符必须用单引号括起来A不能用双引号双引号是给字符串用的。· 单引号里面只能有一个字符abc是错误的。· char变量实际上存储的不是字符本身而是该字符对应的ASCII码一个0~127的整数。这意味着char和整数之间存在奇妙的“血缘关系”char ch A; cout ch endl; // 输出A cout (int)ch endl; // 输出65A的ASCII码 ch 66; // 直接把ASCII码赋值给char cout ch endl; // 输出B66对应字符B常见的ASCII码A是65a是970是48。这个知识点以后处理字符时会经常用到。算了还是温馨地贴张表在这里吧宽字符wchar_t如果你需要处理中文、日文等非英文字符char可能不够用1字节只能表示256种字符。这时可以用wchar_t宽字符型通常占2或4个字节wchar_t ch L中; // 注意前面的L前缀2.4 布尔型bool只有两种答案的盒子布尔型bool是C中最“单纯”的数据类型——它的取值只有两个true真和false假。bool isStudent true; bool hasLicense false;布尔型通常用在条件判断中if (isStudent) { cout 你可以享受学生优惠 endl; }有趣的事实在C中布尔型只占1个字节。输出bool变量时默认显示1true或0false。如果你想让输出显示true/false文字可以使用std::boolalphacout boolalpha isStudent endl; // 输出true2.5 动手实践创建一个完整的变量演示程序理论讲完了让我们来写一个综合性的程序把所有数据类型都用上。打开你的Visual Studio 2026创建一个新的控制台项目把以下代码复制进去#include iostream using namespace std; int main() { // 整型 short age 25; int population 1400000000; // 14亿 long long stars 100000000000LL; // 1000亿颗星星 // 浮点型 float pi 3.14159f; double precisePi 3.141592653589793; // 字符型 char grade D; //呵呵哒 // 布尔型 bool isCppFun true; // 输出所有变量 cout 我的第一个变量演示程序 endl; cout 年龄: age endl; cout 中国人口: population endl; cout 银河系恒星数量(估算): stars endl; cout π的值(float): pi endl; cout π的值(double): precisePi endl; cout 你的数学作业等级: grade endl; cout C有趣吗? boolalpha isCppFun endl; // 用sizeof看看各类型的大小 cout \n 各类型占用的内存 endl; cout short: sizeof(short) 字节 endl; cout int: sizeof(int) 字节 endl; cout long long: sizeof(long long) 字节 endl; cout float: sizeof(float) 字节 endl; cout double: sizeof(double) 字节 endl; cout char: sizeof(char) 字节 endl; cout bool: sizeof(bool) 字节 endl; system(pause); return 0; }运行它看看输出结果。这比单纯看理论有意思多了。嗯对不许说我的教程很无聊三、变量的“规矩”命名、初始化与作用域知道了有哪些数据类型接下来我们要学习如何正确地“使用”变量。这部分有很多容易踩的坑请打起精神3.1 变量命名有规矩也有“潜规则”在C中给变量起名字有些是硬性规定有些是行业“潜规则”。硬性规定必须遵守· 只能由字母、数字、下划线组成。· 不能以数字开头2age不行age2可以。· 区分大小写age和Age是两个不同的变量。· 不能是C关键字比如int、return、if等。潜规则强烈建议遵守· 起有意义的名字age比a好一万倍。· 局部变量用小驼峰命名法studentCount、totalPrice。· 常量用全大写下划线MAX_SIZE、PI。· 布尔变量建议以is、has、can开头isValid、hasLicense。我曾经见过有人把变量起名为a1、a2、a3……三天后他自己回来看代码崩溃地问“这些a到底都是干嘛的”——不要成为这样的人。3.2 初始化别让你的盒子变成“垃圾箱”在C中未初始化的局部变量里面装的是垃圾值内存中残留的随机数据。如果你不小心使用了它程序可能会表现出各种诡异的行为。int x; // 没初始化x里面是随机值 cout x; // 输出什么天知道可能是42可能是-858993460三种初始化方式// 方式1传统的等号赋值 int age 18; // 方式2构造函数式初始化 int age(18); // 方式3C11统一初始化更安全 int age{18};统一初始化{}的好处是它会阻止“窄化转换”——比如把小数塞进整数变量时{}会直接报错提醒你而只会默默截断小数部分让你不知不觉中丢失精度。但平时用的最多的一般是等号赋值。默认初始化规则速查表变量类型未显示初始化时的值全局变量0局部变量未定义随机垃圾值static局部变量0类类型调用默认构造函数3.3 作用域与生命周期变量“活”在哪里、“活”多久这是新手最容易混淆的两个概念但理解它们非常重要。· 作用域Scope 变量名在程序的哪些地方可以被访问。“我能去哪里找到它”· 生命周期Lifetime 变量在内存中存在的时间段。“它从出生到死亡经历了多久”局部变量在函数或代码块{}内部定义· 作用域只在其所在的{}内部可见。· 生命周期进入{}时创建离开{}时销毁。void func() { int x 10; // x 在这里出生 // x 在这里可用 } // 离开大括号x 死亡 // 这里无法访问 x编译器会报错全局变量在所有函数外部定义· 作用域整个文件甚至整个程序如果用extern声明。· 生命周期从程序开始运行到程序结束。int global 100; // 全局变量 void func() { cout global; // 可以访问 }重要提醒全局变量虽然方便但用多了会导致代码难以维护任何地方都能改它出Bug时你根本不知道是谁改的。能用局部变量解决的问题尽量别用全局变量。四、类型转换当不同“盒子”相遇时在编程中经常需要把一种类型的变量“变”成另一种类型。比如把double转成int去掉小数部分或者把int转成double做精确除法。C中有两种类型转换方式隐式转换编译器自动帮你做和显式转换你明确告诉编译器要转换。4.1 隐式转换编译器“偷偷”帮你转当你在表达式中混用了不同类型的数据时C编译器会按照一定的规则自动进行类型转换。规则很简单“小盒子”里的东西可以自动放进“大盒子” ——因为不会丢失数据。int a 10; double b a; // 隐式转换int - double没问题 cout b; // 输出10.0 double c 3.14; int d c; // 隐式转换double - int小数部分被截断 cout d; // 输出3不是四舍五入是直接砍掉第二个例子中3.14被转成int时丢掉了小数部分编译器虽然会帮你转但可能会给一个警告。这种“精度丢失”是隐式转换最常见的坑4.2 显式转换C风格的强制转换为了避免隐式转换带来的意外现代C推荐使用显式类型转换。其中最常用的是static_cast。语法static_cast目标类型(源数据)double pi 3.14159; int intPi static_castint(pi); // 显式转换为int结果为3 int a 5; int b 2; double result static_castdouble(a) / b; // 先把a转成double再做除法 cout result; // 输出2.5而不是2为什么推荐static_cast而不是老式的C风格转换如(int)pi1. 意图明确一眼就能看出这是在进行类型转换。2. 编译器检查更严格如果转换不合理编译器会报错提醒你。3. 容易搜索在大型项目中你可以轻松搜索到所有的static_cast位置。C还有另外三种强制转换——dynamic_cast用于类的多态转换、const_cast用于去掉const属性和reinterpret_cast用于底层的二进制重解释。不过对于新手来说先掌握static_cast就完全够用了。五、常量写死的“铁盒子”有时候你希望某个变量的值永远不会被改变——比如圆周率π、一天的小时数、程序的版本号。这时候你就需要常量了。5.1 const运行时常量const是C中最常用的常量修饰符。被const修饰的变量一旦初始化就不能再次赋值。const double PI 3.1415926; const int HOURS_PER_DAY 24; // PI 3.14; // 编译错误不能修改const变量const的规则· 必须在声明时初始化不能先声明后赋值。· 初始化后不可修改。· 局部const存储在栈上全局const存储在只读数据区修改会导致程序崩溃。5.2 constexpr编译时常量C11起constexpr是C11引入的更强大的常量关键字。它要求变量的值在编译阶段就能确定。constexpr int square(int x) { return x * x; } constexpr int SIZE 100; // 编译期常量 constexpr int AREA square(10); // 也是编译期常量因为square是constexpr函数 int n 10; // constexpr int SIZE2 n; // 错误n的值在编译时不确定const vs constexpr· const变量不可修改但值可以在运行时确定。· constexpr变量不可修改且值必须在编译时确定。对于新手来说大部分场景用const就够了。当你需要定义数组大小、模板参数等必须在编译期确定的常量时再用constexpr。六、总结与巩固恭喜你读到这里你已经掌握了C变量和数据类型的基础知识思考题检验你是否真的学会了1. 以下哪个变量名是合法的2cool、_count、my-name、int2. 把double类型的3.99赋值给int类型变量结果是多少3. unsigned int的取值范围是多少它能存负数吗4. 局部变量不初始化就使用会发生什么5. 如果想把int和double做除法并得到精确结果应该怎么做答案1.只有_count合法2.结果是3截断不是四舍五入3.0到约42亿不能存负数4.里面的值是随机的垃圾值5.用static_castdouble把int转成double再做除法。在下一篇文章中我们将学习C的运算符与表达式——换句话说我们要开始教计算机“算算术”了。到时候你会发现原来编程中的加减乘除比小学数学要“精彩”得多比如整数除法会直接砍掉余数这种骚操作。动手试试今天学到的内容吧把代码复制到VS2026里跑一跑改改数字看看会发生什么。编程这东西光看不练是永远学不会的。可能内容有点繁杂好好消化不懂的欢迎在评论区提问呀真的很欢迎谢谢大家—— 一个也曾被未初始化变量坑得怀疑人生的C学习者

更多文章