肥宅钓鱼网
当前位置: 首页 钓鱼百科

c基本语法结构(一文掌握C基本语法)

时间:2023-08-18 作者: 小编 阅读量: 1 栏目名: 钓鱼百科

使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。一个是乒乓球,一个是男足。因此如果C语言中出现函数重载,那么调用的时候就会查找到两个不同地址,C语言不知道要链接哪一个,因此出错。这个关键字的意思是告诉编译器将该部分按照C语言的规则来进行编译,我们调用C库,当然就要按C的规则来啦。

1. c关键字2. 命名空间

变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。

使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。

2.1 命名空间定义

使用namespace关键字,后面跟命名空间的名字,然后用{}将成员括起来即可,和C语言的结构体类似

存在多个相同的命名空间的时候,编译器编译的时候会把他们合并,如下面

命名空间可以嵌套

PS:命名空间定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中,但是成员的生命周期没有改变,仍然是全局的。

2.2 命名空间使用

命名空间有3种使用方式

以下均使用该命名空间

1.加命名空间名称及作用域限定符

这种方法每次使用的时候都要进行::限定,比较麻烦

2.使用using将命名空间中成员引入

这样就可以不用::限定命名空间,直接使用b

3.使用using namespace 命名空间名称引入

可以使用所有N中内容,但是需要注意的是这样可能会造成名称冲突

3. C输入&输出

1. 使用cout标准输出(控制台)和cin标准输入(键盘)时,必须包含< iostream >头文件以及std标准命名空间。

2. 使用C输入输出更方便,不需增加数据格式控制

4. 缺省参数

缺省参数就像女神的备胎,当女神有男朋友的时候,备胎被冷落在一旁,当女神分手后,备胎才可以派上用场。

4.1 缺省参数概念

缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参。

4.2 缺省参数分类

全缺省参数

半缺省参数

注意:

1. 半缺省参数必须从右往左依次来给出,不能间隔着给2. 缺省参数不能在函数声明和定义中同时出现,且应只出现于声明

3. 缺省值必须是常量或者全局变量

5. 函数重载

自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重载了。

比如:有两个体育项目大家根本不用看,也不用担心。一个是乒乓球,一个是男足。前者是“谁也赢不了!”,后者是“谁也赢不了!”

5.1 函数重载概念

函数重载:是函数的一种特殊情况,C允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 顺序)必须不同,常用来处理实现功能类似数据类型不同的问题。

下面都是函数重载:

下面这两个不是函数重载!

5.2 名字修饰

那么为什么C支持函数重载而C语言不支持呢?

一个程序要运行起来要经历以下几步:假设有以下文件

f.h f.cpp test.cpp

1.预处理——头文件展开,宏替换,条件编译,去掉注释

生成f.i test.i

2.编译——检查语法,生成汇编代码

生成f.s test.s

3.汇编——把汇编代码转换成二进制的机器码(让CPU能看懂)

生成f.o test.o

4.链接——找调用函数的定义地址,链接对应上,合并到一起

生成a.out可执行程序

在链接阶段,编译器看到test.o调用了哪些函数,就会去f.o的符号表中找对应函数的地址,然后链接在一起,那么要怎么去找呢?C和C语言采用了不同的名字修饰,就会用不同的名字去找

我们发现名字由_Z 函数名长度 函数名首字母 函数按顺序参数首字母,因此支持函数重载(名字不一样,找的对象就不一样)C:

这里我们发现C语言则是直接用函数名作为地址查找对象,回想我们的函数指针,是不是函数指针和函数名都可以调用函数呢。因此如果C语言中出现函数重载,那么调用的时候就会查找到两个不同地址,C语言不知道要链接哪一个,因此出错。

5.3 extern “C”

我们知道C语言可以调用C语言的静态库和动态库,C可以调用C的静态库和动态库,那么C能不能调用C的库?C能不能调用C的库?

答案是可以的。

我们先来看C调用C的库,这里我们用C语言实现的栈的代码生成一个静态库

再新开一个项目,调用这个库,这里对新项目的属性进行更改。

然后来看一下现在能否调用

这是不是意味着C不能调用C的库?别急,这时候extern C就登场了

我们发现加了这个关键字后就链接成功了。这个关键字的意思是告诉编译器将该部分按照C语言的规则来进行编译,我们调用C库,当然就要按C的规则来啦。

再来看一下C语言能否调用C的库,我们把后缀名更改一下

(这里是c语言了,因此只能用typedef过的别名,不能再用一个Stack,因为C语言不支持) 好像不行,我们刚刚是在C的部分进行修改,这次我们也在C的部分进行修改,我们来到test_01,对头文件部分的声明进行如下修改。

这样是不是就顺利链接成功了,这里的预编译进行了判断,如果文件是C的,那么就用C的规则进行编译,也可以这么写:

6. 引用6.1 引用概念

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。

类型& 引用变量名(对象名) = 引用实体;

引用类型必须和引用实体是同种类型的

