-
Notifications
You must be signed in to change notification settings - Fork 0
/
day 09
304 lines (289 loc) · 8.63 KB
/
day 09
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
//本阶段主要针对C++面向对象编程技术做详细讲解,探讨C++中的核心和精髓
//内存的分区模型
// C++程序在执行时,将内存大方向划分4个区域
// 代码区:存放函数体的二进制代码,由操作系统进行管理
// 全局区:存放全局变量和静态变量以及常量
// 栈区:由编译器自动分配释放,存放函数的参数值就,局部变量等
// 堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
//
// 内存的四区兄弟
// 不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程
//
//程序运行前
// 在程序编译后,生成了exe可执行程序,未执行该程序前分为两个区域
// 代码区
// 存放cpu执行的机器指令。
// 代码区时共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可
// 代码区时只读的,使其只读的原因是防止程序意外地修改了它的指令
// 全局区
// 全局变量和静态变量存放在此
// 全局区还包含了常量区,字符串常量和其他常量也存放在此
// 该区域的数据在程序结束后由操作系统释放
//
//在不在全局区的特点
// 总结:不在全局区是 - 局部变量、const修饰的局部变量(局部常量)。全局区是 - 全局变量、静态变量(static修饰的)、常量(字符串常量、const修饰的全局变量)
// 结论:C++中在程序运行前分为全局区和代码区,代码区特点是共享和只读,全局区中存放全局变量、静态变量、常量,常量区中存放const修饰的全局常量和字符串常量
////全局变量
//int A = 10;
//int B = 10;
////全局常量
//const int C = 10;
//const int D = 10;
//int main()
//{
// //全局区
// //全局变量,静态变量,常量,因为是在同一区域中所以他们的地址挨的近,不会太远
//
// //局部变量
// int a = 10;
// int b = 10;
// cout << "局部变量a地址:" << (int)&a << endl;
// cout << "局部变量b地址:" << (int)&b << endl;
// cout << "全局变量A地址:" << (int)&A << endl;
// cout << "全局变量B地址:" << (int)&B << endl;
//
// //静态变量 在普通变量前加上static,就属于静态变量
// static int s_a = 10;
// static int s_b = 10;
// cout << "静态变量s_a地址:" << (int)&s_a << endl;
// cout << "静态变量s_b地址:" << (int)&s_b << endl;
//
// //常量 - 分别为
// //字符串常量
// cout << "字符串常量的地址为:" << (int)&"hello world" << endl;
// //const修饰的变量
// //const修饰的全局变量
// cout << "全局常量C地址:" << (int)&C << endl;
// cout << "全局常量C地址:" << (int)&D << endl;
// //const修饰的局部变量
// const int c_l_a = 10;//c- const(关键字) g-global(全局) l-local(局部)
// const int c_l_b = 10;
// cout << "局部常量c_l_a地址:" << (int)&c_l_a << endl;
// cout << "局部常量c_l_b地址:" << (int)&c_l_b << endl;
//
//
// system("pause");
// return 0;
//}
//程序运行后
//栈区
// 由编译器自动分配释放,存放函数的参数值,局部变量等
// 注意事项:不要返回局部变量的地址,栈区开辟的数据由编译器自动释放
//
//栈区数据的注意事项 - 不要返回局部变量的地址
//栈区的数据由编译器管理开辟和释放
//int* func(int i)//型参数据也会放在栈区
//{
// i = 100;
// int a = 10;//局部变量 存放在栈区,栈区的数据在函数执行完之后自动释放
// return &a;//返回局部变量的地址
//}
//int main()
//{
// //接收返回值
// int* p = func(1);//指向一块被释放的空间,这已经是一个非法操作了,野指针了
// cout << *p << endl;//第一次可以打印正确的数字,是因为编译器执行一次保留
// cout << *p << endl;//第二次这个数据就不在保留了
//
// system("pause");
// return 0;
//}
//堆区
//由程序员分配释放,若不是放,程序结束时由操作系统回收
//在C++中主要利用new在堆区开辟内存
//总结:堆区数据由程序员管理开辟和释放,堆区数据利用new关键字进行开辟内存
//在堆区开辟数据
//int* func()
//{
// //利用new关键字,可以将数据开辟到堆区
// //指针 本质也是局部变量,放在栈上,指针保存的数据是放在堆区
// int*p = new int(10);
// return p;
//}
//int main()
//{
// //在堆区开辟数据
// int* p = func();
// cout << *p << endl;
//
// system("pause");
// return 0;
//}
//new操作符
//C++中利用new操作符在堆区开辟数据
//堆区开辟的数据,由程序员手动开辟,手动释放,释放利用delete
//语法 - new 数据类型(初始化多少(没有也行))
//利用new创建的数据,会返回该数据对应的类型指针
////new的基本语法
//int* func()
//{
// //在堆区创建整型数组
// //new返回的是 该数据类型的地址(就是指针啦)
// int*p = new int(10);
// return p;
//}
//void test01()
//{
// int* p = func();
// cout << *p << endl;
// //堆区的数据 由程序员管理开辟、释放
// //如果想释放堆区,利用关键字delete
// delete p;
// cout << *p << endl;//内存已经被释放了,再次访问就是非法操作,会报错
// //这个和C的释放有差别,这个不需要指向空指针。c是指向的地址被释放,才需要释放完地址的指针指向空。c++不需要结合上面的大概猜测C++把c的两步骤合起来了
//}
////开辟一个数组的空间
//void test02()
//{
// int* arr = new int[10];
//
// for (int i = 0; i < 10; i++)
// {
// arr[i] = i + 1;
// }
// for (int i = 0; i < 10; i++)
// {
// cout << arr[i] << endl;
// }
// //释放堆区数组
// //释放数组的时候,要加上[]才可以
// delete[] arr;
//}
////在堆区利用new开辟数组
//
//int main()
//{
// //test01();
// test02();
// system("pause");
// return 0;
//}
//引用 - 差不多和指针常量类似都是指向同一块地址
//引用的基本使用
// 作用:给变量起名
// 语法:数据类型 &别名 = 原名
//
//int main()
//{
// //引用基本语法
// //数据类型 &别名 = 原名
// int a = 10;
// int& b = a;
// cout << a << endl;
// cout << b << endl;
//
// b = 20;
// cout << a << endl;
// cout << b << endl;
// system("pause");
// return 0;
//}
//引用的注意事项
//引用必须要初始化
//引用在初始化后,不可以再改变了
//总结:引用必须要初始化且不可修改
//int main()
//{
// int a = 10;
// int c = 20;
// //引用在初始化后,不可以再改变了
// //int& b;//err错误的必须要初始化
//
// //引用一旦初始化后,就不可以更改了
// int& b = a;
// b = c;//这个是赋值,而不是更改引用
// //int& b = c;//err错误,一旦初始化就不能改了
// cout << a << endl;
// cout << b << endl;
// cout << c << endl;
//
// system("pause");
// return 0;
//}
//引用做函数参数
//函数传参时,可以利用引用的奇数让型参修饰实参
// 优点:可以简化指针修改实参
//总结:通过引用参数产生的效果同按地址传递是一样的,引用的语法更清晰简单
////交换函数
////址传递
//void mySwap01(int a,int b)
//{
// int temp = a;
// a = b;
// b = temp;
//
//}
////地址传递
//void mySwap02(int* a, int* b)
//{
// int temp = *a;
// *a = *b;
// *b = temp;
//}
////引用传递
//void mySwap03(int& a, int& b)
//{
// int temp = a;
// a = b;
// b = temp;
//}
//
//int main()
//{
// int a = 10;
// int b = 20;
// mySwap01(a, b);
// cout << a << endl;
// cout << b << endl;
// mySwap02(&a, &b);
// cout << a << endl;
// cout << b << endl;
// mySwap03(a, b);//别名也可以和原名一样
// cout << a << endl;
// cout << b << endl;
// system("pause");
// return 0;
//}
//引用做返回值
// 引用是可以作为函数的返回值存在的
// 注意:不要返回局部有变量引用
// 用法 - 函数调用作为左值
//注:不要返回局部变量的返回值
int& test01()
{
int a = 10;//栈区
return a;
}
//函数的调用可以作为左值
int& test02()
{
static int a = 10;//静态变量,放在全局区,程序运行完后释放
return a;
}
int main()
{
//引用做函数的返回值
int& ref1 = test01();
cout << ref1 << endl;//第一次对,编译器做一次保留
cout << ref1 << endl;//第二次错误,因为a的内存已被销毁释放
int& ref2 = test02();//引用可以指向自己的引用。
cout << ref2 << endl;
test02() = 100;//返回的是a的引用,可以作为左值
cout << ref2 << endl;//
system("pause");
return 0;
}
//int main()
//{
// int a = 10;
// int& b = a;
// int& c = b;
// cout << c << endl;
// cout << c << endl;
//
// system("pause");
// return 0;
//}