当前位置: 首页 > news >正文

分析网站建设网站改版seo

分析网站建设,网站改版seo,苏州网页设计聚尚网络,快速网站开发课程文章目录 前言一.命名空间二.缺省参数三.函数重载四.引用4.1引用做参数4.2引用做返回值 五.内联函数六.小语法6.1auto6.2范围for6.3空指针 前言 C是业内一门久负盛名的计算机语言#xff0c;从C语言发展起来的它#xff0c;不仅支持C语言的语法#xff0c;还新添加了面向对… 文章目录 前言一.命名空间二.缺省参数三.函数重载四.引用4.1引用做参数4.2引用做返回值 五.内联函数六.小语法6.1auto6.2范围for6.3空指针 前言 C是业内一门久负盛名的计算机语言从C语言发展起来的它不仅支持C语言的语法还新添加了面向对象、泛型等特性以及祖师爷本贾尼博士补充C语言的不足。 这一篇我们先来讲讲C对C语言不足部分的补充。 一.命名空间 Cpp能很好的支持C所以在Cpp文件中写C语言程序是没问题的。 从这段代码里我们好像看不出什么问题唯一觉得奇怪的是为什么整型变量要取名为rand这么奇怪。我们接着往下看 将变量rand放到全局中报错信息给出rand重定义我们想起C语言库里定义有一个叫rand函数与我们定义的rand变量命名冲突了于是报出了这个语法错误。 那么上面为什么放在局部中没有报错呢这是因为局部和全局都有时局部优先 到这里读者可能会说在日常写代码中自己写的又不一定会和自己命名冲突那么在一个大工程里数十几个程序员的代码合并到一起会不会冲突 使用命名空间将其隔离起来这样就不冲突了打印rand时找的是库里的rand函数。 使用域作用限定符::可以让编译器在找rand时先找域作用限定符指定的域里先去找。 #include stdio.h namespace name {//可以嵌套使用如果一个命名空间内也有命名冲突可以再隔离。namespace name1{int a 0;}namespace name2{int a 1;}int Add(int x, int y){return xy;}struct Node{int val;struct Node* next;}; }int main() {printf(%d\n, name::name1::a);//到name里找name1name1里找aprintf(%p\n, name::Add);struct name::Node node {0};//::要加在Node前面return 0; }关于namespace关键字基本的用法和作用讲完了还有一个较为重要分文件写声明和定义接着往下看 //Stack.h文件 #include assert.h namespace sjr {typedef struct Stack{int* a;int top;int capacity;}Stack;void StackInit(Stack* ps);void StackPush(Stack* ps, int x); }//Stack.cpp文件 #include Stack.h namespace sjr {void StackInit(Stack* ps){assert(ps);ps-a NULL;ps-top 0;ps-capacity 0;}void StackPush(Stack* ps, int x){//...} }将两个不同文件的声明和定义使用同名的命名空间包起来就可以实现声明和定义分离的同时都在命名空间内。 编译器会将不同文件的同名命名空间合并在一起一个文件里有同名的命名空间也会合并只是我们一般不会这么写。 总结命名空间是用来弥补C语言命名冲突的不足。有如何创建命名空间、命名空间里的变量、函数、类型都可以正常创建、可以嵌套、声明和定义分离使用同一个命名空间编译器会合并它们。 域作用限定符是一种指定命名空间里找的方法以上面栈为例子我们试着创建栈并插入几个数据 #include Stack.h/*int main {name::Stack st;name::StackInit(st);name::StackPush(st, 1);name::StackPush(st, 2);name::StackPush(st, 3);name::StackPush(st, 4);//每次使用都需要指定日常练习这样完全没必要 }*///展开命名空间 using namespace name; int main {Stack st;StackInit(st);StackPush(st, 1);StackPush(st, 2);StackPush(st, 3);StackPush(st, 4); } 展开命名空间就可以直接使用里面的变量、函数等但是这和头文件的展开不同它只是将隔离拆除了编译器会到展开的命名空间里面去找。如果展开命名空间里的定义与全局的有命名冲突这样还是会报错 在项目中全展开不是很好的做法还有一种指定展开的方法 //第一个C代码cout是输出使用流插入自动识别类型endl是换行 end line; #include iostreamusing namespace std;//展开std(std是C官方库的命名空间) int main() { //cout 和 endl都在命名空间里cout hello world endl;return 0; }#include iostream //为了cout和endl展开整个库太坑了 using std::cout; using std::endl; int main() {int a 0;cout hello world endl;//cin也在std里没有指定展开需要加std::std::cin a;//cin是输入使用流提取,自动识别类型。 return 0; }总结编译器默认不会到命名空间里找这是解决命名冲突的基础。使用::可以单次到指定空间里找、还有using namespace std;展开命名空间此时里面定义的所有东西都将暴露出来、而using std::cout;则只暴露std里面的cout。 二.缺省参数 在形参的后面加上一个值就是缺省参数。Func函数里的a就是缺省参数在调用Func函数时如果没有传参缺省值10将会默认赋值给a打印否则按实际传递的值打印。 接下来我们看缺省参数更多的知识 以上是全缺省的细节也就是缺省值要从左往右给。 半缺省遵循缺省参数从右往左给。 这是因为如果不遵循这个规则对于传参有很大的歧义。比如Fun2(10);此时这个10是传给a还是传给b是不确定的不支持跳跃传参Fun2(,10);总之对于半缺省遵循以上规则。 缺省有什么用请看以下代码 //Stack.h文件 #include assert.h namespace sjr {typedef struct Stack{int* a;int top;int capacity;}Stack;//声明和定义分离缺省写在声明里void StackInit(Stack* ps, int n 4);void StackPush(Stack* ps, int x); }//Stack.cpp文件 #include Stack.h namespace sjr {void StackInit(Stack* ps, int n)//不写缺省但要写对应类型的形参{assert(ps);ps-a (int*)malloc(sizeof(int)*n);ps-top 0;ps-capacity 0;}void StackPush(Stack* ps, int x){//...} }//Test.cpp文件 #include Stack.h using namespace sjr; int main() {//不知道要多少空间Stack st1;StackInit(st1);//默认开辟4个整型空间//知道要多少空间Stack st2;StackInit(st2, 100);//此时我们显示传多少就开多大//使逻辑清晰且知道需要多大空间时减少扩容消耗。return 0; }函数声明、定义分离缺省参数只写在声明里不能声明定义同时写缺省这是为了避免声明和定义缺省值不一。 比如在声明里的缺省值是10在定义里的缺省值是20这种情况。 为什么是在声明里给缺省参数而不是定义里给这是因为有定义的地方一定包括声明有声明的地方不一定有定义。 比如Test.cpp包含头文件Stack.h如果声明里没有缺省参数那么到StackInit这个函数的时候编译器并不知道有没有缺省参数存在。 总结一句话函数声明定义分离缺省参数写在声明里。 三.函数重载 函数重载指的是函数名相同、参数类型不同、个数不同、顺序不同的函数。 同为Add函数名的有两个从C语言的角度看main函数里调用的都是同一个函数这是因为C语言不支持函数重载仅根据函数名区分函数。 C区分函数不仅仅看函数名还看函数的参数类型、个数、顺序等。C中以上两个Add函数构成重载main函数里两个int实参调用int加法两个double实参调用double加法。 但是如果我们调用Add(1,2.2);时隐式转换将产生调用歧义即使构成函数重载也要注意细节。接下来我们看缺省参数属于什么类型 Func(int a 0)这个函数参数虽然是缺省参数但是它的类型依旧是int也就是所它们两个函数不能构成重载并且传参调用有二义性。 函数构成重载的条件类型和个数不同都好理解顺序不同是什么意思呢 ​ 总结函数重载是C支持的一种不同于C语言的特性不同函数的函数名可以相同但参数的类型、个数、顺序需要有不同的。此外函数返回值不参与构成函数重载的评判调用时用不到因为调用时无法根据参数列表确定调用哪个重载函数。 四.引用 引用是给已经存在的变量取一个别名也就是说一块空间可以用多个名称表示。 c是a的别名可以继续给a起别名也可以给a的别名c起别名都指向同一块空间a。并且引用必须初始化不能更改指向。以上是引用的基本使用方法。 那么引用的作用是什么如果仅使用这个功能是没有意思的接下来我们看引用的应用场景 4.1引用做参数 #include iostreamvoid Swap(int* left, int* right) {int tmp *left;*left *right;*right tmp; } //left是a的别名right是b的别名在函数里的改变会影响外面的ab void Swap(int left, int right)//int left 也是int类型 {int tmp left;left right;right left; } int main() {int a 10;int b 20;//函数重载Swap(a, b);Swap(a, b);return 0; }使用引用做参数形式看起来比较容易而且熟悉之后理解起来也很容易。 我们再讲讲之前单链表需要传递二级指针的理解问题对比使用引用和指针的区别更进一步体会引用做参数带来形式上的简便。 typedef struct SListNode {int val;struct SListNode* next; }SLNode,*PSLNode//简写 void SListPushBack(SLNode** pphead, int x) {if(*pphead NULL){*pphead newnode;//要把plist从空指针改成指向第一个结点}else{//找尾tail-next newnode;// } }int main() {SLNode* plist NULL;SListPushBack(plist, 1);SListPushBack(plist, 2);SListPushBack(plist, 3);SListPushBack(plist, 4); }在尾插时需要判断plist是否为空为空则要改变SLNode*类型的变量假如形参部分写着SLNode* phead那就只是plist的一份拷贝phead的改变不会影响plist,所以要传二级指针。 那么学了引用怎么用引用传参呢请看下面代码 typedef struct SListNode {int val;struct SListNode* next; }SLNode,*PSLNodevoid SListPushBack(SLNode* phead, int x) {if(phead NULL){phead newnode;//phead是SLNode*类型 是plist的别名改变phead就会改变plist}else{//找尾tail-next newnode;// } }int main() {SLNode* plist NULL;SListPushBack(plist, 1);SListPushBack(plist, 2);SListPushBack(plist, 3);SListPushBack(plist, 4); }甚至使用上结点指针类型重名命的PSLNode创建变量让不是很懂引用的初学者糊涂。 这以上是引用做参数的应用场景使用指针也可以做到引用和指针在做参数的时候都可以提高效率只是指针用起来形式更复杂一点。 接下来说引用做返回值的应用场景 4.2引用做返回值 int Count() {int n 0;n;return n; } int main() {int ret Count();return 0; }不知道读者有没有思考过局部变量在出了作用域后生命周期结束。对于上面Count函数里的局部变量nreturn n;的时候Count函数调用结束。 如果返回n的话那就相当于是访问一个被释放了的空间。其实了解过函数与栈帧的读者知道n在结束生命周期前拷贝给一个寄存器由于n变量较小这个寄存器代替n作为Count的返回值赋值给ret。 也就是说传值返回会进行拷贝和传值传参一个道理传值传参会生成一个临时拷贝。 上述代码使用传值返回是对的如果使用传引用返回会是怎么样的呢 int Count() {int n 0;n;return n; //传引用返回传n的别名返回 } int main() {int ret Count();//n的别名赋值给ret相当于把n赋值给ret因为n的别名指的也是nreturn 0; }前面讲过在return n;的时候n就被释放掉了。于是返回n赋值给ret的应该是随机值。 如果操作系统还没清理n变量这块空间那么仍有可能保留着1否则会被刷成随机值并且根据不同编译器可能还有所不同。 由于这种随机性编译器会报出警告。因此返回会销毁的变量时不采取传引用返回。注意会销毁的变量使用引用返回是错误的程序 接着再进一步看使用引用接收引用返回会销毁的变量会如何。 ret是n的别名相当于ret指向n那块释放了的空间。那么第一次打印取决于n的空间有没有被清理、取决于是什么编译器因此是随机值。第二次打印的时候我们看到那块区域已经被清理了。 这里执行了Add(3, 4);后ret打印出来的值就变成了7。这是由于栈空间复用的原因同一个函数或结构相似的函数连续调用上一次的栈帧销毁后立刻为下一次相同函数调用做准备局部变量的地址不变。 因此ret指向的z的那块空间被第二次的Add函数调用改成7但是打印出来的也是随机值具体取决编译器和操作系统VS2019打印的是7。 以上都是使用引用返回不恰当场景导致的结果真正使用引用返回的场景是返回不会销毁的。比如malloc在堆上的对象、静态变量等等。 那么引用做返回值的价值是什么提高效率和可以修改返回值。指针也可以做到但形式复杂。当然引用还有指针更适合使用的场景入门篇先不讲。 int main() {//权限平移const int a 10;const int b a;//权限缩小int c 20;const int d c;//引用可以是常量const int e 10;//权限放大const int f 5;int g f;//errorc f//c是int类型f是const int会不会有问题return 0; }引用和指针一样存在权限缩放的问题权限可以平移、可以缩小不能放大。 f赋值给c是没问题的它是值拷贝不存在权限问题c和f不属于同一块空间改变c不影响f。 引用和指针的区别引用是别名不开空间指针存储变量的地址引用必须初始化并且不能更改引用对象指针可以不初始化也可以更改指向引用没有空引用指针有空指针 五.内联函数 内联函数的关键字是inline这是用来替代宏函数的。使用内联函数可以使代码量少的函数在调用处展开避免栈帧创建和销毁的损耗。 宏函数的缺点是写法复杂括号较多宏在预处理阶段就进行替换了不能调试没有类型检查 而使用内联函数避免了宏的缺点写法就是正常写函数一样只需在函数返回类型前加inline就变为内联函数可以进行调试也有类型检查。 这里即使Add函数很短调试进入反汇编还是选择调用而不是像宏一样展开的原因是Debug版本下默认内联函数是不会展开的要把属性修改一下 设置完成后我们再调试起来看看效果 虽说是展开但不是把Add函数里的代码全部放到调用处而是编译器实现和函数逻辑一样的指令。 注意内联函数在调用处选不选择展开取决于编译器不是加了inline关键词的函数就会展开编译器只会展开代码量少的函数。 这是因为如果有程序员给长代码函数、循环函数、递归函数加上内联并且编译器无条件展开则会导致需要执行的指令变得非常多生成的可执行程序文件特别大。 内联函数还有一个特别的点 //Func.h #include iostream using namespace std;inline void Func(int a 10);//Func.cpp #include Func.hvoid Func(int a) {cout a endl; }//Test.cpp #include Func.hint main() {Func();return 0; }出现了链接错误这是因为内联函数在编译时Func.cpp文件包含头文件得知Func函数是内联函数后就没有把函数的地址放进符号表因为在链接的时候Test.cpp文件找不到Func函数的地址。 所以当内联函数声明和定义分离时使用只能在定义的那个文件里使用。 正确的使用内联函数的方法是将内联函数完整的实现放在头文件中这样函数就可以在调用的地方直接展开而不用在链接时候找地址。 六.小语法 6.1auto auto是C一个用来自动推导类型的关键字它的用途是对长类型的省略写法。 对于指针的写法可以写auto* d c;而对于引用我们只能显示写以上只是说明atuo的用法对于这种短类型不是auto的真正使用场景。 注意auto不能做参数类型也不能做函数返回类型以及不能用来创建数组。 6.2范围for 对于数组的遍历C语言使用求数组下标依次遍历C使用一个更为简便的语法 for(auto e: 数组)这个语法中e是一个和数组元素类型一样的临时变量将数组里的值依次取出赋值给e自动判断结束。习惯使用auto当e的类型,让其自动推导类型。 当e作为数组里每个元素的别名时对其进行修改会影响数组里的元素。 由于冒号后面加的是数组因此 #include iostreamvoid Func(int arr[]) {for(auto e : arr)//error,arr是首元素地址不是数组{//...} } int main() {int arr[3] {1,2,3};Func(arr);return 0; }6.3空指针 在C程序中使用nullptr当做空指针C语言的NULL有点错误因此C委员会后来补上这个坑引入nullptr这个关键词实质是void*。 好了以上就是C入门篇希望读者有所收获
http://www.dnsts.com.cn/news/12040.html

