什么是网站的功能模块,什么是一学一做视频网站好,大连网站建设-网龙科技,房屋3d设计软件初识C和C语言缺陷补充 一.主要内容#xff1a;二.具体内容#xff1a;一#xff1a; 作用域1.命名空间#xff1a;2.函数声明和定义#xff1a;3.不存在命名冲突的情况#xff1a; 二.输入输出#xff1a;1.基本输入输出#xff1a;2.关于std的展开#xff1a; 三.函数… 初识C和C语言缺陷补充 一.主要内容二.具体内容一 作用域1.命名空间2.函数声明和定义3.不存在命名冲突的情况 二.输入输出1.基本输入输出2.关于std的展开 三.函数1.缺省参数部分2.全缺省3.缺省参数的定义和参数的传递4.函数重载1.参数个数2.类型3.类型顺序4.总结如果存在一种情况 5.为什么出现函数重载编译链接的原理1.预编译预处理2.编译3.汇编4.链接 6.引用1.基本概念1-1关于函数的引用1-2引用用的特殊1-3常引用 2.常规用法1.作为函数参数2.作为函数返回值 3.特殊用法1.解决方法一二级指针2.解决方法二引用 4.总结7.内联函数1.概念2.inline的优缺点 一.主要内容 1.对于C 来说是在C语言的基础之上刚开始进行对C语言的缺陷进行了优化解决加入面向对象的编程思想加入了非常多有用的库和一些编程范式。对于C语言比较属性那么对于C的学习是有帮助的。 2.那么C对于C语言的一些些缺陷是在那一些方面呢包括有作用域IO方面函数方面指针宏方面进行了修改。 二.具体内容
一 作用域
1.命名空间 1.在C语言中存在这样的一个情况我们使用一个全局变量的时候有可能在命名变量名称的时候和C语言标准库中的内容产生冲突1.我们的标准库在全局展开会和自己的变量名称冲突 2.在我们做一个项目的时候我们定义的变量名函数名和其他人会有冲突。 2.解决方法使用命名空间这一个C提供的语法namespace关键字它可以把我们本地定义的内容进行包裹在正常开始访问变量的时候默认只访问全局。下面这个代码没有进入命名空间在全局只有一个rand函数所以打印出来了一个随机值。 3.如何使用自己的命名空间呢 :: 域作用限定符 命名空间名称域作用限定符去访问这个命名空间。 命名空间中可以放什么东西呢 变量名函数声明函数定义结构体联合体枚举等等。 4.如果出现了在一个命名空间中有两个这个同名称的变量或者函数等等。非常容易解决这个问题因为我们C是支持命名空间的嵌套的 2.函数声明和定义 1自己的函数声明放在自己的命名空间中自己的定义放在自己的命名空间中在我们进行定义和声明分离的时候我们要把定义和声明放在同一个空间中 #includeStack.hnamespace sfpy_stack {//函数定义//1.初始化void InitStack(struct Stack* st1){assert(st1 ! NULL);StData* tmp (StData*)malloc(sizeof(StData) * 4);if (tmp NULL){perror(malloc file);exit(-1);}st1-st tmp;st1-top 0;st1-capacity 4;}//2.插入数据void StackPush(struct Stack* st1, StData x){if (st1-top st1-capacity){StData* tmp (StData*)realloc(st1-st,(sizeof(StData)*((st1-capacity)*2)));if (tmp NULL){perror(malloc file);exit(-1);}st1-st tmp;st1-capacity (st1-capacity) * 2;}st1-st[st1-top] x;st1-top;}//3.数据遍历void StackPrint(struct Stack* st1){assert(st1 ! NULL);for (int i 0; i st1-top; i){printf(%d , st1-st[i]);}}//4.栈销毁void StackDestory(struct Stack* st1){free(st1-st);st1-st NULL;}
}#includestdio.h
#includestdlib.h
#includeassert.hnamespace sfpy_stack {typedef int StData;typedef struct Stack{StData* st;int top;int capacity;}sk;//函数声明//1.初始化void InitStack(struct Stack* st1);//2.插入数据void StackPush(struct Stack* st1, StData x);//3.数据遍历void StackPrint(struct Stack* st1);//4.栈销毁void StackDestory(struct Stack* st1);
}#includeStack.hint main()
{//1.定义一个结构体struct sfpy_stack::Stack st;//1-1:在有struct的情况下//我们定义结构体变量使用上面这个方法//sfpy_stack::struct Stack st2;//1-2:重命名之后就可以使用下面这个方法//sfpy_stack::sk st2;//2.进行初始化sfpy_stack::InitStack(st);//3.数据插入sfpy_stack::StackPush(st, 1);sfpy_stack::StackPush(st, 2);sfpy_stack::StackPush(st, 3);sfpy_stack::StackPush(st, 4);sfpy_stack::StackPush(st, 5);sfpy_stack::StackPush(st, 6);//4.栈数据的打印sfpy_stack::StackPrint(st);//4.进行销毁sfpy_stack::StackDestory(st);return 0;
}3.不存在命名冲突的情况 1.如何打开命名空间使用using namespace spfy_stack; 2.打开命名空间就可以不使用域限定操作符直接使用变量函数等。 3.在我们的个人作业不存在命名冲突的情况使用using namespace spfy_stack ,可以在你去使用命名空间内容就可以不使用域限定操作符 二.输入输出
1.基本输入输出 1.C 官方标准库iostream。 2.我们的std空间名称是C的官方定义的输入输出相关的命名空间。 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时必须包含 iostream 头文件以及按命名空间使用方法使用std。cout和cin是全局的流对象endl是特殊的C符号表示换行输出他们都包含在包含 iostream 头文件中。是流插入运算符是流提取运算符。 使用C输入输出更方便不需要像printf/scanf输入输出时那样需要手动控制格式。C的输入输出可以自动识别变量类型。 实际上cout和cin分别是ostream和istream类型的对象和也涉及运算符重载等知识。 2.关于std的展开 1.std是C 标准库中的一个命名空间他的展开是需要考虑情况的因为对于一个由多个人完成的项目来说这个空间是不可以展开的。 2。在自己的练习上面去使用using namespace std;打开标准库的这一个命名空间这样可以不需要去使用标准库名称和域限定操作符。 3-1换行的多种方法 3-11.在字符串中结尾使用\n. 2.在输出到控制台的单词后面加一个“\n”.3.使用endl结尾这个是std这个命名空间中的一个用来换行的根第2个是同样的效果。 endlend line 4:如果存在一种情况需要换行多次但是其他的std中的有冲突(不允许完全打开命名空间)我们可以只打开命名空间中的一个操作符。 三.函数
1.缺省参数部分 如果我们给这个函数的这个变量进行了传参我们就使用我们的传参如果我们没有去进行传参就使用默认的缺省参数。 2.作用我们开辟栈空间知道要看多少空间和不知道需要开多少空间 2-1不知道要开多少空间我们就使用默认开辟空间的值后面动态增长 2-2知道要开多少空间我们就使用传参的值一下开辟好空间不需要多次判断扩容 2-3函数相同在存在一个缺省值的情况下完成了多个功能。 注意如果生命与定义位置同时出现恰巧两个位置提供的值不同那编译器就无法确定到底该用那个缺省值。 2.全缺省 1.函数的参数全部都具有缺省值这样我们对于一个函数就有n1种调用方式为什么可以使用相同的函数名称呢我们接下来再说 3.缺省参数的定义和参数的传递 1.缺省参数值只能从右往左给。 2.函数传实参只能从左往右。 3.如果我们给了全部缺省我们不能跳跃的进行实参传递。 4.函数的声明和定义中不要同时出现缺省参数我们一般在函数的声明中给缺省值如果函数的定义和声明中都有缺省值我们的编译器不知道使用哪一个缺省值。 4.函数重载 1.函数重载是函数的一种特殊情况C允许在同一作用域中声明几个功能类似的同名函数这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同常用来处理实现功能类似数据类型不同的问题。 1.参数个数 2.类型 3.类型顺序 4.总结如果存在一种情况 事情A单独出现必须去做。 事情B单独出现必须去做。 事情A和B同时出现怎么办编译器面对这样的情况不知道怎么办的那就报错 A:妈妈掉水里了 B爸爸掉水里了 5.为什么出现函数重载编译链接的原理 为什么C支持函数重载但是C语言不支持函数重载呢 定义Func.cpp 声明Func.h 主函数text2.cpp
//Func.cpp
int add(double b, int c)
{return b c;
}int add(int b, double c)
{return b c;
}
//Func.h
#includeiostreamint add(double b, int c);int add(int b, double c);//text2
#includeFunc.husing namespace std;int main()
{//1.参数不同cout add(2.2, 3) endl;cout add(2, 3.3) endl;return 0;
}这里我们通过linux进行预编译编译汇编链接整个过程 1.预编译预处理 1.头文件的展开宏替换条件编译去掉注释。 生成通过预编译生成func.i test2.i文件 2.编译 2.编译进行语法分析词法分析语意分析符号汇总。 生成通过编译生成汇编代码Func.s text2.s 通过vim观察一下汇编代码我们看一看两个函数的地址名称 关于linux下的函数定义的汇编代码通过什么方法命名的呢 _Z (函数名字符个数) 函数名称参数类型的首字母 通过观察下面两个函数名称我们就可以看出来 通过vs上的反汇编我们可以观察到两个函数定义call的地址是不相同的 在vs下定义相同函数名称的函数重载的方法比较linux下的是windows下是通过特殊符号对应一个类型进行的函数名称的汇编定义 3.汇编 在linux下汇编后生成的二进制文件是是以.o结尾的文件在linux下生成的是以.obj 为后缀的二进制文件。 4.链接 链接机器会把各种.o文件和并对文件需要的库进行链接生成可执行的二进制文件 .out 如果我们的函数没有定义在func.cpp中那么到链接的时候会显示链接错误说明链接错误是发生在链接的过程中。这个时候我们的代码已经生成了二进制的机器码了。但是在链接的过程中找不到函数的定义了 6.引用
1.基本概念 引用不是新定义一个变量而是给已存在变量取了一个别名编译器不会为引用变量开辟内存空间它和它引用的变量共用同一块内存空间。 1-1关于函数的引用 1-2引用用的特殊 1.引用必须要初始化 2.一个变量可以被多次引用 3.一个引用只能被初始化一次之后如果ab(a已经引用初始化过了b对a是赋值操作) 1-3常引用 1.常引用常表示的是常变量。 2.给一个常量取别名 2-1访问打印 或者 进行改变常量是不可以改变的 图1 从图1到图2是一种权限的缩小原来的引用可以干两个事情 1.通过引用改变–引用的变量的值。2。获取引用变量的值进行打印 3.图二中的引用只能做获取引用变量的值进行打印 图2
图三
图四
图五
图6
图7 图8 总结我们观察上面的两个图片我们会发现引用和指针在汇编实现的时候是相同的但是题目有不同的作用 1.在语法上r是ch的别名改变r就是改变ch 2.但是在底层r是开辟了一个4字节空间用来保存地址 2.常规用法
1.作为函数参数 swap函数用来交换数值 2.作为函数返回值 如何保存函数返回值 1.函数返回值比较小的时候就用一个寄存器去保存函数返回值 2.函数返回值比较大的时候在main和函数栈帧空间中开辟一个位置保存这个返回值。 3ret的值取绝于函数栈帧销毁之后是否清理空清理的化就是随机值不清理就是上面的情况但是范围一个不属于当前代码的空间是比较危险。 怎么样引用才可以作为函数返回值呢 1.这个变量在函数栈帧销毁的时候它不会被销毁 1-1static静态变量存放在静态区 1-2开辟在堆区的变量存放在堆区 3.特殊用法 1.我们在模拟实现单链表的时候因为进行开始的头节点的改变和头插都需要改变头节点而传了一个二级指针的操作 1.解决方法一二级指针 我们通过二级指针的方法就可以直接改变我们头节点的地址 2.解决方法二引用 通过上面的知识我们知道int是可以有别名的int*有别人名的。当然结构体类型有别名的。结构体指针类型有别名。 4.总结 1.引用在语法上就是另一个变量的别名指针是存储了另一个变量的地址。 2.引用必须初始化指针无所谓初始化。 3.引用初始化是一种传址后面的赋值都是一种改变变量数值的操作。 4.引用初始化一个变量之后就不可以在引用其他变量然鹅指针可以在任何时候指向另一个同类型的实体 5.sizeof 中的含义不同因为我引用是你的别名应该有你的所有属性所以sizeof大小应该满足引用类型的字节大小指针类型是地址地址在32为平台下就是4字节 6.引用 就是引用的实际个体数值指针就是向后移动应该类型的字节大小。 7.有多级指针但是没有多级引用。 8.访问实体的方式不同指针靠解引用引用靠编译器自己处理。 9.引用比指针使用起来更加安全这个安全是相对的内容。 7.内联函数 关于宏 优点 1.不需要开辟函数栈帧节省空间。 2.宏的效率会快一些。 缺点 1.容易出现优先级的问题。 2.不可以调试 3.宏的内容过多会产生空间的浪费。 4.宏是没有类型检查的。 1.概念 一个inline加在一个函数的前面就让这个函数获得了宏的所有优点但是并没有宏的一些缺陷优先级函数调试类型检查内联提高了函数的运行效率 1.因为inline是一个对代码的优化默认不会打开这个代码优化。 打开之后的结果 2.inline的优缺点 1.inline是具有不错的优点但是inline不是一个非常好的处理方法。 2.inline本质上是一个用空间换时间的做法如果编译器把函数当作内联函数处理。那么在代码进行预编译的时候我们就进行替换好处节省了调用函数栈帧的时间消耗缺点导致目标文件变大。 3.inline对于编译器只是一个建议不同的的编译器对于inline的实现的机制可能不同一般函数比较小不是递归并且频繁调用的函数可以去用inline修饰。 4.inline不建议定义和声明分开会导致连接错误因为inline函数需要展开但是如果定义和声明分离展开是没有内容的找不到函数地址链接找不到的。 5.优点 1.有宏的所有优点没有宏的缺点 2.频繁调用一个小函数效率是比较高的 6.缺点 1.内联函数比较大就会大大使用了目标空间。 2.使用一个较大函数我们内联就都会去编译函数代码对于正常的函数调用只会编译一条函数代码。