1,指针

表示内存地址(指针指向了内存地址)

如果这个内存地址恰好是某个变量的地址,那么又称“这个指针指向该变量”

只要在变量前面加上&,就表示变量的地址


2,指针变量

指针变量用来存放指针(地址)

⚠️:一般把星号放在数据类型之后(C++程序员),星号是类型的一部分。


给指针变量赋值的方式一般是把变量的地址取出来,然后赋给对应类型的指针变量。

eg,

int a;

int* p=&a;


p保存的是地址,*p是这个地址存放的元素;


指针变量支持自增和自减操作,对于int*类型的指针变量p来说,p+1是指p所指的int变量的下一个int类型变量地址;


对于指针变量,把其存储的地址类型称为基类型,例如定义为int* p的指针变量,int就是它的基类型。

⚠️:基类型必须和指针变量存储的地址类型相同,也就是上面定义的指针变量p不能存放double或char类型数据的地址,而必须是int类型数据的地址。


3,指针与数组

数组名可以作为数组的首地址使用

eg,

int a[10]={1};

int* p=a;

a作为数组a的首地址&a[0]而被赋值给指针变量p 


由于指针变量可以进行加减法,即a+i等同于&a[i];

如果想要访问其中的元素a[i],需要加上星号,使其变成*(a+i)后才和a[i]等价


输入数组元素的新颖写法:

scanf(“%d”,a+i);


两个int类型的指针相减,等价于在求两个指针之间相差了几个int


4,使用指针变量作为函数参数

这时视为把变量的地址传入函数,如果在函数中对这个地址的元素进行改变,原先的数据就会确实地改变


    在上述代码中,把int型的指针变量p赋值为a的地址,然后通过change函数把指针变量作为参数传入,此时传入的其实是a的地址,在change函数中,使用*p修改地址中存放的数据,也就是改变了a本身,当最后输入a时,就已经是改变了的值,这种传递方式被称为地址传递。


⚠️:函数在接收参数的过程中是单向一次性的值传递。

只有在获取地址的情况下对元素进行操作,才能真正地修改变量。


5,引用

引用不产生副本,而是给变量起了别名。

对引用变量的操作就是对原变量的操作。


引用只需要在函数的参数类型后面加上&就可以了。(一般写在变量名的前面)

⚠️:要把引用跟取地址运算符&区分开来,引用并不是取地址的意思。


区分:

引用:

1,在等号左边

2,与类型在一起

3,定义的时候必须初始化

4,&后面跟的别名是新名字,之前不存在


取地址:

1,在等号右边

2,与变量在一起

3,&后面跟的变量,已经存在


eg,

int a=3;

int &b=a;    //引用

int* p=&a;  //取地址


指针变量其实是unsigned类型的整数,因此为了理解方便,可以“简单”地把*int类型理解为unsigned int类型,而直接交换这样的两个整型变量是需要加引用的


6,结构体的使用

结构体的定义:

格式

struct Name{

//一些基本的数据结构或者自定义的数据类型

};


eg,

struct studentInfo{

      int id;

      char gender; //‘F’ or ‘M’

      char name[20];

}Alice,Bob,stu[1000];


结构体变量和结构体数组,也可以按照基本数组类型(如int型)那样定义

studentInfo Alice;

studentInfo stu[1000];



结构体里面定义出了自身(这样会引起循环定义的问题)之外的任何数据类型,虽然不能定义自身,但是可以定义自身类型的指针变量

eg,

struct node{

        node n;          //不能定义node型变量

        node* next;  //可以定义node*型指针变量

};



7,访问结构体内的元素

“.”操作和”->”操作


eg,

struct studentInfo{

    int id;

    char name[20];

    studentInfo* next;

}stu,*p;


访问stu中变量的写法如下:

stu.id

stu.name

stu.next


访问指针变量p中元素的写法如下:

(*p).id

(*p).name

(*p).next


C语言中又有一种访问结构体指针变量内元素的更简洁的写法:

p->id

p->name

p->next


也可以对结构体变量进行赋值:

stu.id = 10086;

int getId =stu.id;


构造函数是用来初始化结构体的一种函数,它直接定义在结构体中。

一个特点是它不需要写返回类型,且函数名与结构体名相同。


对一个普通定义的结构体,其内部会生成一个默认的构造函数(但不可见)

struct studentInfo{

      int id;

      char gender;

      //  默认生成的构造函数

      studentInfo(){} 

};


如果想要手动初始化参数,只需要提供初始化参数来对结构体内的变量进行赋值即可。

struct studentInfo{

      int id;

      char gender; 

      //下面的参数用以对结构体内部变量进行赋值

      studnetInfo(int _id,char _gender){

        id=_id;

        gender=_gender;

        }

};


构造函数也可以简化为一行;

struct studentInfo{

      int id;

      char gender;

      studentInfo(int _id,char _gender) : id(_id),gender(_gender){ }

};


这样可以在需要时直接对结构体变量进行赋值:

studentInfo stu= studentInfo(10086,”M”);


⚠️:如果自己重新定义了构造函数,则不能不经初始化就定义结构体变量(也就是默认的生成的构造函数 studentInfo(){ } 已经被覆盖了)

为了既能记不初始化就定义结构体变量,又能享受初始化带来的便捷,可以吧”studentInfo(){}”手动加上


只要参数格式和类型不完全相同,就可以定义任意多个构造函数。