网页设计商城网站建设,wp建站优化,成都竞价托管多少钱,html5模板开发wordpress主题目录 一、什么是C二、C关键字三、命名空间3.1命名空间的定义3.2命名空间的使用 四、C输入和输出五、缺省参数5.1缺省参数的概念5.2缺省参数的分类 六、函数重载6.1函数重载的概念6.2函数重载的原理----名字修饰 七、引用7.1引用概念7.2引用特性7.3常引用7.4引用的使用7.5传值、… 目录 一、什么是C二、C关键字三、命名空间3.1命名空间的定义3.2命名空间的使用 四、C输入和输出五、缺省参数5.1缺省参数的概念5.2缺省参数的分类 六、函数重载6.1函数重载的概念6.2函数重载的原理----名字修饰 七、引用7.1引用概念7.2引用特性7.3常引用7.4引用的使用7.5传值、传引用效率比较7.6引用和指针的区别7.7引用与指针的不同点 八、内联函数8.1内联函数概念8.2 特性 九、auto关键字9.1类型别名思考9.2 auto简介9.3 auto的使用细则9.4 auto不能推导的场景 十、C范围的for循环C1110.1范围for的语法10.2范围for的使用条件 十一、nullptr指针空值C11 一、什么是C
二、C关键字
相较于C语言C语言有32个关键字而C则有63个关键字 三、命名空间
在C/C中变量、函数等的类都是大量存在的这些变量、函数和类的名称将都存 在于全局作用域中可能会导致很多冲突。 使用命名空间的目的是对标识符的名称进行本地化 以避免命名冲突或名字污染**namespace**关键字的出现就是针对这种问题的
3.1命名空间的定义
命名空间的普通定义
//命名空间的普通定义
namespace bit
{int rand 10;int scanf 2;int Add(int x, int y){return x y;}
}命名空间的嵌套定义
//命名空间的嵌套定义、
namespace bit1
{int rand 10;int scanf 2;int Add(int x, int y){return x y;}namespace bit2{int c;int d;int Sub(int left, int right){return left right;}}
}同一个命名空间的合并 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中
3.2命名空间的使用
作用域: 符号**“::”**在C中叫做作用域限定符我们通过“命名空间名称::命名空间成员”便可以访问到命名空间中相应的成员 加命名空间名称及作用域限定符,嵌套调用可以用xxx::bbb:: std::cin i;cout xxxx endl;cout bit::rand endl;使用using将命名空间中某个成员引入
using std::cout;
using std::endl;使用using namespace 命名空间名称 引入
using namespace bit;
int main()
{int i 0;std::cin i;cout xxxx endl;cout bit::rand endl;Add();
}四、C输入和输出
std是C标准库的命名空间名,C将标准库的定义实现都放在这个命名空间中 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时必须包含 iostream 头文件 以及按命名空间使用方法使用std。 输出流:cout和endl,其中endl表示换行输出.他们都包含在的头文件中 输入流:cin 是流插入运算符是流提取运算符 在C的输入输出可以自动识别变量类型
五、缺省参数
5.1缺省参数的概念
缺省参数是声明或定义函数时为函数的一个参数指定一个缺省值,在调用函数的时候,如果没有传参(也就是没有指定的实参)则采用该形参的缺省值
5.2缺省参数的分类
全缺省参数
void myq(int x5,int y2,int z5)
{cout x x endl;cout y y endl;cout z z endl;}半缺省参数
void fun(int x, int y 10)
{cout x y endl;
}半缺省参数必须从右往左依次来给出不能间隔着给缺省参数不能在函数声明和定义中同时出现
六、函数重载
同一个函数名可以定义为多个不同类型的函数
6.1函数重载的概念
函数重载是指在同一个作用域内可以定义多个具有相同名称但参数列表不同的函数。C通过函数的参数个数、类型或顺序的不同来实现函数重载。 通过使用相同的函数名来实现不同的功能和操作 //1.参数类型不同
int max(int x, int y)
{if (x y)return x;elsereturn y;
}double max(double x, double y)
{if (x - y 0)return x;else return y;
}
//2.参数个数不同
void max()
{cout max() endl;
}//3.参数类型的顺序
void min(int x, char y)
{cout x y endl;
}void min(char x, int y)
{cout x y endl;
}int main()
{max(1, 4);max(1.2, 4.2);max();min(6, m);min(m, 5);return 0;
}6.2函数重载的原理----名字修饰
C/C中,一个程序在运行中都需要经历这四个阶段:预处理、编译、汇编、链接 编译后链接前a.o的目标 文件中没有Add的函数地址因为Add是在b.cpp中定义的所以Add的地址在b.o中。那么 怎么办呢?链接阶段就是专门处理这种问题,链接器看到a.o调用Add但是没有Add的地址就会到b.o的符号表中找Add的地址然后链接到一起。在c中的链接,函数是通过函数名来寻找函数的地址而C中的链接,会通过函数名和函数参数的类型来寻找
七、引用
7.1引用概念
引用不是新定义一个变量而是给已有的变量去一个别名本质上就是同一个变量的不同叫法。 因此编译器不会为引用变量开辟内存空间他和它引用的变量共用同一块内存空间
类型 引用变量名(对象名) 引用实体 注意引用类型必须和引用实体为同一种类型 7.2引用特性 引用在定义是必须初始化一个变量可以有多个引用引用一旦引用一个实体,再不能引用其他实体 7.3常引用 int main()
{const int a 10;const int ma a;//int fa a; //编译出错double b 3.14;double fa b;const int c 10;double d 12.34;//int rd d; // 该语句编译时会出错类型不同const int rd d;cout b endl c endl;return 0;
}7.4引用的使用
参数引用
void Swap(int x, int y)
{int tmp x;x y;y tmp;
}
返回值引用
int count()
{static int x 0;x;return x;
}引用函数返回值的作用 避免不必要的对象拷贝开销提高程序的性能支持连续赋值和链式调用使代码更加简洁和易读同时允许函数返回修改后的对象增加了程序的灵活性。因此在设计函数接口时如果函数返回的是一个非基本数据类型的对象考虑返回值引用通常是一个不错的选择。
7.5传值、传引用效率比较
以值作为参数或者返回值类型在传参和返回期间函数不会直接传递实参或者将变量本身直接返回而是传递实参或者返回变量的一份临时的拷贝因此用值作为参数或者返回值类型效率是非常低下的尤其是当参数或者返回值类型非常大时效率就更低。
struct A { int a[10000]; };
void TestFunc1(A a) {}
void TestFunc2(A a) {}
void TestRefAndValue()
{A a;// 以值作为函数参数size_t begin1 clock();for (size_t i 0; i 10000; i)TestFunc1(a);size_t end1 clock();// 以引用作为函数参数size_t begin2 clock();for (size_t i 0; i 10000; i)TestFunc2(a);size_t end2 clock();// 分别计算两个函数运行结束后的时间cout TestFunc1(A)-time: end1 - begin1 endl;cout TestFunc2(A)-time: end2 - begin2 endl;
}传值和指针在作为传参以及返回值类型上效率相差很大
7.6引用和指针的区别
语法的概念上,引用就是一个别名,没有独立空间,同引用实体共用一块空间 而在编译器实现的底层上,实际是有空间的,因为引用也是按照指针方式来实现的,只是较于c来说,把事情的重复性交给了底层,来提高效率
7.7引用与指针的不同点
1. 引用概念上定义一个变量的别名指针存储一个**变量地址**。 2. **引用在定义时必须初始化而指针没有要求** 3. 引用在初始化时引用一个实体后就不能再引用其他实体而指针可以在任何时候指向任何一个同类型实体 4. 没有NULL引用但有NULL指针 5. 在sizeof中含义不同引用结果为引用类型的大小但指针始终是地址空间所占字节个数(32 位平台下占4个字节) 6. 引用自加即引用的实体增加1指针自加即指针向后偏移一个类型的大小 7. 有多级指针但是没有多级引用 8. 访问实体方式不同指针需要显式解引用引用编译器自己处理 9. 引用比指针使用起来相对更安全
八、内联函数
8.1内联函数概念
以inline修饰的函数叫做内联函数,编译时C编译器会在调用内联函数的地方展开没有函数调用建立栈帧的开销内联函数提升程序运行的效率 这里便涉及到汇编的一些知识 内联函数实质是,将整个函数(也就是这一堆的指令) ,直接展开使用 比较 宏: 宏虽然也能直接展开函,但宏的本质是将所写的指令从一个名字中替换 8.2 特性
inline是一种以空间换时间的做法如果编译器将函数当成内联函数处理在编译阶段会 用函数体替换函数调用. 缺陷可能会使目标文件变大优势少了调用开销提高程序运行效率。inline对于编译器而言只是一个建议不同编译器关于inline实现机制可能不同一般建议将函数规模较小(即函数不是很长具体没有准确的说法取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰否则编译器会忽略inline特性。inline不建议声明和定义分离分离会导致链接错误。因为inline被展开就没有函数地址 了链接就会找不到
相较于宏的优缺点: 优:
可以增强代码复用性提高性能 缺:不方便调试可读性差没有类型的检查 C有哪些技术替代宏 常量定义 换用const enum短小函数定义 换用内联函数 九、auto关键字
9.1类型别名思考
当程序过于复杂,类型过于繁多复杂,如
类型难以拼写含义不明确
#include string
#include map
int main()
{std::mapstd::string, std::string m{ { apple, 苹果 }, { orange,
橙子 }, {pear,梨} };std::mapstd::string, std::string::iterator it m.begin();while (it ! m.end()){//....}return 0;
}std::mapstd::string, std::string::iterator 是一个类型但是该类型太长了特别容易写错。
使用typedef给类型取别名确实可以简化代码但是typedef有会遇到新的难题:
typedef char* pstring;
int main()
{const pstring p1; // 编译成功还是失败const pstring* p2; // 编译成功还是失败return 0;
}在编程时常常需要把表达式的值赋值给变量这就要求在声明变量的时候清楚地知道表达式的 类型。然而有时候要做到这点并非那么容易因此C11给auto赋予了新的含义。
9.2 auto简介
使用auto修饰的变量是具有自动存储器的局部变量 但实际应用中并不多见,这是为什么?
auto不再是一个存储类型指示符而是作为一 个新的类型指示符来指示编译器auto声明的变量必须由编译器在编译时期推导而得
【注意】 使用auto定义变量时必须对其进行初始化在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明而是一个类型声明时的“占位符”编译器在编译期会将auto替换为变量实际的类型。
9.3 auto的使用细则
auto与指针和引用结合起来使用 用auto声明指针类型时,用auto和auto* 没有区别,但用auto声明引用类型则必须加 在同一行定义多个变量 当在同一行声明多个变量时这些变量必须是相同的类型否则编译器将会报错因为编译 器实际只对第一个类型进行推导然后用推导出来的类型定义其他变量。
9.4 auto不能推导的场景
auto不能作为函数的参数
// 此处代码编译失败auto不能作为形参类型因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{}不能直接用来声明数组
十、C范围的for循环C11
10.1范围for的语法
C是兼容C的,所以for循环中,C的语法依然是适用的
int main()
{for(int i0;i10;i){printf(%d ,i);}return 0;
}对于一个有范围的集合而言由程序员来说明循环的范围是多余的有时候还会容易犯错误。因 此C11中引入了基于范围的for循环。for循环后的括号由冒号“ ”分为两部分第一部分是范 围内用于迭代的变量第二部分则表示被迭代的范围。 for(迭代变量 : 别迭代范围){} int main()
{int array1[] { 1,2,3,4,5,6 };int array2[] { 1,2,3,4,5,6 };//仅仅只是变量的拷贝不做修改for (int i : array1){i * 2;}for (auto e : array1){cout e ;}cout endl;//for范围配合引用可以做到指针的效果for (auto i : array2){i * 2;}for (auto i : array2){cout i ;}return 0;
}10.2范围for的使用条件
for循环迭代的范围必须是确定的 对于数组而言**,就是数组中第一个元素和最后一个元素的范围**;对于类而言,应该提供begin和end的办法,begin和end就是for循环迭代的范围
十一、nullptr指针空值C11
声明一个变量时最好给该变量一个合适的初始值否则可能会出现不可预料的错误比如未初始化的指针。如果一个指针没有合法的指向我们基本都是按照如下方式对其进行初始化 int* N NULL;int* M 0;在C的头文件中,(stddef.h) NULL实际是一个宏 ,所以在应用中,NULL可能被定义为字面常量0或者被定义为无类型指针(void*)的常量。不论采取何种定义在使用空值的指针时都不可避免的会遇到一些麻烦
void fun(int)
{cout fun(int) endl;
}
void fun(int*)
{cout fun(int*) endl;
}int main()
{fun(0);fun(NULL);fun((int*)NULL);return 0;
}本意是想通过f(NULL)调用指针版本的f(int*)函数但是由于NULL被定义成0因此与程序的 初衷相悖. 字面常量0既可以是一个整形数字也可以是无类型的指针(void*)常量但是编译器默认情况下将其看成是一个整形常量如果要将其按照指针方式来使用必须对其进行强转(void *)0。
注意 在使用nullptr表示指针空值时不需要包含头文件因为nullptr是C11作为新关键字引入 的。在C11中sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。为了提高代码的健壮性在后续表示指针空值时建议最好使用nullptr