网站进入百度沙盒,公司发布网站需要备案,做阿里巴巴的网站的费用吗,怎么做QQ信任网站1#xff0c;类型分区模型
c程序在执行中#xff0c;将内存大方向划分为4个区域
1#xff0c;代码区#xff1a;存放函数体的二进制代码#xff0c;由操作系统进行管理的
2#xff0c;全局区#xff1a;存放全局变量和静态变量以及常量
3#xff0c;栈区#xff1…1类型分区模型
c程序在执行中将内存大方向划分为4个区域
1代码区存放函数体的二进制代码由操作系统进行管理的
2全局区存放全局变量和静态变量以及常量
3栈区由编译器自动分配释放存放函数的参数值局部变量等
4堆区由程序员分配和释放若程序员不释放程序结束时由操作系统回收
内存四区的意义
不同区域存放的数据赋予不同的声明周期给我们更大的灵活编程
1.1 程序运行前
在程序编译后生成exe可执行程序未执行程序前分两个区域
代码区
存放CPU执行的机器指令
代码区是共享的共享的目的是对于频繁被执行的程序只需要在内存中有一份代码即可
代码区是只读的使其只读的原因是防止程序意外地修改了它的指令
全局区
全局变量和静态变量存放于此
全局区还包含了常量区字符串常量和其他常量也存放于此
该区域的数据在程序结束后由操作系统操作
代码展示
#includeiostream
using namespace std;//全局变量
int g_a 10;
int g_b 10;int main()
{//全局区//全局变量静态变量常量//创建普通局部变量int a 10;int b 10;cout 局部变量a的地址: a endl;cout 局部变量b的地址: b endl;cout endl;cout 全局变量g_a的地址: g_a endl;cout 全局变量g_b的地址: g_b endl;cout endl;//静态变量 在普通变量前加static属于静态变量static int s_a 10;static int s_b 10;cout 静态变量s_a的地址: s_a endl;cout 静态变量s_b的地址: s_b endl;cout endl;//常量//字符串常量cout 字符串常量的地址为 hello world endl;cout endl;//const修饰的变量//const修饰的全局变量const int c_g_a 10;const int c_g_b 10;cout 全局常量 c_g_a的地址: c_g_a endl;cout 全局常量 c_g_b的地址: c_g_b endl;cout endl;//const修饰的局部变量const int c_l_a 10;const int c_l_b 10;cout 全局常量 c_g_a的地址: c_l_a endl;cout 全局常量 c_g_b的地址: c_l_b endl;cout endl;system(pause);return 0;
}
总结
c中程序运行前分为全局区和代码区
代码区的特点是共享和只读
全局区中存放全局变量静态变量常量
常量区中存放const修饰的全局变量和字符串变量
1.2 程序运行后
栈区由编译器自动分配释放存放函数的参数值局部变量等
注意不要返回局部变量的地址栈区开辟的数据由编译器自动释放
int* func()
{//利用new关键字 可以将数据开辟到堆区//指针本质也是局部变量放在栈区指针保存的数据是放在栈区int* a new int(10);return a;
}
int main()
{//在堆区开辟数据int* p func();cout 第一个 *p endl;//每一次都会保存正确的数据cout 第二个 *p endl;cout 第二个 *p endl;cout 第二个 *p endl;cout 第二个 *p endl;cout 第二个 *p endl;cout 第二个 *p endl;system(pause);return 0;
} 堆区
由程序员分配释放若 程序员不释放程序结束时由操作系统释放
在C中主要利用new在堆区开辟内存
示例
int* func()
{int* a new int(10);return a;
}
int main()
{int* p func();cout 第一个 *p endl;//每一次都会保存正确的数据cout 第二个 *p endl;cout 第二个 *p endl;cout 第二个 *p endl;cout 第二个 *p endl;cout 第二个 *p endl;cout 第二个 *p endl;system(pause);return 0;
}1.3 new操作符
C中利用new操作符在堆区开辟数据
堆区开辟的数据由程序员手动开辟释放利用操作符delete
语法 new 数据类型
利用new创建的数据会返回该数据对应的类型的指针
示例1基本语法
#includeiostream
using namespace std;
//1new的基本语法
int* func()
{//在堆区创建整型数据//new返回是 该数据类型的指针int* a new int(10);return a;
}int main()
{int* p func();cout *p endl;cout *p endl;cout *p endl;//delete p;//堆区的数据 由程序员管理开辟程序员管理释放//如果向释放堆区的数据利用关键字 deletecout *p endl;system(pause);return 0;
} 示例2开辟数组
//2,开辟数组
int main()
{int* arr new int[10];for (int i 0; i 10; i){arr[i] i 100;}for (int i 0; i 10; i){cout arr[i] endl;}delete[] arr;//释放数组 delete后加[]//int* arr new int[10];/*for (int i 0; i 10; i)//释放后不能再次使用{arr[i] i 100;}for (int i 0; i 10; i){cout arr[i] endl;}*/system(pause);return 0;
} 2引用
2.1 引用的基本使用
作用给变量起别名
语法数据类型 别名 原名 示例
#includeiostream
using namespace std;
int main()
{//引用的基本语法//数据类型 别名 原名int a 10;//创建引用int b a;cout a a endl;cout b b endl;b 100;cout a a endl;cout b b endl;system(pause);return 0;
} 2.2 引用的注意事项
引用必须初始化
引用在初始化后不可以改变 int main()
{int a 10;int b 10;//int c;//报错引用必须初始化int ca;//一旦初始化后就不可以更改c b;//这是赋值操作不是更改引用cout a a endl;cout b b endl;cout c c endl;system(pause);return 0;
} 2.3 引用做函数参数
作用函数传参是可以利用引用的技术让形参修饰实参
优点可以简化指针修饰实参
示例
//引用做函数参数
//1值传递
void Swap01(int a,int b)
{int temp a;a b;b temp;cout a a endl;cout b b endl;cout endl;
}
//2地址传递
void Swap02(int* a, int* b)
{int temp *a;*a *b;*b temp;cout a *a endl;cout b *b endl;cout endl;
}//3引用传递
void Swap03(int a, int b)
{int temp a;a b;b temp;cout a a endl;cout b b endl;cout endl;
}
int main()
{Swap01(10,20);//值传递形参不会修饰实参int a 30;int b 40;cout a a endl;cout b b endl;cout endl;Swap02(a,b);//地址传递形参会修饰实参cout a a endl;cout b b endl;cout endl;a 50;b 60;Swap03(a, b);//引用传递形参会修饰实参cout a a endl;cout b b endl;cout endl;system(pause);return 0;
}总结通过引用参数产生的效果同按地址传递是一样的。 引用的语法更清楚
2.4 引用做函数返回值
作用引用时可以作为函数的返回值存在的
注意不要返回局部变量引用
用法函数调用作为左值
示例1
1不要返回局部变量的引用
int test01()
{int a 10; //局部变量放在四区中的栈区return a;
}int main()
{int ref test01();cout ref ref endl;//第一次结果正确是因为编译器做了保留cout ref ref endl;//第二次结果错误是因为a的内存已经释放system(pause);return 0;
} 示例二
//函数的调用可以作为左值
int test02()
{static int a 10; //静态变量存放在全局区全局区上的数据在程序结束后系统释放return a;
}int main()
{int ref test02();cout ref ref endl;cout ref ref endl;test02() 1000;//如果函数的返回值是引用这个函数调用可以作为左值cout ref ref endl;cout ref ref endl;system(pause);return 0;
} 2.5 引用的本质
本质引用的本质在c内部实现是一个指针常量
示例
//引用的本质
//发现是引用转换为int* const ref a;
void func(int ref)
{ref 100;//ref是引用转换为*ref 100;
}int main()
{//自动转化为int* const ref a;指针常量是指针指向不可改也说明为什么引用不可以更改int a 10;int ref a;ref 20;//内部发现ref是引用自动帮我们转换为*ref20;cout a a endl;cout ref ref endl;func(a);cout a a endl;cout ref ref endl;system(pause);return 0;
} 结论C推荐引用技术因为语法方便引用本质是常量指针
2.6 常量引用
作用常量引用主要用来修饰形参防止误操作
在函数形参列表中我们可以加const修饰形参防止形参改变实参
示例
//引用使用的场景通常用来修饰形参
void showValue(const int v)
{//v 10;cout v v endl;
}
int main()
{//int ref 10;//引用本身需要一个合法的内存空间因此这行错误//加入const就可以了编译器做了优化代码int temo 10;const int ref temp;const int ref 10;cout ref ref endl;//ref100;//加入const后不可以修改变量int a 10;//函数中利用常量引用防止误操作修改实参showValue(a);system(pause);return 0;
} 3函数提高
3.1 函数默认参数
在C中函数的形参列表中的形参是由默认值的。
语法返回值类型 函数名 参数 默认值{}
示例1
#includeiostream
using namespace std;
int func1(int a, int b, int c)
{return a b c;
}//如果我们积极传入数据就用自己的数据如果没有那就用默认值
//b未传入数据则使用默认值
int func2(int a, int b 20, int c 30)
{return a b c;
}//都传入了数据那就用自己的数据
int func3(int a, int b, int c)
{return a b c;
}int main()
{cout func1()的值 endl;cout func1(10, 20, 30) endl;cout endl;cout func2()的值 endl;cout func2(10, 30) endl;cout endl;cout func3()的值 endl;cout func1(30, 40, 50) endl;cout endl;system(pause);return 0;示例2 //注意事项
//1如果某个位置已经有了默认参数那么从那个位置往后从左到右必须都有默认值
//int func1(int a10, int b, int c,int d)//错误
//{
// return a b c;
//}//2,如果函数声明由默认参数函数实现就不能由默认参数
//int func2(int a10, int b10);
//声明和实现都能有一个默认参数
int func2(int a10, int b20)
{return a b;
}int main()
{cout func2(10) endl;return 0;
}
3.2函数占位参数
C中函数的形参列表里可以有占位参数用来做占位调用函数时必须填补该位置
语法返回值类型 函数名 函数类型{ }
在现阶段函数的占位参数存在意义不大但是后面的课程中会用到该技术
示例
//函数占位参数占位参数也可以有默认参数
void func(int a, int)
{cout this is func endl;
}
int main()
{func(10, 10);//占位参数必须填补system(pause);}3.3 函数重载
void func()
{cout func的调用 endl;
}void func(int a)
{cout func的调用 endl;
}void func(double a)
{cout func的调用 endl;
}//函数返回值不能作为函数重载条件
//int func(double a,int b)
//{
// cout func(double a,int b) endl;
//}int main()
{//func()func(10);func(3.14);
}
作用函数名可以相同提高复用性
3.3.1函数重载满足条件
1同一个作用域下
2函数名相同
3函数参数类型不同或者个数不同或者顺序不同
注意函数的返回值不可以作为函数重载的条件
void func()
{cout func的调用 endl;
}void func(int a)
{cout func的调用 endl;
}void func(double a)
{cout func的调用 endl;
}//函数返回值不能作为函数重载条件
//int func(double a,int b)
//{
// cout func(double a,int b) endl;
//}int main()
{//func()func(10);func(3.14);
}
3.3.2 函数重载注意事项
1引用作为重载条件
2函数重载碰到函数默认条件
示例
// 函数重载注意事项
//1引用作为重载条件
void func(int a)
{cout func(int a)的调用 endl;
}void func(const int a)
{cout func(int a)的调用 endl;
}
//2函数重载碰到函数默认条件
void func2(int a, int b 10)
{cout func2(int a,int b 10)调用 endl;
}void func2(int a)
{cout func2(int a)调用 endl;
}int main()
{int a 10;//func2(a);//调用无const//func2(10);//调用有const//func2(10);//碰到默认参数产生歧义需要避免system(pause);return 0;
}