结构体
定义:用户自定义符合数据类型,可以包含不同类型的不同成员。
//声明结构体
struct 结构体类型(自己起名)
{
成员1类型 成员1名称;
。。。
成员N类型 成员N名称;
}
基本用法(类似class)
struct Student {
string name;
int age = 20; //设定默认值
string gender;
};
//结构体的变量声明 可以在前面带上struct关键字(非必须 但推荐写)
struct Student stu;
//对结构体变量赋值
stu = {"sj",11,"male"};
//cout<< stu << endl; 结构体变量是一个整体的包装,无法直接cout输出
cout << stu.name <<endl;
结构体数组
struct Student {
string name;
int age;
string gender;
};
//方式1声明
struct Student stu2[3];
stu2[0] = {"kk",11,"male"};
stu2[1] = {"dd",3,"female"};
stu2[2] = {"ll",4,"male"};
//方式2声明
struct Student stu3[3] = {{"kk",11,"male"},{"dd",3,"female"},{"ll",4,"male"}};
for(Student i:stu2) {
cout << i.name << endl;
}
结构体指针
struct Student stu0 = {"cc",12,"male"};
//创捷结构体指针,指向结构体对象的地址
struct Student * p = &stu0;
//通过结构体指针访问成员
cout << p-> name <<endl;
//自己管理内存空间
struct Student * p7 = new Student {"qq",39,"male"};
delete p7;
结构体指针数组
//方式1
struct Student stu4[3] = {{"kk",11,"male"},{"dd",3,"female"},{"ll",4,"male"}};
struct Student * p1 = stu4;
cout << p1[0].name <<endl;
//方式2 能自己管理内存
struct Student * p9 = new Student[3]{{"kk",11,"male"},{"dd",3,"female"},{"ll",4,"male"}};
cout << p9[0].name <<endl;
delete[] p9;
函数
//语法
返回值类型 函数名称 (参数列表)
{
函数体
。。。
返回值
}
地址传递
void switch_num(int *a,int *b) {
//直接对地址里的内容进行修改,能实现对外部变量进行操作
int temp = *a;
*a = *b;
*b = temp;
}
int main(int argc, char *argv[]) {
int *a = new int(10);
int *b = new int(20);
switch_num(a,b);
cout << *a << endl; //20
cout << *b << endl; //10
delete a;
delete b;
}
函数传入数组
由于数组对象本身只是第一个元素的地址,所以数组传参不区分值传递还是地址传递。本质都是传地址
void arr_test(int a[],int length) //很难通过地址值知道数组长度,所以一般要求把数组长度
//作为参数传入
{
cout<<sizeof(a)<<endl; //指针长度 8字节
//说明传进来的就是指针
for(int i=0 ; i<length ; i++) {
cout<<*(a+i)<<endl;
cout<<a[i]<<endl;
}
}
int main(int argc, char *argv[]) {
int arr[] = {1,2,3,4,5,6,7};
cout<<sizeof(arr)<<endl; //28 7*4字节
arr_test(arr,sizeof(arr)/sizeof(arr[0]));
}
排序练习
void sort(int arr[],int length) {
for(int i=0;i<length;i++) {
int temp;
int min = arr[i];
int min_index = i;
for(int j=i;j<length;j++) {
if(arr[j]<min) {
min = arr[j];
min_index = j;
}
}
temp = arr[i];
arr[i] = arr[min_index];
arr[min_index] = temp;
}
}
int main(int argc, char *argv[]) {
int arr[] = {2,10,4,3,9,6,7};
sort(arr,sizeof(arr)/sizeof(arr[0]));
for(int i:arr) {
cout<<i<<endl;
}
}
引用
引用:是变量的一个别名,它是某个已存在变量的另一个名字
特点:1引用创建后不可更改(更改指向到其他内存区域)
2.因为不可更改,所以引用必须初始化
3.因必须初始化,所以引用不可为空(不可修改)
本质:是一个指针常量
int a = 10;
//数据类型& 引用名 = 被引用变量;
int& b = a; //自动转换为 int* const b = &a 指向地址不可改
cout << "a=" << a <<endl; //10
cout << "b=" << b <<endl; //10
a = 20;
cout << "a=" << a <<endl; //20
cout << "b=" << b <<endl; //20
b = 30; //内部发现b是引用,自动转换为 *b = 30
cout << "a=" << a <<endl; //30
cout << "b=" << b <<endl; //30
//相当于a和b完全等价了
引用传递
void switch_num(int &x,int &y) //这里相当于执行了 int* const x=&a;
//int* const y =&b;
{
int temp = x;
x = y;
y = temp;
}
int main(int argc, char *argv[]) {
int a = 10;
int b = 20;
switch_num(a,b);
cout<<a<<endl; //20
cout<<b<<endl; //10
return 0;
}
常量引用
目的:防止误操作修改引用值
//误操作情况
void show(int& x) {
x = 100; //误操作
cout<< x <<endl;
}
int main(int argc, char *argv[]) {
int a = 10;
show(a);
cout<<a<<endl; //导致变量a的值变为100
return 0;
}
//用const修饰后
void show(const int& x) {
x = 100; //用const修饰后 编译阶段直接报错不通过防止犯错
cout<< x <<endl;
}
返回指针的函数
语法
返回值类型 * 函数名(形参){
函数体
return 指针
}
实例
//错误写法
int * add(int a,int b) {
int sum;
sum = a + b;
return ∑ //这是局部变量,在函数执行完毕后,变量会被销毁,所占内存空间将被释放
//这就是C++的静态内存管理,如果要规避需要动态内存管理(new delete)
}
//正确写法
int * add1(int a,int b) {
int *sum = new int;
*sum = a + b;
return sum;
}
int main() {
int* c = add1(1,2);
delete c; //不删除的话会有提示
}
函数返回数组
其实和返回指针是一样的,因为返回数组本质上就是返回指针
函数重载
函数名可相同
需要满足的条件:同一个作用于下,名称相同,函数参数类型不同,或个数不同,或顺序不同
static
是一个关键字可以修饰 函数和变量
int * add(int a,int b) {
static int sum = a + b; //当用static修饰后,函数完成时不会被回收
return ∑
}
int main() {
int *p = add(1,2);
cout << *p << endl;
return 0;
}
但无限制的使用static会浪费内存
内存分区模型
内存大方向分为4个区域
代码区:存放二进制代码,由操作系统进行管理的
全局区:存放全局变量和静态变量以及常量
栈区:由编译器自动分贝释放,存放函数的参数值,局部变量等
堆区:有程序员分配和释放,若程序员不释放,程序结束时由操作系统回收