ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

C++ 入门核心知识点|缺省参数、函数重载、引用、nullptr(附带栈代码示例)

C++ 入门核心知识点|缺省参数、函数重载、引用、nullptr(附带栈代码示例) 一、C 输入输出流 cin /coutC 语言用printf/scanf需要手动写格式控制符%d %lf %c容易写错。C 的cout自动识别变量类型不用指定格式。#include iostream int main() { int a 0; double b 0.1; char c c; // C输出 std::cout a b c std::endl; // C输出 printf(%d %lf %c\n, a, b, c); return 0; }输出0 0.1 c 0 0.100000 c提升 cin/cout IO 效率竞赛常用cin/cout默认和 C 的 stdio 同步大量数据输入输出会很慢加上下面三行代码提速#include iostream int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); // 后续cin cout代码 return 0; }ios_base::sync_with_stdio(false);断开 C 流和 C stdio 的同步cin.tie(nullptr);解除 cin 绑定 cout默认每次 cin 前都会刷新 cout 缓冲区cout.tie(nullptr);解除 cout 绑定 cin⚠注意关闭同步后不要混合使用 cout 和 printf、cin 和 scanf缓冲区不同步会出现乱序。二、函数默认参数函数声明时可以给形参设置默认值不传实参时自动使用默认值。核心规则带默认值的参数必须放在参数列表的最右侧。#include iostream void Func1(int a 10, int b 20, int c 30) { std::cout a a std::endl; std::cout b b std::endl; std::cout c c std::endl std::endl; } //半缺省 void Func2(int a, int b 10, int c 20) { std::cout a a std::endl; std::cout b b std::endl; std::cout c c std::endl std::endl; } int main() { Func1(); //全部使用默认参数 a10,b20,c30 Func1(1); //a1b、c默认 Func1(1,2); //a1,b2c默认 Func1(1,2,3); //全部传参覆盖默认值 Func2(1); Func2(1,2); Func2(1,2,3); return 0; }错误示例//报错默认参数没有靠右c没有默认值 void Func2(int a, int b 10, int c) { }编译器提示缺少形参 3 的默认实参。如图所示缺省参数使用场景缺省参数函数声明 / 定义时给参数一个默认值。调用函数如果不传这个参数就自动使用默认值。核心规则缺省参数只能写在函数声明不能声明和定义同时写。如果头文件写了默认值函数实现源文件就不要再重复写。typedef int STDataType; typedef struct Stack { STDDataType* a; int top; int capacity; }ST; //函数声明给n默认值4 void STInit(ST * ps, int n 4); void STPush(ST * ps, STDataType x); //函数定义这里不能再写 4 void STInit(ST* ps, int n) { assert(ps); ps-a (STDDataType*)malloc(n * sizeof(STDDataType)); ps-capacity n; ps-top 0; }调用示例int main() { ST str1; STInit(str1); //不传n自动用默认值4 STInit(str1, 10); //传参使用传入的10 STPush(str1, 1); STPush(str1, 2); STPush(str1, 3); STPush(str1, 4); return 0; }再次注意缺省参数必须从右往左连续给不能中间跳过参数设置默认值。三、函数重载C 语言同一个作用域不能定义同名函数。 C 支持函数重载同一个作用域函数名相同参数列表参数个数 / 类型 / 顺序不同。 返回值不能单独作为重载区分条件。void f() { std::cout f() std::endl; } void f(int a 1) { std::cout f(a) std::endl; } int main() { f(); //编译报错调用歧义不知道调用哪一个 return 0; }上面代码经典坑无参调用f()既匹配f()也匹配带默认参数的f(int a1)编译器不知道选谁报调用不明确。四、引用 C 最重要特性之一引用给已经存在的变量起一个别名引用不是新变量和原变量共用同一块内存空间。语法类型 引用名 原变量;#include iostream int main() { int a 10; int b a; int c b; int d c; d; std::cout a std::endl; std::cout b std::endl; std::cout c std::endl; std::cout d std::endl; return 0; }输出四个地址完全一样a,b,c,d 都是同一块内存的别名。重点误区int a 10; int b a; int c 20; b c; //⚠这不是引用更改绑定只是赋值操作bc只是把 c 的值拷贝给 b也就是 a引用一旦绑定变量不能更换绑定对象。引用最常用场景函数传参传引用C 语言交换函数需要传指针C 引用写法更简洁直接操作实参本身不需要解引用。#include iostream void Swap(int x, int y) { int tmp x; x y; y tmp; } int main() { int i 0, j 1; std::cout i: i j: j std::endl; Swap(i, j); std::cout i: i j: j std::endl; return 0; }输出i: 0 j: 1 i: 1 j: 0野引用悬垂引用核心不要返回局部变量的引用局部变量在函数栈帧内函数调用结束栈帧销毁局部变量空间被回收此时返回的引用指向一块已经失效的内存叫做野引用。int fun(int x, int y) { int ret x y; //ret是函数内局部变量函数结束后ret销毁 return ret; // 野引用 } int main() { int a fun(1, 2); cout a endl; cout a endl; fun(100, 200); cout a endl; cout xxxxxx endl; cout a endl; return 0; }现象有时候第一次打印看起来正常这只是栈空间数据还没被覆盖属于侥幸。后续函数调用覆盖栈内存值就会乱掉程序未定义行为。临时变量 const 引用权限问题临时变量具有const常属性。普通引用不能绑定临时变量也不能做权限放大操作const 变量不能交给普通引用但是 const 引用可以绑定临时变量。int main() { int d 1; double e d; //double re d; //报错隐式转换产生临时变量临时变量带const普通引用权限放大禁止 const double re d; //const引用可以绑定临时变量权限平移 return 0; }原理d是 int赋值给 double 的时候编译器会生成一个临时 double 变量。临时变量默认带常属性普通引用无法绑定const引用可以接收临时变量。五、兼容 C 语言动态内存栈模拟示例C 完全兼容 C 的malloc/realloc/free下面是栈结构示例参数使用引用直接修改结构体本身typedef int STDDataType; typedef struct Stack { STDDataType* a; int capacity; int top; }ST; void STInit(ST rs, int n) { rs.a (STDDataType*)malloc(n * sizeof(STDDataType)); rs.capacity n; rs.top 0; } void STPush(ST rs, STDDataType x) { if (rs.top rs.capacity) { int newcapacity rs.capacity 0 ? 4 : 2 * rs.capacity; STDDataType* tmp (STDDataType*)realloc(rs.a, sizeof(STDDataType) * newcapacity); if (tmp NULL) { perror(realloc fail); exit(1); } rs.capacity newcapacity; rs.a tmp; } rs.a[rs.top] x; rs.top; }C 后面还有new/delete替代 malloc/free。六、NULL 和 nullptr 的区别函数重载坑点C11 引入nullptr专门表示空指针用来解决NULL的缺陷C 语言里NULL本质就是宏定义#define NULL 0是一个整数 0。 当存在重载函数一个接收 int、一个接收 int * 指针传递 NULL 会匹配 int 版本而不是指针版本和预期不符。#includeiostream using namespace std; void f(int x) { cout f(int x) endl; } void f(int* ptr) { cout f(int* ptr) endl; } int main() { f(0); //调用f(int x) f(NULL); //NULL等价0依然调用f(int x)不符合预期 f((int*)NULL);//强转后调用指针版本 f(nullptr); //nullptr是空指针常量调用f(int* ptr) return 0; }开发规范C 中表示空指针优先使用nullptr不要再用 NULL。总结缺省参数默认值写在函数声明定义处不要重复写从右往左设置默认值。函数重载同名函数依靠参数区分返回值不能单独作为重载条件。引用变量别名禁止返回局部变量引用野引用临时变量只能用const 接收。空指针NULL是整数 0重载场景会出错C11 推荐nullptr代表空指针。这些是 C 区别 C 语言最基础的语法也是后面学习类、对象、STL 的前置基础面试笔试出现频率很高。
返回列表