各位道友,在修仙路上炼气期是一切大道的根基——感应天地灵气打通周身经脉方能在日后结丹化神。而C编程又何尝不是如此变量好比丹田用以存储真元函数如同功法运转灵力完成招式控制流则是心法口诀决定每一次出招的走向。身为一个连“灵气”都还感知不清的凡人修士我深知唯有从最基础的“吐纳法门”练起才能在未来驾驭更高深的法术。这篇博客不求什么惊天动地的神通只想诚实地记录下自己从零开始的每一步如何定义第一个变量如何调用第一个函数如何在编译器的报错中一次次跌倒又爬起。或许你会觉得这些内容太过简单但对我而言每一行代码都是一次小小的顿悟每一次运行成功都是修为的精进。愿与我一样初入此界的道友们能在这条“凡人编程传”的路上耐得住寂寞守得住初心。且看我这炼气期的小修士如何在C的世界里一步一步向更高的境界攀登。那么炼气期第一课我们要修炼哪些基础法门且看本期目录目录一、C的第一个程序二、命名空间2.1 namespace的修炼价值2.2namespace的定义三、C输⼊输出四、缺省参数五、函数重载5.1、参数类型不同六、引用6.1 引用的概念和定6.2 引用的法则6.3 引用的使用七、const引用八、inline九、nullptr一、C的第一个程序C兼容C语⾔绝⼤多数的语法所以C语⾔实现的hello world依旧可以运⾏C中需要把定义⽂件代码后缀改为.cppvs编译器看到是.cpp就会调⽤C编译器编译linux下要⽤g编译不再是gcc#includestdio.h int main() { printf(Hello,World!); return 0; }当然C有⼀套⾃⼰的输⼊输出严格说C版本的hello world应该是这样写的。#includeiostream using namespace std; int main() { cout Hello,World! endl; return 0; }这⾥的std cout等作为炼气小白的我都看不懂没关系下⾯有前辈的修炼心得。二、命名空间2.1 namespace的修炼价值在C语言界存在类似下⾯程序这样的命名冲突是普遍存在的问题C的祖师引⼊namespace就是为了更好的解决这样的修炼问题#include stdio.h #include stdlib.h int rand 10; int main() { printf(%d\n, rand); return 0; }编译报错error C2365: “rand”: 重定义以前的定义是“函数”那namespace又是如何解决自定义rand和库函数中rand重复的呢心法中是这样记载的#includeiostream using namespace std; namespace zwz { int rand 10; } int main() { printf(%d\n, zwz::rand); return 0; }namespace本质是定义出⼀个域这个域跟全局域各自独⽴不同的域可以定义同名变量所以上面的rand不在冲突了。 :: 在 C 语言中被称为作用域解析运算符zwz::rand 表示访问 zwz 这个命名空间下的变量 rand。2.2namespace的定义定义命名空间需要使⽤到namespace关键字后⾯跟命名空间的名字然后接⼀对{}即可{}中即为命名空间的成员。命名空间中可以定义变量/函数/类型等。#includeiostream using namespace std; namespace zwz { int add(int a, int b) { return a b; } struct Node { struct Node* next; int data; }; }C中域有函数局部域全局域命名空间域类域域影响的是编译时语法查找⼀个变量/函数/类型出处(声明或定义)的逻辑所有有了域隔离名字冲突就解决了。局部域和全局域除了会影响编译查找逻辑还会影响变量的⽣命周期命名空间域和类域不影响变量⽣命周期。namespace只能定义在全局当然他还可以嵌套定义。多⽂件中可以定义同名namespace他们会默认合并到⼀起就像同⼀个namespace⼀样C标准库都放在⼀个叫std(standard)的命名空间中。知道了namespce的奥秘后我对于helloworld是怎么输出的还存在一些困惑三、C输⼊输出•iostream 是 Input Output Stream 的缩写是标准的输⼊、输出流库定义了标准的输⼊、输出对象。•std::cin 是 istream 类的对象它主要⾯向窄字符narrow characters (of type char)的标准输⼊流。•std::cout 是 ostream 类的对象它主要⾯向窄字符的标准输出流。•std::endl 是⼀个函数流插⼊输出时相当于插⼊⼀个换⾏字符加刷新缓冲区。•是流插⼊运算符是流提取运算符。•cout/cin/endl等都属于C标准库C标准库都放在⼀个叫std(standard)的命名空间中所以要通过命名空间的使⽤⽅式去⽤他们。在练习的过程中我发现使⽤C输⼊输出更⽅便不需要像printf/scanf输⼊输出时那样需要⼿动指定格式C的输⼊输出可以⾃动识别变量类型。自此我对于C界学习的第一个程序已经熟练掌握了要开始学习其他的编程常识了。四、缺省参数•缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值。在调⽤该函数时如果没有指定实参则采⽤该形参的缺省值否则使⽤指定的实参缺省参数分为全缺省和半缺省参数。有些地⽅把缺省参数也叫默认参数•全缺省就是全部形参给缺省值半缺省就是部分形参给缺省值。C规定半缺省参数必须从右往左依次连续缺省不能间隔跳跃给缺省值。•带缺省参数的函数调⽤C规定必须从左到右依次给实参不能跳跃给实参。•函数声明和定义分离时缺省参数不能在函数声明和定义中同时出现规定必须函数声明给缺省值。全缺省void Func1(int a 10, int b 20, int c 30) { cout a a endl; cout b b endl; cout c c endl endl; }半缺省void Func2(int a, int b 10, int c 20) { cout a a endl; cout b b endl; cout c c endl endl; }五、函数重载C⽀持在同⼀作⽤域中出现同名函数但是要求这些同名函数的形参不同可以是参数个数不同或者类型不同。这样C函数调⽤就表现出了多态⾏为使⽤更灵活。C语⾔是不⽀持同⼀作⽤域中出现同名函数的。5.1、参数类型不同2、参数个数不同#includeiostream using namespace std; void f() { cout f() endl; } void f(int a) { cout f(int a) endl; } int main() { f(); f(10); return 0; }**返回值不同不能作为重载条件因为调⽤时也⽆法区分**六、引用6.1 引用的概念和定引用不是新定义⼀个变量而是给已存在变量取了⼀个别名编译器不会为引⽤变量开辟内存空间 它和它引⽤的变量共⽤同⼀块内存空间。⽐如韩立在漂亮妹子前报本名韩立在敌人面前自称历飞宇正派称其韩仙师韩天尊反派称其韩老魔。类型 引用别名 引⽤对象;6.2引用的法则•引用在定义时必须初始化•⼀个变量可以有多个引用•引用⼀旦引⽤⼀个实体再不能引用其他实体6.3 引用的使用引用在实践中主要是于引⽤传参和引⽤做返回值中减少拷贝提⾼效率和改变引⽤对象时同时改变被引用对象。void Swap(int rx, int ry) { int tmp rx; rx ry; ry tmp; } int main() { int x 0, y 1; cout x y endl; Swap(x, y); cout x y endl; return 0; }七、const引用可以引⽤⼀个const对象但是必须⽤const引⽤。const引⽤也可以引⽤普通对象因为对象的访问权限在引⽤过程中可以缩小但是不能放大不影响引用对象的权限。及节省了拷贝又保留了原值int main() { const int a 10; int ra a; ra; // 编译报错⽆法从“const int”转换为“int ” // 这⾥的引⽤是对a访问权限的放⼤ int b 20; const int rb b; // 这⾥的引⽤是对b访问权限的缩⼩ return 0; }rb和rd引⽤的都是临时对象⽽C规定临时对象具有常性所以这⾥就触发了权限放⼤必须要⽤常引⽤才可以。临时对象具有常性只读不写const引用可以目标的临时对像临时对象的生命周期随着引用的结束而结束临时对象的存在条件1.实参传值2.类型转换3.表达式的运算八、inline⽤inline修饰的函数叫做内联函数编译时C编译器会在调⽤的地⽅展开内联函数这样调⽤内联函数就需要建⽴栈帧了就可以提⾼效率。inline适⽤于频繁调⽤的短⼩函数对于递归函数代码相对多⼀些的函数加上inline也会被编译器忽略。C设计了inline⽬的就是替代C的宏函数。inline不建议声明和定义分离到两个⽂件分离会导致链接错误。#includeiostream using namespace std; //宏函数 #define ADD(a, b) ((a) (b)) //内联函数 inline void add(int a, int b) { cout Sum1: a b endl; } int main() { add(10, 20); cout Sum2: ADD(20, 30) endl; return 0; }九、nullptrNULL实际是⼀个宏在传统的C头⽂件(stddef.h)中可以看到如下代码#ifndef NULL #ifdef __cplusplus #define NULL 0 #else #define NULL ((void *)0) #endif #endifC中NULL可能被定义为字⾯常量0或者C中被定义为⽆类型指针(void*)的常量。不论采取何种定义在使⽤空值的指针时都不可避免的会遇到⼀些⿇烦本想通过f(NULL)调⽤指针版本的 f(int*)函数但是由于NULL被定义成0调⽤了f(int x)因此与程序的初衷相悖。f((void*)NULL); 调⽤会报错。C11中引⼊nullptrnullptr是⼀个特殊的关键字nullptr是⼀种特殊类型的字⾯量它可以转换 成任意其他类型的指针类型。使⽤nullptr定义空指针可以避免类型转换的问题因为nullptr只能被 隐式地转换为指针类型⽽不能被转换为整数类型。炼气圆满筑基在望至此炼气期的第一课便告一段落。此次我们从“引气入体”的Hello World开始学会了c界输入输出、缺省参数、函数从在等基础功法。然而凡人修仙之路从来不止于打坐吐纳。真正的变化在于从“气”到“形”的蜕变——这便是下一阶段要修炼的核心功法类和对象。道阻且长行则将至。各位道友我们下期再见。