建个网站要花多少钱,做企业官网的步骤,wordpress文章怎么打开空格,手机编程教学目录1.认识Chello worldC关键字2.命名空间3.std标准库4.输入输出5.缺省参数6.函数重载7.引用7.1引用的概念7.2引用的场景1.作参数2.作返回值7.3引用的注意点7.4指针和引用的区别8.auto关键字9.基于范围的for循环10.内联函数10.1概念10.2特征11. C98中的指针空值1.认识C
hello …
目录1.认识Chello worldC关键字2.命名空间3.std标准库4.输入输出5.缺省参数6.函数重载7.引用7.1引用的概念7.2引用的场景1.作参数2.作返回值7.3引用的注意点7.4指针和引用的区别8.auto关键字9.基于范围的for循环10.内联函数10.1概念10.2特征11. C98中的指针空值1.认识C
hello world
#includeiostream
int main() {std::cout hello world std::endl;return 0;
}C关键字 C语言32个关键字而C总计63个关键字 2.命名空间 对于上述问题即是C语言常见的命名冲突问题C中用命名空间来解决 命名空间是域
变量查找规则先在局部找再全局找 在C/C中变量、函数和后面要学到的类都是大量存在的这些变量、函数和类的名称将都存 在于全局作用域中可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化 以避免命名冲突或名字污染 namespace关键字的出现就是针对这种问题的。 定义命名空间需要使用到namespace关键字后面跟命名空间的名字然后接一对{}即可 {} 中即为命名空间的成员
默认查找规则先在局部找再全局找
#includestdio.h
#includestdlib.h
namespace A {int rand 10;int x 1;
}int main() {printf(%p\n, rand);printf(%d\n, A::rand);printf(%d\n, A::x);return 0;
}namespace域不会影响生命周期相当于全局变量放在静态域中在预处理完后头文件展开rand未找到局部变量的定义因此在头文件声明展开后的全局找到了它而我们用到的**::即为作用域限定符**相当于在查找变量时在指定空间查找
变量定义在全局和定义在命名空间的区别防止冲突
1.命名空间中可以定义变量/函数/类型可以嵌套
namespace N1
{int a;int b;int Add(int left, int right){return left right;}namespace N2{int c;int d;int Sub(int left, int right){return left - right;}}
}对于嵌套的命名空间访问时应
N1::a1;
N1::N2::c2;2.同一个工程中允许存在多个相同名称的命名空间 ,编译器最后会自动合并到同一个命名空间中
3.std标准库
std是C标准库的命名空间如何展开std使用更合理呢
1.在日常练习中建议直接using namespace std即可这样就很方便 2.using namespace std展开标准库就全部暴露出来了如果我们定义跟库重名的类型/对象/函数就存在冲突问题因此我们不展开std而是使用时加上std作用域限定符 3.指定展开常用的展开自己定义的时候避免跟常用重名即可 总结命名空间std尽量避免全部展开防止命名冲突
4.输入输出
1.使用cout标准输出对象(控制台Console)和cin标准输入对象**(键盘)时必须包含 iostream头文件 以及按命名空间使用方法使用std**
2.cout和cin是全局的流对象 endl是特殊的C符号表示换行输出他们都包含在包含 iostream 头文件中。
3.****是流插入运算符 ****是流提取运算符。
4.使用C输入输出更方便不需要像printf/scanf输入输出时那样需要手动控制格式C的输入输出可以自动识别变量类型
#include iostream
using namespace std;int main()
{int a;double b;char c;// 可以自动识别变量的类型cin a;cin b c;cout a endl;cout b c endl;return 0;
}C的输入输出虽然方便了却不好精确控制输入输出格式例如保留小数点后几位但是C兼容C语言因此在处理这些问题时可以配合着C语言使用对于值、字符串、空格等多种混输出时printf同样的比cout更方便
5.缺省参数
using namespace std;
void Func(int a 10, int b 20, int c 30) {cout a a endl;cout b b endl;cout c c endl;
}1.全缺省调用
int main() {Func();
}2.半缺省调用从左向右依次传
int main() {Func(1);
}缺省只能从右往左连续缺省
此时b和c缺省
void Func(int a, int b 20, int c 30) {cout a a endl;cout b b endl;cout c c endl;
}例如缺省的使用
namespace S {typedef struct Stack{int* a;int top;int capacity;}ST;void StackInit(ST* ps, int defaultCapacity 4) {ps-a (int*)malloc(sizeof(int)*defaultCapacity);assert(ps-a);ps-top 0;ps-capacity defaultCapacity;}
}int main() {//不知道要插入多少数据S::ST st1;S::StackInit(st1);//知道要插入100个数据S::ST st2;S::StackInit(st2, 100);
}注意缺省参数不能在函数声明和定义中同时出现规定只能在声明时.h去定义缺省参数
//a.h
void Func(int a 10);// a.cpp
void Func(int a 20){}
// 注意如果声明与定义位置同时出现恰巧两个位置提供的值不同那编译器就无法确定到底该用那个缺省值。6.函数重载 函数重载是函数的一种特殊情况 C允许在同一作用域中声明几个功能类似的同名函数这些同名函数的形参列表(①参数个数或②类型或③类型顺序)不同常用来处理实现功能类似数据类型不同的问题。 int add(int x, int y) {return x y;
}double add(double x, double y) {return x y;
}int main() {cout add(1, 2) endl;cout add(1.2, 1.5) endl;return 0;
}①C能自动识别参数类型本质也是函数重载支持的
②函数重载调用时应该明确调用哪个函数重载缺省调用会报错二义性
③为什么C语言不支持重载C是怎么支持重载呢——函数名修饰(name Mangling)
④返回值不同不能构成重载原因是调用时的二义性无法区分调用时不指定返回值类型
7.引用
7.1引用的概念 引用不是新定义一个变量而是给已存在变量取了一个别名编译器不会为引用变量开辟内存空 间它和它引用的变量共用同一块内存空间 类型 引用变量名(对象名) 引用实体引用的存在就能间接替代C语言当中的指针的部分功能了无法完全替代指针
例如我们常用的交换函数
void Swap(int m, int n) {int tmp m;m n;n tmp;
}int main() {int a 10;int b 20;Swap(a, b);std::cout a a b b std::endl;
}同理的我们不仅能给一般变量取别名也可以给指针变量取别名因此可以代替二级指针
*pa**p; //相当于我们用pa来代替*p那么对于**p来说即为*pa注意
①引用在定义时必须初始化
② 一个变量可以有多个引用
③引用一旦引用一个实体再不能引用其他实体引用的指向不可改变
7.2引用的场景
1.作参数
一般用作输出型参数C中可用引用来替代指针减少拷贝提高效率
void Swap1(int left, int right)
{int temp left;left right;right temp;
}2.作返回值
①引用返回
int Count()
{ //只有静态才行减少了一次拷贝static int n 0;n;// ...return n;
}②传值返回
int Count()
{static int n 0;n;// ...return n;
}那么引用返回和传值返回有什么区别呢
在传值返回时会将返回值拷贝到一个临时变量寄存器或上一层栈帧中而利用引用返回时也可以理解为存在一个临时变量它的类型仍是引用类型相当于返回了一个返回值n的别名但是由于返回时原返回值n的栈已经销毁了而返回的它的别名仍然指向的这一片空间
内存空间销毁意味着什么
①空间还在吗在只是使用权不是我们的我们存的数据不被保护
②我们还能访问吗能只是我们读写的数据都是不确定的 为什么会出现100main函数调用了Func函数恰好和调用Count位于同一块空间ret是这块空间的别名因此它的值变成了100本质即是非法空间的访问这也说明了空间是可以重复使用的
【结论】出了函数作用域返回变量不存在了不能用引用返回因为引用返回的结果是未定义的正确使用引用返回值是对于静态声明的变量返回变量还存在这种情况就可以使用使用它的意义即是在返回值传递时不用再开辟临时拷贝变量提高效率
通过设计一个简单的程序可以发现确实能提高效率 7.3引用的注意点
1.指针和引用赋值中权限可以缩小但是不能放大
这里b是只读的a是可读可写的 对于权限缩小是允许的 需要注意的是权限的放大缩小只对于指针或引用来说的正常的赋值是无影响的
int a1;
const int b0;
ab; //right这里是将b的值传递给aa值的改变并不会影响b其本质即是它们不是指针/引用变量值的改变对互相无影响这也是指针/引用赋值中有权限放大缩小的概念
那么对于以后一般用引用参数都是用const引用但是如果你要修改这个参数不用const就行了 2.引用不能使用缺省参数因为缺省参数一般是常量但是加上const即可使用
void func(const int N10){ //right}3.引用时涉及强制类型转换需要用到常引用
强制类型转换会产生临时变量例如我们将double类型的a转换为int类型我们输出10但是我们修改的不是并不是a输出的是产生的临时变量 临时变量具有常性无法被修改因此在引用时也要定义常引用
int ra1 a; //wrong
const int ra2 a; //right这里的ra2不是a的别名了而是这个临时变量的别名打印ra2的值即可验证 4.传值返回不能用引用变量接收
同理传值返回涉及到临时变量的拷贝临时变量具有常性因此只能用const引用接收 5.语法层面上ra是a的别名不开空间底层实现上引用是使用指针实现的
7.4指针和引用的区别
①引用概念上定义一个变量的别名指针存储一个变量地址。
②引用在定义时必须初始化指针没有要求
③引用在初始化时引用一个实体后就不能再引用其他实体而指针可以在任何时候指向任何 一个同类型实体
④没有NULL引用但有NULL指针
⑤在sizeof中含义不同引用结果为引用类型的大小但指针始终是地址空间所占字节个数(32 位平台下占4个字节64位平台下占8个字节)
⑥引用自加即引用的实体增加1指针自加即指针向后偏移一个类型的大小
⑦有多级指针没有多级引用
⑧访问实体方式不同 指针需要显式解引用引用编译器自己处理
⑨引用比指针使用起来相对更安全
8.auto关键字
引入随着程序越来越复杂程序中用到的类型也越来越复杂经常体现在 ①类型难于拼写 ②含义不明确导致容易出错 因此有了auto一个类型指示符来指示编译器 auto声明的变量类型由编译器在编译时期推导而得
int a10;
auto ba;定义变量时auto声明的变量b根据a的类型推导b的类型
9.基于范围的for循环
范围for循环的作用是方便遍历数组
int arr[]{1,2,3,4,5};
//依次取arr中数据赋值给e自动判断结束自动迭代
for(auto e:arr)
{coute ;
}
coutendl;遍历结果为 10.内联函数
10.1概念 以inline修饰的函数叫做内联函数 编译时C编译器会在调用内联函数的地方展开没有函数调用建立栈帧的开销内联函数提升程序运行的效率 例如对于冒泡排序、交换排序等我们涉及到Swap交换函数当数据量很大的时候就要多次调用Swap频繁调用的小函数即多次调用栈帧C语言中通过宏函数可以避免栈帧消耗预处理替换优化
而对于C来说可以通过inline函数内联函数来解决
为什么不继续使用C语言的宏①不能调试②没有类型安全检查③容易出错
例如ADD的宏函数
#define ADD(int x,int y) ((x)(y))10.2特征
1.inline是一种以空间换时间的做法如果编译器将函数当成内联函数处理在编译阶段会用函数体替换函数调用缺陷可能会使目标文件变大优势少了调用开销提高程序运行效率。
2.inline对于编译器而言只是一个建议不同编译器关于inline实现机制可能不同一般建议将函数规模较小即函数不是很长具体没有准确的说法取决于编译器内部实现不是递归、且频繁调用的函数采用inline修饰否则编译器会忽略inline特性
是否展开取决于编译器函数过长强行展开会引起代码膨胀 代码量决定了可执行程序的大小在开发中编译出的程序即可以被理解为安装包 3.在debug模式下内联不会默认展开通过修改设置可以展开 使用时直接在函数前加关键字inline即可
inline ADD(int a,int b){return ab;
}4.inline不在声明和定义分离在.h文件中声明后预处理后会在.cpp文件展开inline被展开没有函数地址链接地址就会找不到
11. C98中的指针空值 在良好的C/C编程习惯中声明一个变量时最好给该变量一个合适的初始值否则可能会出现不可预料的错误比如未初始化的指针如果指针没有合法的指向我们基本都是按照如下 方式对其进行初始化 int* p1 NULL;
int* p2 0;NULL实际是一个宏在传统的C头文件(stddef.h)中可以看到如下代码
#ifndef NULL
#ifdef __cplusplus
#define NULL
#else
#define NULL
#endif
#endif可以看到 NULL可能被定义为字面常量0或者被定义为无类型指针(void)的常量
由于语言具有向前兼容的特点因此在C98中的指针空值问题延续到了现在
解决方案为关键字nullptr表示指针空值因此在以后我们均使用nullptr来表示空指针
return ab; } 4.inline不在声明和定义分离在.h文件中声明后预处理后会在.cpp文件展开inline被展开没有函数地址链接地址就会找不到## 11. C98中的指针空值 在良好的C/C编程习惯中声明一个变量时最好给该变量一个合适的初始值否则可能会出现不可预料的错误比如未初始化的指针如果指针没有合法的指向我们基本都是按照如下 方式对其进行初始化cpp
int* p1 NULL;
int* p2 0;NULL实际是一个宏在传统的C头文件(stddef.h)中可以看到如下代码
#ifndef NULL
#ifdef __cplusplus
#define NULL
#else
#define NULL
#endif
#endif可以看到 NULL可能被定义为字面常量0或者被定义为无类型指针(void)的常量
由于语言具有向前兼容的特点因此在C98中的指针空值问题延续到了现在
解决方案为关键字nullptr表示指针空值因此在以后我们均使用nullptr来表示空指针