指针
- 指针的定义和使用
可以理解为:指针即是地址
- 语法:
数据类型 * 指针变量名;
如:
int a=10;
int *p;
p=&a;
- 解引用:
指针前加*代表解引用,找到指针指向的内存中的数据
如:
*p=1000;// a变为1000
- 空指针和野指针
- 空指针
指针变量指向内存中编号为0的空间
用途:初始化指针变量
空指针指向的内存是不可以访问的
int *p=NULL;
*p=100;//错误 0到255之间的内存编号是系统占用的,因此不可以访问
- 野指针
指针变量指向非法的内存空间
int *p=(int *)0x1100;//无法运行,读取访问冲突.在程序中,尽量避免出现野指针
空指针和野指针都不是我们申请的空间,因此不要访问
- const修饰指针
1.常量指针:const修饰指针
const int *p=&a ;
特点:指针的指向可以修改,但是指针指向的值不可以修改.也就是说,不可以用常量指针来解引用修改内存中的值,但是变量本身的值是可以修改的.
2.指针常量
int * const p = &a ;
特点:指针的指向不可以改,但是指针指向的值可以改.和常量指针刚好相反.
3.const既修饰指针又修饰常量
const int * const p = &a ;
特点:都不可以改
记忆方法:const在*前面,可以理解为修饰指针,所以是常量指针;反之,理解为const在后面,所以是指针常量.特点:const修饰哪个,哪个就不可以改
- 指针和数组
int arr[10]={1,2,3,4,5,6,7,8,9,10};
int *p=arr;//arr就是数组的首地址
*p;//a[1] 即1
p++;//指针向后偏移四个字节;
*p;//a[2] 即2
- 指针和函数
用指针实现数值传递:
void swap(int *p1, int *p2)
{
int temp=*p1;
*p1=*p2;
*p2=temp;
}//地址传递
结构体
- 结构体的定义
结构体属于用户自定义的数据类型,允许用户存储不同的数据类型
- 语法:
struct 结构体名 { 结构体成员列表 } ;
如:
struce Student
{
string name;
int age;
int score;
};
struct Student s1;
注:在C++中创建变量时struct可以省略不写,即可以写成: Student s1;
结构体定义的时候struct不可省略
- 结构体数组
将自定义的结构体放入到数组中方便维护
- 语法:
struct 结构体名 数组名[元素个数]={ {} , {} , … {} }; - 步骤:
//1.定义结构体
//2.创建数组
//3.给结构体数组中的元素赋值
//4.遍历结构体数组
struct Student
{
string name;
int age;
int score;
};
struct Student stuArray[3]=
{
{"A",18,100},
{"B",28,99},
{"C",38,66}
};
//数组中结构体的值是可变的
- 结构体指针
struct Student
{
string name;
int age;
int score;
};
struct Student s = {"A",18,100};//创建学生结构体变量
struct Student * P=&s;//通过指针指向结构体变量,这里的struct也可以省略
cout << p->name <<endl;//通过指针访问结构体变量中的数据
cout << (*p).name <<endl;//两种遍历方法均可
- 结构体嵌套结构体
结构体中的成员可以是另一个结构体
- 结构体作函数参数
结构体作为参数向函数中传递
- 值传递
void f(struct Student s)
{
...
}
值传递时,如果形参发生了任何改变,在main函数中实参不会改变
- 地址传递
void f(struct Student *p)
{
...
}
地址传递时,利用指针修饰了数据,则子函数和main函数中都会改变
将函数中的形参改为指针,可以减少内存空间,而且不会复制一个新的副本出来
- 结构体中const使用场景(常量指针)
地址传递有一个缺点是,子函数可能会使一些不应该变的变量发生改变,如学生的姓名等,而地址传递是用指针作为形参,可以减少内存空间,这时可以用到const达到一举两得的效果,防止我们的误操作
void f(const struct Student *s) { }