小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
一、函数重载
在C++语言中,一个程序里面,如果多个函数的功能相同,但是只要保证参数的个数或者类型不一样,这些函数的名字可以定义成同一个。
为什么C++可以实现函数重载
- C语言中函数的地址只是由函数的名字确定
- C++语言中函数的地址是由函数名和参数共同确定的
#include <iostream>
using namespace std;
void MyAdd(int a, int b)
{
cout << a << " + " << b << " = " << a + b << endl;
}
void MyAdd(float a, float b)
{
cout << a << " + " << b << " = " << a + b << endl;
}
void MyAdd(long a, long b)
{
cout << a << " + " << b << " = " << a + b << endl;
}
void MyAdd(int a, float b)
{
cout << a << " + " << b << " = " << a + b << endl;
}
void MyAdd(int a)
{
cout << "a = " << a << endl;
}
void test1()
{
MyAdd(100, 20);
MyAdd(3.14f, 8.18f);
MyAdd(100, 5.16f);
}
void MyFun(int a = 333, int b = 666, int c = 888)
{
cout << "a = " << a << ", ";
cout << "b = " << b << ", ";
cout << "c = " << c << endl;
}
void MyFun(int a, int b)
{
cout << "a = " << a << ", ";
cout << "b = " << b << endl;
}
void MyFun(int a)
{
cout << "a = " << a << endl;
}
void test2()
{
//当函数重载和函数的默认参数一起使用时,一定要注意会不会出现歧义
//MyFun(100);
//MyFun(100, 200);
MyFun();
}
//注意:返回值不能作为函数重载的条件
#if 0
void MySub(int a, int b)
{
cout << "a - b = " << a - b << endl;
}
int MySub(int a, int b)
{
cout << "a - b = " << a - b << endl;
return a - b;
}
#endif
int main()
{
test2();
return 0;
}
二、引用
2.1 引用的基本使用
#include <iostream>
using namespace std;
void test1()
{
//定义一个变量保存常量100
//当运行到这部分代码时,就会在内存中开辟一块空间来存放100
//此时的a也称之为这块空间的别名
int a = 100;
cout << a << endl;
//将变量a的地址保存在指针变量p中
//保存之后这个指针变量就可以对a变量地址里面的内容进行操作
int *p = &a;
*p = 666;
cout << a << endl;
}
void test2()
{
int a = 100;
//引用:就是对已有的空间重新再起一个别名
//定义一个引用
int &b = a;
cout << "&a = " << &a << endl;
cout << "&b = " << &b << endl;
b = 888;
cout << a << endl;
}
int main()
{
test2();
return 0;
}
2.2 引用的注意事项
1、引用==必须初始化==,他必须是对已有的空间进行去别名
2、引用只能初始化一次意味着初始化之后,引用就不能再作为其他空间的别名, 一旦引用初始化后,与原本的变量没有任何区别只是名字不一样
3、定义引用的时候,&只是一个标识,说明在定义引用,一旦定义完毕,&就表示取一个变量的地址
//引用的注意事项
void test3()
{
//1、引用必须初始化,他必须是对已有的空间进行去别名
//int &b;
int a = 100;
//int *p = &a;
//int &b = *p;
int &b = a;
cout << b << endl;
//2、引用只能初始化一次
//意味着初始化之后,
//引用就不能再作为其他空间的别名
//一旦引用初始化后,与原本的变量没有任何区别只是名字不一样
//int c = 200;
//&b = c;
//3、定义引用的时候,&只是一个标识,说明在定义引用,
//一旦定义完毕,&就表示取一个变量的地址
//int &c = a;
//&c;
}
int main()
{
test3();
//常量也可以引用,但是需要加const
//const int &b = 100;
return 0;
}
2.3 引用的使用
- 复制传参,将实参的值传递给形参,不管形参如何改变值,实参都不会有变化,是因为实参和形参不是同一块空间
- 地址传参,将实参的地址传递给形参,形参如果对地址里面的内容修改,实参的值也会变化,因为是用一块地址
- 引用传参,将实参定义引用,所以现在形参就是实参的别名,意味着就是用一块空间,所以引用修改空间的值,实参一定会变另外引用没有再开辟空间,所以相对而言更加节省空间
📣注意:引用可以作为返回值,这样做一定程度上节省空间并且防止内存泄漏
//引用的使用
//函数的传参方式1:复制传参,将实参的值传递给形参,不管形参如何改变值,
//实参都不会有变化,是因为实参和形参不是同一块空间
void MyChange1(int a, int b)
{
int temp;
temp = a;
a = b;
b = temp;
}
//函数的传参方式2:地址传参,将实参的地址传递给形参,形参如果对地址里面的
//内容修改,实参的值也会变化,因为是用一块地址
void MyChange2(int *a, int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
void MyChange3(int *a, int *b)
{
int m = 888, n = 999;
a = &m;
b = &n;
*a = 111;
*b = 222;
}
//函数的传参方式3:引用传参,将实参定义引用,所以现在形参就是实参的
//别名,意味着就是用一块空间,所以引用修改空间的值,实参一定会变
//另外引用没有再开辟空间,所以相对而言更加节省空间
void MyChange4(int &a, int &b)
{
cout << &a << ", " << &b << endl;
int temp;
temp = a;
a = b;
b = temp;
}
void test4()
{
int m = 100, n = 50;
cout << "交换前:";
cout << "m = " << m << ", ";
cout << "n = " << n << endl;
cout << &m << ", " << &n << endl;
//MyChange1(m, n);
//MyChange2(&m, &n);
//MyChange3(&m, &n);
MyChange4(m, n);
cout << "交换后:";
cout << "m = " << m << ", ";
cout << "n = " << n << endl;
}
//引用可以作为返回值
//这样做一定程度上节省空间并且防止内存泄漏
int &MyFun()
{
static int a = 100;
cout << "&a = " << &a << endl;
return a;
}
void test5()
{
int &b = MyFun();
cout << "b = " << b << endl;
cout << "&b = " << &b << endl;
}
三、C++动态开辟空间
使用malloc在堆区开辟空间,malloc开辟的堆区空间是不会初始化的
使用 calloc在堆区开辟空间,calloc开辟的堆区空间会自动初始化为0
释放空间
- 释放:这块空间我不用了,别人可以使用
- 开辟多少空间就必须释放多少,不能只释放一部分
注意:同一块空间不允许释放两次,否则直接报错退出
空间释放之后,地址还是保存原本的空间,所以既然已经释放了,就不要在用了。
防止野指针的目的就是不要再使用释放后的空间
realloc是在已有的空间基础上增加空间,返回的地址有可能是原本的首地址,也有可能是新地址。
C++中动态开辟空间,使用new
-
new开辟的空间不会自动初始化 -
new支持申请空间的同时初始化 -
如果要释放申请多个指定类型的空间,需要在首地址的前面加[]
-
delete a;
将一个字符串常量的地址赋值给指针变量,如果这样做,就会导致原本堆区空间泄漏,所以绝对不要这样赋值。
#include <iostream>
#include <cstdlib>
#include <string.h>
using namespace std;
//C语言动态开辟空间(堆区开辟空间)
void test1()
{
//使用malloc在堆区开辟空间
//malloc开辟的堆区空间是不会初始化的
int *a = (int *)malloc(4);
cout << "*a = " << *a << endl;
*a = 666;
cout << "*a = " << *a << endl;
//使用 calloc在堆区开辟空间
//calloc开辟的堆区空间会自动初始化为0
int *b = (int *)calloc(1, 4);
cout << "*b = " << *b << endl;
//释放空间
//释放:这块空间我不用了,别人可以使用
//开辟多少空间就必须释放多少,不能只释放一部分
free(a);
free(b);
//注意:同一块空间不允许释放两次,否则直接报错退出
//free(a);
//空间释放之后,地址还是保存原本的空间,
//所以既然已经释放了,就不要在用了
//*a = 999;
//cout << "*a = " << *a << endl;
//防止野指针的目的就是不要再使用释放后的空间
a = NULL;
//realloc是在已有的空间基础上增加空间
//返回的地址有可能是原本的首地址,也有可能是新地址
//realloc()
}
//C++中动态开辟空间,使用new
void test2()
{
//new开辟的空间不会自动初始化
int *a = new int;
cout << "*a = " << *a << endl;
*a = 555;
cout << "*a = " << *a << endl;
//new支持申请空间的同时初始化
int *b = new int(100);
cout << "*b = " << *b << endl;
//申请多个指定类型的空间
int *c = new int[6];
c[0] = 100;
c[1] = 200;
c[5] = 600;
cout << c[0] << ", " << c[1] << ", " << c[5] << endl;
//释放空间
delete a;
delete b;
//如果要释放申请多个指定类型的空间,需要在首地址的前面加[]
delete []c;
char *str = new char[32];
printf("str = %p\n", str);
//将一个字符串常量的地址赋值给指针变量,
//如果这样做,就会导致原本堆区空间泄漏,
//所以绝对不要这样赋值
//str = "hello world";
//printf("str = %p\n", str);
strcpy(str, "hello world");
printf("str = %p\n", str);
cout << str << endl;
delete []str;
}
int main()
{
test2();
return 0;
}