6.2 引用特性

1. 引用在定义时必须初始化2. 一个变量可以有多个引用3. 引用一旦引用一个实体,再不能引用其他实体

6.3 常引用

这里我们取别名的规则是:

对原引用变量,权限只能缩小,不能放大。这里权限指的是读写权限。

因此对const常量只能进行读,也就只能用const引用。

在下面将double赋给int别名的过程中,编译器会产生“临时变量”,将double d中整数部分赋给临时变量, 这个临时变量再将这个整数赋给另一个int类型的临时变量,最后int把临时变量赋给rd,也就是说rd引用的其实是这个int临时变量,而临时变量具有常属性,因此要用const引用。

6.4 使用场景

1.作函数参数

在学习C语言的时候我们如果要交换两个数,那么就需要传址调用函数,而现在可以直接用引用进行修改,这就是引用做参数的好处,输出型参数另外,如果是传值调用的话,我们知道形参是实参的一个临时拷贝,而传引用的时候并没有拷贝这一步,这就提高了效率

2.作函数返回值

结果是显然的,我们返回的是静态变量n的别名,而出了函数作用域n并没有销毁,那么来看下面这个代码

n和ret地址一样

这里n不再是静态变量了,出了函数作用域后空间返还,而我们的ret是n的别名,这是不是就相当于野指针。因此只有第一次调用函数后ret中的值是1,调用一次函数(函数重载<<)后n的空间被制成随机数,因此剩下两次都是随机数,因此我们用引用作返回值的时候返回的应该是出了函数定义域还存在的变量的引用,否则就应该按值返回,这里和指针是一个道理。

明白了这些下面这个程序的结果就应该很明确了,应该是7

道理是一样的。另外引用作返回值也会提高效率

6.5 传值、传引用效率比较

以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。

这里用程序来比较一下

不是很明显的原因是我们计算机的速度实在太快,但是还是有效率差异的。

指针和引用的效率是一样的,因为引用的底层和指针的底层是一样的!

6.6 引用和指针的区别

从语法概念上:引用是别名,没有额外开空间,而指针存储变量的地址,开辟了4/8字节的空间

从底层实现的角度:引用实际上是有空间的,因为引用是按指针的方式来实现的

来看一下指针和引用的汇编

汇编指令完全一样,也印证了底层是一样的

那引用和指针的不同点是什么呢?

1. 引用在定义时必须初始化,指针没有要求

2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体

3. 没有NULL引用,但有NULL指针

4. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)

5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小

6. 有多级指针,但是没有多级引用

7. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理

8. 引用比指针使用起来相对更安全

7. 内联函数

7.1 概念

以inline修饰的函数叫做内联函数,编译时C编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率。

在学习C语言的时候,我们遇到函数体短小且频繁调用的函数的时候,采用的优化方式是使用宏进行替换,但是宏太繁琐啦,难以看懂,因此c就产生了内联函数。

那么内联函数是如何进行优化的呢?来看代码。

当我们不用inline定义函数的时候,函数是怎么调用的呢?

进行函数压栈,然后用call指令调用。那么用了inline后呢

我们发现在汇编代码中直接对函数调用的代码进行了替换,没有压栈和call调用指令。

7.1 特性

1. inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的函数不适宜使用作为内联函数。

2. inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联。

3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

例如如果在.h和.cpp文件中分别声明和定义内联函数,那么在链接的时候就会出现错误:main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl f(int)" (?f@@YAXH@Z),该符号在函数 _main 中被引用

那么内联函数相比宏有哪些优点?

1.内联函数在debug版本下支持调试,而宏不支持

2.内联函数就是普通函数的写法,解决了宏晦涩难懂的问题

8. auto关键字(C11)

8.1 auto简介

在早期C/C中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量

C11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。

使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。

8.2 auto的使用细则

1.用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&

2. 在同一行定义多个变量当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

8.3 auto不能推导的场景

1. auto不能作为函数的参数

2. auto不能直接用来声明数组

3. 为了避免与C98中的auto发生混淆,C11只保留了auto作为类型指示符的用法4. auto在实际中最常见的优势用法就是C11提供的新式for循环,还有lambda表达式等进行配合使用。

9. 基于范围的for循环(C11)9.1 范围for的语法

for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围。

范围for循环与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环。

9.2 范围for的使用条件

1. for循环迭代的范围必须是确定的对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供begin和end的方法,begin和end就是for循环迭代的范围。

2. 迭代的对象要实现和==的操作。

10. 指针空值nullptr(C11)10.1 C98中的指针空值

