1.C++基础回顾
有一定的C语言基础,下面是一些基础回顾
-
while() 重在条件判断
for( ; ; )重在计数 -
if 侧重于判断区间
case侧重判断单个数字或字符,如果case中没有break,那么将会向下执行
数组中数组名的作用
- 查看二维数组所占内存空间
#include <iostream>
#include <utility>
using namespace std;
int main() {
int arr[40];
cout << sizeof(arr) << endl;
return 0;
}
- 获取二维数组首地址
cout << arr << endl;
cout << &arr[0] << endl;
函数的默认参数
int func(int a, int b = 10, int c = 10) {
return a + b + c;
}
//1. 如果某个位置参数有默认值,那么从这个位置往后,从左向右,必须都要有默认值
//2. 如果函数声明有默认值,函数实现的时候就不能有默认参数
int func2(int a = 10, int b = 10);
int func2(int a, int b) {
return a + b;
}
int main() {
cout << "ret = " << func(20, 20) << endl;
cout << "ret = " << func(100) << endl;
cout << "func2 = " << func2() << endl;
return 0;
}
const修饰指针
看const右侧修饰的是什么,如果是指针 那就是常量指针,意思是指针指向的值不可以改,但是指针指向可以改; 如果const右侧修饰的是一个常量,那就是指针常量,意思是指针指向不可以改,但是指针指向的值可以改。后面也会遇到
int a = 100;
int b = 200;
//常量指针
const int * p1 = &a;
// *p1 = 20; 报错
p1 = &b;
cout << p1 << endl;
cout << &b << endl;
//指针常量
int * const p2 = &a;
*p2 = 30;
// p2 = &b; 报错
cout << *p2 << endl;
cout << a << endl;
2.C++中的内存分配
- 内存分区的四个区域
//全局变量
int g_a = 10;
int g_b = 10;
//全局常量
const int c_g_a = 10;
const int c_g_b = 10;
int main() {
//局部变量
int a = 10;
int b = 10;
//打印地址
cout << "局部变量a地址为: " << (int)&a << endl;
cout << "局部变量b地址为: " << (int)&b << endl;
cout << "全局变量g_a地址为: " << (int)&g_a << endl;
cout << "全局变量g_b地址为: " << (int)&g_b << endl;
cout << "字符串常量地址为: " << (int)&"hello world" << endl;
cout << "字符串常量地址为: " << (int)&"hello world1" << endl;
cout << "全局常量c_g_a地址为: " << (int)&c_g_a << endl;
cout << "全局常量c_g_b地址为: " << (int)&c_g_b << endl;
//静态变量
static int s_a = 10;
static int s_b = 10;
cout << "静态变量s_a地址为: " << (int)&s_a << endl;
cout << "静态变量s_b地址为: " << (int)&s_b << endl;
const int c_l_a = 10;
const int c_l_b = 10;
cout << "局部常量c_l_a地址为: " << (int)&c_l_a << endl;
cout << "局部常量c_l_b地址为: " << (int)&c_l_b << endl;
return 0;
}
不要返回局部变量的地址,栈区开辟的数据由编译器自动释放
int * func()
{
int a = 10;
return &a;
}
int main() {
int *p = func();
cout << *p << endl;
cout << *p << endl;
return 0;
}
全局区包括全局变量、静态变量和静态常量。同时该区域还包括字符串常量和其他常量。
该区域的数据在程序结束后有操作系统释放。
如果一定要在函数中返回局部变量的地址,那可以利用new在堆区开辟内存,堆区开辟的内存由程序员分配释放,若程序员不释放,程序结束时由操作系统回收。
int* func()
{
int* a = new int(10);
return a;
}
int main() {
int *p = func();
cout << *p << endl;
cout << *p << endl;
//利用delete释放堆区数据
delete p;
//cout << *p << endl; //报错,释放的空间不可访问
return 0;
}
在堆区开辟数组,注意和变量不同的是在释放的时候需要在delete后面加上[]
//堆区开辟数组
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 后加 []
delete[] arr;
return 0;
}
3.C++中的引用
函数做引用的参数
函数传参时,可以利用引用的技术让形参修饰实参,其效果和指针一样。
简单理解代码就是给例子中的变量a起了一个别名,但在形参中起的别名和main函数中的别名是一样的,其优点是可以简化指针修改实参。
//1. 值传递
void mySwap01(int a, int b) {
int temp = a;
a = b;
b = temp;
}
//2. 地址传递
void mySwap02(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
//3. 引用传递
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:" << a << " b:" << b << endl;
mySwap02(&a, &b);
cout << "a:" << a << " b:" << b << endl;
mySwap03(a, b);
cout << "a:" << a << " b:" << b << endl;
return 0;
}
引用做函数的返回值
一定注意,不要返回局部变量引用
如果函数的返回值是引用,这个函数调用可以作为左值。
//返回局部变量引用
int& test01() {
int a = 10; //局部变量
return a;
}
//返回静态变量引用
int& test02() {
static int a = 20;
return a;
}
int main() {
//不能返回局部变量的引用
int& ref = test01();
cout << "ref = " << ref << endl;
cout << "ref = " << ref << endl;
//如果函数做左值,那么必须返回引用
int& ref2 = test02();
cout << "ref2 = " << ref2 << endl;
cout << "ref2 = " << ref2 << endl;
test02() = 1000;
//因为函数的返回值是引用类型,所以函数可以作为左值;
//同时 ref2是函数的一个别名,所以当函数的值改变时,引用的别名也会改变。
cout << "ref2 = " << ref2 << endl;
cout << "ref2 = " << ref2 << endl;
return 0;
}
引用的本质
引用的本质就是在C++内部实现了一个指针常量。
意思就是指针的指向是不可以修改的,但是指针所指向的值是可以修改的。
int* const ref == &a; //两者是等价的
下面这段代码能正确的说出 那就表明明白了。
#include <iostream>
using namespace std;
//发现是引用,转换为 int* const ref = &a;
void func(int& ref){
cout << "ref:" << ref << endl;
ref = 100; // ref是引用,转换为*ref = 100
}
int main(){
int a = 10;
cout << "a:" << a << endl;
//自动转换为 int* const ref = &a; 指针常量是指针指向不可改,也说明为什么引用不可更改
int& ref = a;
ref = 20; //内部发现ref是引用,自动帮我们转换为: *ref = 20;
cout << "a:" << a << endl;
cout << "ref:" << ref << endl;
func(a);
cout << "ref:" << ref << endl;
cout << "ref的地址:" << &ref << endl;
cout << "a的地址:" << &a << endl;
return 0;
}
4.C++中的模板
目前只是简单的学习了下,方便后面在STL能够看懂并使用系统提供的模板
函数的模板使用的关键字为template
函数模板的语法
T为通用的数据类型,名称可以替换,通常为大写字母
template<typename T>
使用函数的模板有两种方式:自动类型推导(就是不指定参数的类型,让编译器自己推) 第二种是显示指定类型
模板的目的是为了提高函数的复用性,将类型参数化
template<typename T>
void mySwap( T &a, T &b) {
T temp = a;
a = b;
b = temp;
}
void test01() {
int a = 10;
int b = 20;
//1.有参数时
// 第一种:自动类型推导
mySwap(a, b);
// 第二种: 显示指定类型
mySwap<int>(a, b);
cout << "a = " << a << endl;
cout << "b = " << b << endl;
}
// 2、无参数时 模板必须要确定出T的数据类型,才可以使用
template<class T>
void func()
{
cout << "func 调用" << endl;
}
void test02()
{
//func(); //错误,模板不能独立使用,必须确定出T的类型
func<int>(); //利用显示指定类型的方式,给T一个类型,才可以使用该模板
}
int main() {
test01();
test02();
return 0;
}
当模板无传入的形参时,模板不能独立使用,必须确定出T的类型,需要显示指定类型的方式,给T一个类型,才可以使用该模板。
所以使用模板时必须确定出通用数据类型T,并且能够推导出一致的类型。