相关文章:

  • 东莞seo网站建设英文seo如何优化
  • 电脑做视频的网站比较好建设工程教育网论坛官网
  • 养殖业网站模板唐山网站建设哪家好
  • 广西地矿建设集团网站十大网站建设公司排名
  • 云访客类似的网站设计一套企业网站多少钱
  • 网站站点结构的构建wordpress如何去除分类
  • 网站建设怎样创建链接西安网络seo公司
  • 马鞍山网站建设 明达一重大连工程建设有限公司官方网站
  • 网站源码模块2018年做视频网站
  • 网站开发培训光山营销型网站建设公司哪家建设
  • 做贵网站多少钱泉州网站制作网页
  • 坪山网站建设公司建筑业企业资质标准建设部网站
  • 做网站怎么切psd图dedecms双语网站
  • 特价网站建设价格如何修改网站主页
  • 平面设计师网站都有哪些百度移动网站检测
  • 打开网站弹出窗口代码3d建模自学教程
  • 网站建设待遇下瓦房做网站公司
  • 如何做电子书网站企业网站建设合同 百度文库
  • 建设部四库一平台网站关键词分析工具
  • 如何给一个网站做定时的更新响应式布局原理是什么
  • 建筑网站水泡网招标资源网官网
  • 建设摩托车所有车型seo外链招聘
  • 天津塘沽网站建设珠海网络
  • 招商网站的建设意义无锡百度推广代理公司
  • 网站的页脚什么做关于网站建设的建议
  • 新手怎样自己做网站网页源代码有什么用
  • 用别人的二级域名做网站注册一个空壳公司需要多少费用
  • 028网站建设wordpress固定链接是存在哪个表
  • 做网站会被捉吗云南楚雄旅游必去的景点
  • 网站建设公司市场定位长沙seo管理