赞
踩
在函数声明或者定义的时候,给定参数默认值,如果实参传递时候,不给该形参传值,则会按照默认值传参
函数参数的默认值是在编译期生成指令的时候,直接生成入参指令。
函数的默认值参数需要从右往左依次赋值,不能跳过。
函数的值参数在同一作用域只能赋值一次,不能重复赋值。
因为函数参数的默认值是在编译期带入的,所以函数的参数的默认值只在本文件生效。
在调用内联函数时,该函数会直接在调用点展开(在编译期展开指令)。
作用域只在本文件。
正常函数调用:
1.传参 2. 将下一行指令地址入栈 3.将ebp 寄存器入栈,esp ebp 偏移 ——开辟栈帧 4.执行函数体 5.返回值 6.栈帧回退 7.恢复现场 8.参数清除
在debug版本下,内联函数和正常函数调用方式一致。
在realse版本下,在调用内联函数时,该函数会在调用点展开。
递归函数一定不能作为内联函数。(由于内联在编译期展开,编译期无法获取变量的值,而递归函数的终止条件一定需要有变量参与,所以,递归函数不可能被处理成内联函数)
inline 只是对系统的建议(做不做是系统的事),建议将其函数处理为内联函数。
符号:
所有的数据都会生成符号
指令中只有函数名会生成符号
符号:
1.全局符号 global 符号(所有的文件只要引用声明就可以使用)
2.局部符号 local 符号(只有本文件可以用)
inline 产生的符号是 local 符号,所以只能在本文件下使用。
函数名相同,参数列表不同
c 语言函数编译生成函数符号 ,依赖函数名
c++中函数编译生成的函数符号 , 依赖函数名+参数列表
- bool compare(int a,int b)//c语言中生成的符号大致为 _compare
- {
- return a>b;
- }
- bool compare(char a,char b)//c++中生成的符号大致为_compare_char_char
- {
- return a>b;
- }
类型的自动转换
普通函数
有类型安全校验(参数列表需要类型的都需要)
可以调试
会生成global 符号
静态函数
有类型安全校验
可以调试
会生成 local 符号
宏函数(替换)
没有类型安全校验
不可以调试
不生成符号
内联函数
有类型安全校验
可以调试(在debug 内联函数和静态函数表现一致(不会展开),在 release 版本下和宏函数表现一致)
在debug版本会生成local 符号,在release 版本不生成符号
- extern "C"
- {
- void fun_c(int a,int b);//将括号中的按照c语言标准编译
- }
- #include<iostream>//c++
- using namespace std;
- extern "C"
- {
- void fun(int a, int b)
- {
- cout << "fun()" << endl;
- }
- }
但是若没有c++源代码,这种方法就不可行
自己写一个.cpp 文件
- void fun(int a, int b);//想要调用的c++函数的声明
- extern "C"//括号中的代码产生c语言链接
- {
- void fun_tmp(int a, int b)//借助第三方函数,此函数的返回值,参数列表应与想调用的函数相同
- {
- return fun(a, b);//return 想调用的函数
- }
- }
在c中调用自己所写的函数
- #include<stdio.h>
- void fun_tmp(int a, int b);//通过调用自己所写函数,来达到调用所需函数的目的
- int main()
- {
- fun_tmp(10, 20);
- return 0;
- }
c++中三者一样
c语言中,数组名就是地址。
指针存放地址。(联系)
指针是个变量,地址是常量。(区别)
指针有类型。
-
- #include<iostream>
- using namespace std;
- int main()
- {
- int a = 10;
- int b = 20;
- b = a;
- b = 10;
- }
在C++中支持三种域:局部域、名字空间域和类域。
名字空间域是随标准C++而引入的。它相当于一个更加灵活的文件域(全局域),可以用花括号把文件的一部分括起来,并以关键字namespace开头给它起一个名字:
namespace将类型名,重命名放在一个空间之中,对外封闭。可以防止命名冲突
直接使用会报错。
若想使用,可以using namespace,整个命名空间里的东西都可以使用
若想只使用其中的一个,可以using Type::INT; 只使用命名空间Type中的INT,其他就不可以使用
花括号括起来的部分称声明块。声明块中可以包括:类、变量(带有初始化)、函数(带有定义)等。最外层的名字空间域称为全局名字空间域(global namespace scope),即文件域。
名字空间域的引入,主要是为了解决全局名字空间污染(global namespace pollution)问题,即防止程序中的全局实体名与其他程序中的全局实体名,命名冲突。
-
- //普通的命名空间
- namespace zyt
- {
- int a_max = 10;
- int g_min = 0;
- int my_add(int a, int b) { return a + b; };
- }
- //名字空间域可分层嵌套,同样有分层屏蔽作用
- namespace primer
- {
- double pi = 3.1415926;
- double my_add(double a, double b) { return a + b; }
- namespace Matrix
- {
- char my_max(char a, char b) { return a > b ? a : b; }
- }
-
- }
- //同一个工程中允许存在多个相同名称的命名空间
- //便一去最后会合成一个命名空间
- namespace zyt
- {
- float pi = 3.14;
- int my_sub(int a, int b)
- {
- g_min = a - b;
- return g_min;
- }
- }
一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中。
- int main()
- {
- int a = zyt::my_add(12, 23);//::作用域限定符
- printf("%lf\n", primer::pi);
- printf("%lf\n", zyt::pi);
- primer::Matrix::my_max('a','b');
- return 0;
- }
使用using声明可只写一次限定修饰名。using声明以关键字using开头,后面是被限定修饰的名字空间成员名:
- using zyt::pi;
- using primer::Matrix::my_max;
- //名字空间类成员matrix的using声明
- // 以后在程序中使用matrix时,就可以直接使用该成员名,而不必使用限定修饰名
- int main()
- {
- printf("%lf\n", primer::pi);
- printf("%lf\n", pi);
- my_max('a', 'b');
使用using指示符可以一次性地使名字空间中所有成员都可以直接被使用,比using声明方便。using指示符;以关键字using开头,后面是关键字namespace,然后是名字空间名。
using namespace名字空间名;
- using namespace zyt;
- int main()
- {
- printf("%lf\n", primer::pi);
- printf("%lf\n", pi);//zyt
- my_add(12,23);
- return 0;
- }
- //A.h
- namespace zyt
- {
- int my_add(int, int);
- int my_sub(int, int);
- }
- //A.cpp
- #include"A.h"
- namespace zyt
- {
- int my_add(int a, int b)
- {
- return a + b;
- }
- int my_sub(int a, int b)
- {
- return a - b;
- }
- }
使用using指示符
标准C++库中的所有组件都是在一个被称为std的名字空间中声明和定义的。在采用标准C++的平台上使用标准C++库中的组件,只要写一个using指示符:
using namespace std;
就可以直接使用标准C++库中的所有成员。这是很方便的。
一维数组 二维数组
- //给一个变量申请一个空间
- int *p=(int *)malloc(sizeof(int));
- free (p);
- //一维数组的申请
- int* p1 = (int*)malloc(10 * sizeof(int));
- //一维数组的释放
- free(p1);
- //二维数组的申请arr[5][10]
- int** p2 = (int **)malloc(5 * sizeof(int*));
- for (int i = 0; i < 5; i++)
- {
- p2[i] =(int *) malloc(sizeof(int) * 10);
- }
- //二维数组的释放,先释放里层,再释放外层
- for (int i = 0; i < 5; i++)
- {
- free(p2[i]);
- }
- free(p2);
- //给变量申请一个空间
- int* q = new int(10);//申请一个空间,并给q赋值为10
- int* q = new int();//申请一个空间,并给q赋值为默认值,0
- int* q = new int;//申请一个空间,并给q赋值为随机值
- //释放
- delete q;
- //动态开辟一个10个元素大小的一维数组空间
- int* q1 = new int[10];
- //释放
- delete[]q1;//释放数组要加上[],代表变量是一个数组
- //二维数组的申请
- int** q2 = new int* [5];
- for (int i = 0; i < 5; i++)
- {
- q2[i] = new int[10];
- }
- //释放
- for (int i = 0; i < 5; i++)
- {
- delete[]q2[i];
- }
- delete[]q2;
c语言中(.c),const 修饰的变量为常变量
c++中,const 定义的为常量,常量会在编译器将常量所在地方全部替换为该常量的值
const定义的为常量,是用const修饰,初始值为常量才可被称作常量
- #include<iostream>
- using namespace std;
- int main()
- {
- const int a = 10;
- int* p = (int *)&a;//强转
- *p = 20;
- cout << "a= " << a << endl;//10
- cout << "*p= " << *p << endl;//20
-
- }
若被const修饰,初始值为变量,则为常变量
也就是说,如果使用变量初始化常量,常量会退化为常变量
- int c = 10;
- const int a = c;//如果使用变量初始化常量,常量会退化为常变量
- int* p = (int *)&a;//强转
- *p = 20;
- cout << "a= " << a << endl;//20
- cout << "*p= " << *p << endl;//20
const修饰的量必须初始化,不初始化,后期就无法对其赋值。
一个与指针密切相关的特殊数据类型。
底层是一个指针。所有使用到该引用的地方,在编译期会自动替换为底层指针的解引用。
引用是一个变量的别名,定义引用类型变量,实质上是给一个已定义的变量起一个别名。
引用类型变量与其相关的变量使用同一个内存空间。
定义引用类型变量的一般格式为:
类型符 & 引用名=变量名(& 为引用声明符)
如: int a=3;
int &b= a;
注意区分:引用声明运算符和取地址运算符
int *b= &a;
为什么引用必须初始化:所有使用到该引用的地方,在编译期会自动替换为底层指针的解引用。不初始化,后面就没机会了。
为什么一经引用就无法改变引用的目标:所有使用到该引用的地方,在编译期会自动替换为底层指针的解引用。
int &f ,引用底层是一个指针,但e是一个常量,引用一个常量,将常量的地址泄露给非常量的指针,定义一个常引用。
10会产生一个临时量,临时量都具有常属性
临时量的生命周期只在当前指令。
如果临时量被引用,他的生命周期就会扩大到和引用一致。
- #include<iostream>
- using namespace std;
- void swap1(int* m, int* n)//指针
- {
- int tmp;
- tmp = *m;
- *m = *n;
- *n = tmp;
- }
- void swap2(int &m, int &n)//引用
- {
- int tmp;
- tmp = m;
- m = n;
- n = tmp;
- }
- int main()
- {
- int a = 10;
- int b = 20;
- swap1(&a, &b);//指针
- cout << a << b << endl;//20 10
- swap2(a, b);//引用
- cout << a << b << endl;//10 20
-
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。