房产中介网站建设管理,wordpress发不文章不按顺序怎么办,专做专业课视频的网站,网页设计代码模板免费本专栏目的
更新C/C的基础语法#xff0c;包括C的一些新特性
前言 1-10在上篇C/C语言基础–从C到C的不同(上#xff09;#xff1b;当然C和C的不同还有很多#xff0c;本人暂时只总结这些#xff0c;其他的慢慢更新#xff1b;上一篇C/C语言基础–从C到C的不同(上…本专栏目的
更新C/C的基础语法包括C的一些新特性
前言 1-10在上篇C/C语言基础–从C到C的不同(上当然C和C的不同还有很多本人暂时只总结这些其他的慢慢更新上一篇C/C语言基础–从C到C的不同(上受到了不少人的喜欢因此本人抓紧赶出下篇欢迎大家点赞 收藏 关注C语言后面也会继续更新知识点如内联汇编本人现在正在写一个C语言的图书管理系统1000多行代码包含之前所学的所有知识点包括链表和顺序表等数据结构请大家耐心等待 思维导图如下 文章目录 11. 枚举类型1C语言中的enum2C中的enum3,C中的 enum class 强枚举类型小结 12. auto自动类型推导13. for循环遍历14. 类型信息15. 函数内联函数函数默认参数占位参数函数重载**函数重载的不同****重载函数的调用匹配规则** 函数重载遇上默认参数 11. 枚举类型
C语言和C语言都提供了枚举类型两者是有一定区别。
有如下定义
enum SHAPE {CIRCLE,RECT,LINE,POINT};
enum WEEK {MON,TUE,WED,THI,FIR,SAT,SUN};1C语言中的enum 允许非枚举值赋值给枚举类型允许其他枚举类型的值赋值给另一个枚举类型 enum WEEK today 3; //正确
today CIRCLE; //正确枚举具有外层作用域容易造成名字冲突(在不同作用域不会冲突但是遵循就近原则访问不到外层作用域的枚举)
enum OTHER { RECT };//error C2365: “RECT”: 重定义以前的定义是“枚举数”
int RECT 12; //同上不同类型的枚举值可以直接比较
if (CIRCLE MON)
{printf(oh.yes);
}2C中的enum
只允许赋值枚举值
enum WEEK today 3; //错误 error C2440: “初始化”: 无法从“int”转换为“main::WEEK”
today CIRCLE; //错误 error C2440: “”: 无法从“main::SHAPE”转换为“main::WEEK”枚举元素会暴露在外部作用域不同两个枚举类型若含有相同枚举元素则会冲突
enum OTHER { RECT }; //错误 error C2365: “RECT”: 重定义以前的定义是“枚举数”
int RECT 12; //错误同上 但是可以通过枚举名访问指定的枚举属性
OTHER::RECT; //正确不同类型的枚举也可以直接比较
if (CIRCLE MON)
{coutoh.yes;
}3,C中的 enum class 强枚举类型
enum class SHAPE {CIRCLE,RECT,LINE,POINT};
enum class WEEK {MON,TUE,WED,THI,FIR,SAT,SUN};强枚举类型不会将枚举元素暴露在外部作用域必须通过枚举名去访问
coutSHAPCE::RECTendl; //输出 1 不相关的两个枚举类型不能直接比较编译报错
if (SHAPE::CIRCLE WEEK::MON) //error C2676: 二进制“”:“main::SHAPE”不定义该运算符或到预定义运算符可接收的类型的转换
{coutoh.yes;
}小结
C语言中枚举可以暴露在外面且可以枚举与非枚举之间进行比较赋值等操作C中枚举可以暴露外外面但是不可以枚举与非枚举之间进行赋值但是可以比较C强枚举中不可以暴露在外面必须指明作用域才能使用枚举与非枚举之间不能进行比较赋值就算是枚举与枚举之间不相关的枚举之间也不行。
12. auto自动类型推导
在 C11 之前的版本中定义变量或者声明变量之前都必须指明它的类型比如 int、char 等这个其实很不方便尤其是在复杂项目的时候有多个命名空间如Boost::asio::ip::tcp等等而在其他语言如js就只需要用关键字var或者let定义变量就行到C11后auto诞生了可以在编译的时候制动推导替换类型。
注意auto 仅仅是一个占位符在编译器期间它会被真正的类型所替代。或者说C 中的变量必须是有明确类型的只是这个类型是由编译器自己推导出来的。
使用 auto 类型推导的变量必须马上初始化auto 不能在函数的参数中使用(但是能作为函数的返回值)auto 不能作用于类的非静态成员变量也就是没有 static 关键字修饰的成员变量中auto 关键字不能定义数组auto 不能作用于模板参数
13. for循环遍历
对于一个有范围的集合而言由程序员来说明循环的范围是多余的有时候还会容易犯错误因此C大叔给我们提供了一个简单的方法如下
int arr[]{1,2,3,4,5,6,7};
//一般用法
for(int i0;isizeof(arr)/sizeof(arr[0]);i)
{coutarr[i] ;
}
//新用法
for(int i:arr)
{couti ;
}特点
从数组的第一个元素开始逐个赋值给迭代变量不依赖于下标元素通用但是经常还是喜欢用第一种哈哈哈哈哈哈哈。
14. 类型信息
typeid 是一个运算符用来获取一个表达式的类型信息。
typeid 的操作对象既可以是表达式也可以是数据类型下面是它的两种使用方法
typeid( dataType )
typeid( expression )typeid 会把获取到的类型信息保存到一个 type_info 类型的对象里面并返回该对象的常引用当需要具体的类型信息时可以通过成员函数来提取本质是一个类封装了大量的API如下
//获取一个普通变量的类型信息
int n 100;
const type_info nInfo typeid(n);
cout nInfo.name() | nInfo.raw_name() | nInfo.hash_code() endl;//获取一个字面量的类型信息
const type_info dInfo typeid(25.65);
cout dInfo.name() | dInfo.raw_name() | dInfo.hash_code() endl;//获取一个普通类型的类型信息
const type_info charInfo typeid(char);
cout charInfo.name() | charInfo.raw_name() | charInfo.hash_code() endl;//获取一个表达式的类型信息
const type_info expInfo typeid(20 * 45 / 4.5);
cout expInfo.name() | expInfo.raw_name() | expInfo.hash_code() endl;其中
name() 用来返回类型的名称。raw_name() 用来返回名字编码Name Mangling算法产生的新名称。。hash_code() 用来返回当前类型对应的 hash 值。
除此之外还可以用 比较两个类型是否相等如下
char *str;
int a 2;
int b 10;
float f;类型判断结果为
类型比较结果类型比较结果typeid(int) typeid(int)truetypeid(int) typeid(char)falsetypeid(char*) typeid(char)falsetypeid(str) typeid(char*)truetypeid(a) typeid(int)truetypeid(b) typeid(int)truetypeid(a) typeid(a)truetypeid(a) typeid(b)truetypeid(a) typeid(f)falsetypeid(a/b) typeid(int)true
建议内容很多这个其实也并不常用可以留个映像到后面用到的时候查询即可。
15. 函数
内联函数
函数调用时通过哈希表需要跳转到函数的地址去执行执行完成后返回到被调用函数比较费时因此C中提供了一种操作方式允许编译时直接把函数替换到调用处即内联函数。
// 使用
inline int add(int a, int b) {return a b;
}为什么使用内联函数 内联函数没有普通函数调用时的额外开销(压栈跳转返回)
注意
内联函数声明时inline关键字必须和函数定义结合在一起否则编译器会直接忽略内联请求。C编译器不一定准许函数的内联请求(只是对编译器的请求因此编译器可以拒绝)现代C编译器能够进行编译优化因此一些函数即使没有inline声明也可能被编译器内联编译 C中内联函数的限制 不能存在任何形式的循环语句不能存在过多的条件判断语句函数体不能过于庞大不能对函数进行取址操作编译器对于内联函数的限制并不是绝对的内联函数相对于普通函数的优势只是省去了函数调用时压栈跳转和返回的开销。因此当函数体的执行开销远大于压栈跳转和返回所用的开销时那么内联将无意义。
总结上面内容过多很难记住我也记不住我只记住了内联函数可以直接跳转到函数地址中执行省去入栈出栈等开销还有就是内联函数之间不能写太多东西。
函数默认参数
定义函数时可以给形参指定一个默认的值这样调用函数时如果没有给这个形参赋值没有对应的实参那么就使用这个默认的值。
void showX(int x 666)
{coutx:xendl;
}
showX();
showX(6);小结
有函数声明时默认参数可以放在声明或定义中但不能同时存在
int add(int a,int b 5);
int add(int a,int b)
{return ab;
}注意函数声明时必须按照从右向左的顺序依次给与默认值。
int foo(int a, int b 2, int c 3); // 正确
int foo1(int a, int b 2, int c); // 错误, i3未指定默认值
int foo2(int a 1, int b, int c 3); // 错误, i2未指定默认值占位参数
定义函数时还可以给函数提供占位参数
占位参数只有参数类型而没有参数名在函数体内部无法使用占位参数占位参数也可以指定默认参数
void func(int a,int 0)
{coutaendl;
}
func(2);函数重载
不知道在C语言写函数的时候会不会遇到这种情况想函数名难想(不想直接拼音)而如果想实现以下功能
int add(int a, int b) {return a b;
}int add(double a, double b) {return a b;
}想实现以上功能的时候好像名字都可以用add故在C的时候引入了一个新的概念函数重载。(当然上面的实现还可以更加简介他可用模板这个后面会更新)。
函数重载是指在同一作用域内可以有一组具有相同函数名不同参数列表的函数这组函数被称为重载函数。
函数重载的不同
参数个数不同参数类型不同参数顺序不同函数重载与返回值类型无关
来个例子体会一下比较不同类型的两个变量的大小
int maxmum(int a, int b)
{return a b?a:b;
}
long maxmum(long int a, long int b)
{return a b ? a : b;
}
char maxmum(char a, char b)
{return a b ? a : b;
}
double maxmum(double a, double b)
{return a b ? a : b;
}
const char* maxmum(const char* str1,const char* str2)
{return strcmp(str1, str2)1?str1:str2;
}
char* maxmum(char* str1, char* str2)
{return strcmp(str1, str2) 1 ? str1 : str2;
}int main()
{cout maxmum(2, 6) endl;cout maxmum(2L, 6L) endl;cout maxmum(A, C) endl;cout maxmum(maye, MAYE) endl;char str1[] hello;char str2[] hello;cout maxmum(str1, str2) endl;return 0;
}函数重载可以根据具体的参数去决定调用哪一个函数。
重载函数的调用匹配规则
精确匹配参数匹配而不做转换或者只是做微不足道的转换如数组名到指针、函数名到指向函数的指针提升匹配即整数提升如bool 到 int、char到int、short 到intfloat到double使用标准转换匹配如int 到double、double到int、double到long double、Derived到Base、T到void、int到unsigned int
函数重载遇上默认参数
如果在给重载函数的时候指定默认参数时这个时候很容易造成函数冲突如下
void fun(int a)
{cout fun(int a) a endl;
}
void fun(int a, int b 8)
{cout fun(int,int 8) a b endl;
}
int main()
{//fun(5); //error C2668: “fun”: 对重载函数的调用不明确fun(5, 6);//正确return 0;
}