在传统头文件中有如上定义,我们发现在C中Null被宏替换为0,而如果我们要对一个指针赋空值,仍采用NULL的话有些不妥,因为0毕竟是一个数字,而不是指针类型,因此C11引入了nullptr,其实也就相当于(void*)0。

    推荐阅读
  • 怀孕二十天误食指甲油(指甲油可致癌还引发流产)

    最近,指甲油含塑化剂致癌物,长期使用可能致癌的报道,再度在微博上引发热议,长期使用指甲油会危害健康已毋庸置疑,但是,许多时尚MM仍然抱着偶尔用用无妨的心态,在透支着“美丽的代价”。五彩缤纷的指甲油,是冬天里的一道亮色,我们不禁想问,难道就没有一种绝对安全的指甲油吗?有没有什么办法让指甲油不再成为健康威胁呢?“美丽也是技术活”,不如来了解一下如何DIY属于你自己的那款指甲油吧。指甲油腐蚀泡沫不靠谱?

  • 日式极简原木风小户型(土味精装房变日系原木风)

    在北京传统四合院的布局里,大门常正对着一面「影壁墙」,而非其它室内门。

  • 命里有靠山的五大生肖(这些生肖一生都受上天照顾)

    在我们生活中有些人,生活真的就是一帆风顺,有如神助一样,但是并不是每个人都能得到这份赏赐,我们这些凡人也就只有羡慕的份了,到底能有这份荣耀的人都有些什么的过人之处?就让我们一起来看看这些一生都受上天照顾的生肖吧!

  • oppoa9和a9x的区别(oppoa9和a9x有什么区别)

    oppoa9和a9x区别如下1、外观方面:OPPOA9x配备了一块6.53英寸的水滴屏幕,屏占比达百分之90.0,屏幕分辨率为2340乘以1080,使用康宁第五代大猩猩玻璃;OPPOA9x后面板采用渐变式设计,有冰玉白和曜石黑两种配色,更在冰玉白机身后盖覆上珠光提高镀层,营造出光的流动效果,外观上来讲,这款OPPOA9x确实很漂亮,整体效果也非常的好;而OPPOA9则采用6.53英寸水滴屏,屏占比

  • 就地取材的意思(就地取材的解释)

    下面内容希望能帮助到你,我们来一起看看吧!就地取材的意思就地取材,汉语成语,拼音是jiùdìqǔcái,意思是在本地找需要的材料,比喻不依靠外力,充分发挥本身的潜力。

  • 芸豆和四季豆的区别,四季豆的好处 芸豆和四季豆的区别图片

    芸豆和四季豆其实是同一种豆科植物,只是称呼不同。四季豆做法简单,可以和很多种食材随意搭配。芸豆又称菜豆、四季豆,是玫瑰目豆科菜豆族菜豆属豆科植物,根系发达。吃有助于补铁、强壮骨骼,同时降低胆固醇,减轻心脏压力。

  • 三国时期东吴的四个冷知识(会有哪两个字来概括它的历史呢)

    三国时代,还有一个东吴,今天简单地来聊一聊东吴,是孙权在东南部建立的政权,又称孙吴。说到东吴便不得不说其开国皇帝——孙权。不过在说孙权之前,我们来简单介绍下孙权的父亲孙坚与兄长孙策。孙坚在东汉末年已经是一方诸侯,在十八路诸侯伐董卓的时候,他也是其中一支。孙坚其人有勇有谋,在讨伐董卓时,表现尤为突出,多次重创董卓。一次偶然,孙坚得到传国玉玺,这可把孙坚高兴坏了,想不到这却是孙坚厄运的开始。

  • 自己买的鲜羊肉怎么做羊肉串(羊肉串怎么做)

    自己买的鲜羊肉怎么做羊肉串先准备新鲜的羊肉,烤羊肉串建议用羊腿肉。碗里面再加入适量的盐和少量的水搅拌,羊肉搅拌均匀后腌半个小时。调料切记只需要放洋葱和盐就可以,不用放其他的大料。腌的时候加少许的水主要是要让洋葱和盐渗透到肉里面去,只有羊肉充分的吸收了水,这样烤的羊肉肉质才嫩。准备串羊肉串的竹签清洗干净,然后在水里泡一会。如果家里没有烤炉,就用烤箱烤,烤箱烤的话没有油烟,吃着更安全放心。

  • 快手怎么老是重新登录(快手怎么老是重新登录账号)

    快手的前身,叫“GIF快手”,诞生于2011年3月,最初是一款用来制作、分享GIF图片的手机应用。2012年11月,快手从纯粹的工具应用转型为短视频社区,用于用户记录和分享生产、生活的平台。后来随着智能手机的普及和移动流量成本的下降,快手在2015年以后迎来市场。

  • 春饼配什么菜好吃又简单(吃春饼少不了这炒合菜)

    取一小块纯瘦肉,冲洗干净后,先切成薄片,再切成细条。平底锅中再多倒一些食用油,油温5成热,倒入腌好的肉丝,快速地翻炒至肉丝变色,盛出备用。放入适量的生抽、老抽、食盐、十三香、花椒粉,翻炒均匀。炒至绿豆芽断生后,放入炒好的肉丝和鸡蛋,再放入焯了水的菠菜,最后放入切好的韭菜段,充分地翻炒均匀,即可关火出锅。