C++系列01:C11统一初始化及C++输入输出

张开发
2026/4/13 4:19:26 15 分钟阅读

分享文章

C++系列01:C11统一初始化及C++输入输出
一、C统一的初始化1.结构体的字节大小计算核心规则内存对齐关键知识点基本数据类型字节数32/64 位通用char1 |short2 |int4 |float4 |double8 | 指针 4 (32 位)/8 (64 位)三大对齐规则必须严格遵守成员对齐每个成员的起始地址必须是自身字节数的整数倍。整体对齐结构体总大小必须是最大基础成员字节数的整数倍不足则补字节。嵌套结构体嵌套的结构体算一个成员对齐模数取所有成员中最大的基础类型字节数。例子1简单结构体struct Test { char a; // 1字节 int b; // 4字节 char c; // 1字节 };12字节char a占 1 字节地址0int b必须从 4 的整数倍开始 → 从4开始加-8char c占 1 字节地址8(819,不是4的倍数-12)整体对齐最大成员是 int (4)总大小必须是 4 的倍数 → 总大小 12 字节例子2调整成员顺序大小会变struct Test { char a; // 1 char c; // 1 int b; // 4 };8字节例子3嵌套结构体struct A { char x; int y; }; // 大小 8 字节 struct B { char m; struct A n; // 嵌套结构体 double p; // 8字节 };24字节快速计算口诀找出结构体中最大的基础类型字节数记为 M按规则排布每个成员补齐空字节总大小向上取整为M 的整数倍2.C11的初始化1.2.1、C传统初始化写法// 基本类型 int a 10; float b 3.14f; char c A; // 数组 int arr[3] {1, 2, 3}; // 结构体 struct Student { int id; char name[10]; }; struct Student s {101, Tom};C 初始化的缺点无法统一所有类型的初始化语法不能初始化动态数组、容器C 无 STL容易出现窄化转换隐式丢精度语法不统一容易写错1.2.2、C11统一初始化写法C11 推出{}列表初始化花括号初始化统一所有对象的初始化方式是现代 C 推荐的首选写法具有更严格的数据类型检查。// 空初始化自动赋值为 0 / nullptr int a{}; //int a 0 double b{}; //int b 0.0 int* p{}; //int p nullptr // 直接赋值 int x{10};//int x10 float y{3.14f};//float y 3.14f // 数组 int arr[]{1,2,3}; // int arr[]{1,2,3}; // STL容器C语言没有 vectorint vec{1,2,3,4}; mapint,string mp{{1,a},{2,b}}; //结构体 Student s{101, Tom};//Student s{101, Tom}1.2.3、C11 列表初始化的核心优势1. 禁止窄化转换最安全C/C 传统初始化会隐式丢精度C11 直接编译报错// 传统初始化不报错丢失精度危险 int x 3.14; // ✅ 合法x3 // C11 列表初始化直接报错安全 int y{3.14}; // ❌ 编译错误禁止窄化转换2. 统一所有初始化语法不管是基本类型、数组、结构体、类、STL 容器全部用{}初始化不用记多种语法。3. 解决 “最令人头疼的解析”C 传统写法会出现歧义{}完美解决// 歧义你想创建对象编译器当成函数声明 vectorint v(); // ❌ 编译器认为是函数 // C11 无歧义 vectorint v{}; // ✅ 正确创建空容器C11 解决了 C 初始化的不安全、不统一、有歧义三大问题。提问下面初始化谁对谁错int a10; //拷贝初始化C/C都支持int b(10)/C特有构造函数初始化int c{10}//C11int dint{10}//C中显示类型转换列表初始化通过int{10}创建一个临时的int对象在拷贝给d二、C的输入输出输入输出流引入头文件#includeiostream以及命名空间using namespace std2.1、输入cin语法cin 变量 变量;叫输入运算符提取符自动识别变量类型不用像 C 语言写 % d % f例int age cin;cin可以连续读取多个值cinab;coutab;2.2、输出cout语法cout 内容 内容 endl;叫输出运算符插入符endl 换行相当于\n例子int a10 coutaendl; //coutaaendl;2.3、输入输出字符串1.输出字符串cout 我是字符串;2.输入字符串无空格string name; cin name; // 输入Tom → 正确 // 输入Tom Lee → 只会读到 Tom遇到空格停止3.输入带空格的整行cin.getline(str,128)几乎等于std::fgets(str,128,stdin)std::fgets(str,128,stdin)fgets会把换行符\n一起读进字符串cin.getline(str,128)会丢掉换行符string s; getline(cin, s); // 读取一整行包括空格2.3.1、getline用法讲解1std::getline(cin, str) C 字符串专用最常用属于string头文件专门读std::string#include iostream #include string using namespace std; int main() { string s; getline(cin, s); // 读一整行包括空格 cout s endl; return 0; }自动管理内存不会溢出读到换行\n停止不把\n存进字符串专门配合string使用2cin.getline(buf, size) C 风格字符数组专用属于iostream用来读char 数组。#include iostream using namespace std; int main() { char buf[128]; cin.getline(buf, 128); // 最多读127个字符 cout buf endl; return 0; }特点安全限制长度同样丢弃换行符\n用于老式char[]2.4、转化输出类型int main { int a; char b; cinab; coutabendl; }此时b输出为字符b那么如何输出他的asc码值在c语言中char b; printf(%d %c,b,b);//b98 bb;但是在C中我们输出是自动判断类型因此我们采取强转。char b coutb(int)bendl;//输出b982.5、scanf为何改为scanf_sscanf被建议改为scanf_s核心原因是解决传统scanf的缓冲区溢出安全漏洞。2.5.1、为什么scanf不安全核心问题scanf在读取字符串%s、字符数组%c、%[]时不检查输入长度极易导致缓冲区溢出。缺少边界检查。数据被存放在栈区容易越界干扰其余数据存放。2.5.2、scanf_s如何解决安全机制scanf_s是安全增强版C11 标准可选函数VS 强制推荐强制要求缓冲区大小参数读取字符串 / 字符时必须额外传入缓冲区总容量。自动截断 补\0最多读n-1个字符自动加终止符。溢出直接报错不静默越界返回EOF并设错误码。溢出直接不输出字符串直接空白。// ❌ scanf危险 char buf[10]; scanf(%s, buf); // 无长度检查 // ✅ scanf_s安全 char buf[10]; scanf_s(%s, buf, (unsigned)_countof(buf)); // 必须加大小 // 或scanf_s(%s, buf, 10);2.6、sprintf与snprintf、一、共同点都在stdio.h里都是把格式化字符串 “打印” 到字符数组char[]中用法和printf几乎一样%d、%s、%f都支持都会自动在末尾加\0printf 输出到屏幕sprintf/snprintf 输出到 char 数组二、sprintf原型int sprintf(char *str, const char *format, ...);把格式化后的内容写入 str 字符数组。例子char buf[20]; sprintf(buf, age%d, name%s, 18, Zhang);输出buf age18, nameZhang\0致命问题不检查长度会溢出char buf[5]; sprintf(buf, hello world);buf只有 5 字节但要写hello world远大于 5直接越界写内存 → 崩溃、覆盖变量、安全漏洞三、snprintf安全版 sprintf原型int snprintf(char *str, size_t size, const char *format, ...);最多向str写入size - 1 个字符最后一定留一个位置给\0绝对不会溢出例子char buf[5]; snprintf(buf, 5, hello world);只写入前 4 个字符 \0结果buf hell\0snprintf为什么安全因为你明确告诉它缓冲区大小它绝不越界。四、最关键区别1. 是否检查长度sprintf不检查溢出就炸snprintf严格限制最多写 size-1 字节2. 返回值含义非常重要sprintf 返回值成功写入的字符数不含 \0溢出时返回值依然很大但内存已经炸了。snprintf 返回值如果空间足够返回写入字符数不含 \0如果空间不足返回 “本来应该写入的总字符数”char buf[5]; int ret snprintf(buf, 5, 123456789);实际写入1234\0返回 ret 9本来要写 9 个通过返回值可以判断是否被截断。如果ret size→被截断了如果ret 0→ 出错否则正常

更多文章