一、指针:rj:用来记录地址编号
指针的定义及大小
//定义指针:数据类型 * | 指针变量名;
int * p;
//让指针记录变量a的地址
p=&a;//取址符&
int * p=&a;
//用指针=地址取出数据
*p=1000;//解引用* 相当于a=1000
//空指针:rj:指向0的指针
//由于内存编号0~255是系统占用的,所以没有权限更改
int * p=NULL;
//*p=100;
//野指针:rj:指向别人开的房
//int * p=(int *)0x0011;
p=&a *p=a;在32位操作系统中都是占用4个字节空间,64位8个字节
利用指针访问和遍历数组中的元素
int * p=arr;//数组首地址给了指针p
*p//解引用p就是数组arr的第一个元素
p++;//指针会向后偏移一个整型4字节
*p//再次解引用p就是数组arr的第二个元素
//用指针遍历数组,for仅表示次数
for(int i=0;i<10;i++){
cout<<*p<<endl;
p++;
}
const修饰指针
//const修饰指针:常量de指针:指针指向值不可以修改,指针指向可以改
const int * p=&a;
//*p=10;a=10不能改
p=&b;
//const修饰:指针shi常量:指向不能改
int * const p=&a;//const
//const即修饰指针又修饰常量
const int * const p=&a;
记法:名称:看*和const的顺序 作用:看const在谁的前面*p还是p
指针作为函数的参数=地址传递:弊端是会改变原数据:const
void swap(int * p1,int * p2){
int temp=*p1;
*p1=*p2;
*p2=temp;
}
int a=10;
int b=20;
swap(&a,&b);//a=20,b=10
应用:封装冒泡排序:整型数组的升序排序
//冒泡排序函数(首地址 数组长度)
void bubbleSort(int * arr,int len){
for(int i=0;i<len-1;i++){
for(int j=0;i<len-i-1;j++){
if(arr[j]>arr[j+1]){
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
//打印
void printArray(int * arr,int len){
for(int i=0;i<len;i++){
cout<<arr[i]<endl;
}
}
//创建数组,数组长度
int arr[10]={4,3,6,9,1,2,10,8,7,5};
int len=sizeof(arr)/sizeof(arr[0]);
bubbleSort(arr,len);//传长度算法更加灵活
printArray(arr,len);
二、引用
理解:int &b=&a;不能只定义不初始化,初始化后不能更改(b=c不是更改引用)
//引用:数据类型 &别名=原名;
int &b=a;//rj:int &b=&a;
//int & ref=10;是错误的
本质:指针常量int * const def=&a+发现是引用类型时会自动解引用*ref;引用ref=20相当于*ref=20
引用做函数参数以及常量引用(const版)
int Swap(int &a,int &b){
int temp=a;
a=b;
b=temp;
}
int a=10;
int b=20;
Swap(a,b);//函数中改变,变量也会改变
const int & ref=10;//加const才能=10
编译器优化为:int temp=10;const int & ref=remp;
//形参前加const,防止什么样的误操作?
void showValue(int &val){
val=1000;//const int &val就不让修改了
cout<<val<<endl;
}
int a=10;
showValue(a);
cout<<val<<endl;//a=1000被改变了;
//rj:就爱搞这种本来不能改,现在能改了还不让改的事,你给他值传递不好吗?
引用做函数返回值:不能返回局部引用、静态局部可以做左值
int& test(){
int a=10;
return a;//返回局部变量的引用:值
}
int &ref=test();
cout<<ref<<endl;//结果正确
cout<<ref<<endl;//结果错误
int& test(){
static int a=10;
return a;
}
int &ref=test();
cout<<ref<<endl;//结果正确
cout<<ref<<endl;//结果也正确
test()=1000;//函数返回值为别名可以做左值 rj:a=1000;
cout<<ref<<endl;//ref=1000;
cout<<ref<<endl;//ref=1000;
三、结构体=自定义数据类型:内置类型的集合
定义和创建结构体:学生(姓名,年龄,分数)
//定义结构体模板
struct Student{
string name;
int age;
int score;
};
//创建具体学生;struct可省略,定义时不可省
//struct 结构体名 变量名;
struct Student s1;
s1.name="张三";
s1.age=18;
s1.score=100;
cout<<"姓名:"<<s1.name<<"年龄"<<s1.age<<"成绩"<<s1.score<<endl;
//struct Student s2={...}
struct Student s2={"张三",18,100};
//定义时创建(少)
struct Student{
string name;
int age;
int score;
}s3;
s3.name="张三";
s3.age=18;
s3.score=100;
结构体嵌套结构体 重点:属性的属性..
struct Student{
string name;
int age;
int score;
};
struct Teacher{
int id;
String name;
int age;
struct Student stu;//注意先后顺序
}
Teather t;
t.stu.name;
t.stu.age;//rj:属性的属性
结构体数组定义,赋值和遍历
//定义结构体:除了定义外都在main中
struct Student{
string name;
int age;
int score;
};
//struct 结构体名 数组名[元素个数]={{},{},{}};
//数据类型 数组名[数组长度];
struct Student stuArray[3]=
{
{"张三",18,100},
{"李四",28,99},
{"王五",38,66}
};
//结构体数组中的元素赋值
stuArray[2].name="赵六";
stuArray[2].age=80;
stuArray[2].score=60;
//遍历
for(int i=0;i<3;i++){
cout<<"姓名:"<<stuArray[i].name<<"年龄:"<<stuArray[i].age<<"分数:"<<stuArray[i].score<<endl;
}
结构体做函数参数(可const):学生传到参数中打印其信息
//传递方法1:值传递
void printStudent(struct Student s){
cout<<s.name;
...
}
printStudent(s);
//传递方法2:地址传递
//不想被改时,结构体前加const struct Student * p,指针指向值不能修改
void printStudent(struct Student * p){
cout<<p->name;
...
}
printStudent(&s);
//区别:在子函数中修改属性,观察main函数中打印的输出
结构体指针 重点:指针对象的属性->
//定义和创建结构体
struct Student{
string name;
int age;
int score;
};
struct Student s={"张三",18,100};
//指针指向结构体变量 struct可省略
struct student * p=&s;
//通过指针访问结构体变量
p->name//rj:可能由于*p后的对象有属性,大概约等于*p.name