指针:是一种数据类型,指针装的是地址类型的变量

int * a;//声明指针的方式: 类型+*+变量名,*a表示一个指针变量,a是指针的名字

指针在没有赋值的情况下不允许使用,没有赋值的指针叫做野指针

int a=12;
int* p=&a;//指针变量的初始化,p中装的是地址,*p表示指针变量,p的地址与p的值不同(&p!=p)

指针类型要与被赋值的变量数据类型对应,否则编译器就会警告

指针变量的使用

1、*p与定义时的*意义不同,定义时是标记,表示定义一个指针变量,使用时*时一个运算符(内存操作运算符,解引用运算符)

2、使用方法:*+地址。地址一定要是合法地址,一个指针指向一个变量,*这个指针表示这个变量本身

int a=12;
int* p=&a;//在之后的运算中a都可以用*p间接操作

指针类型决定可以操作的内存空间大小

二级指针

指针变量也是变量,也有存储空间

int a=12;
int* p=&a;
int** p1=&p;//定义指针的指针,叫做二级指针

二级指针的使用

数组名跟指针不一样

int a[2];
int** p=&a;//会产生警告,可以通过查看警告来了解数组是什么类型的

指针与数组

1、利用指针遍历数组

int a[5]={1,2,3,4,5};
int* p=&a[0];
for(int i=0;i<=4;i++)
{
printf("%d\n",*(p+i));//注意p+i的小括号
}

地址的加减不是在地址数值的加减,加代表下一个地址,减代表上一个地址

(1)数组的空间是连续的

(2)地址加减是加一个类型的大小

2、数组指针

数组名字的本质是地址+[偏移量]

方括号的意义表示偏移量,即方括号前和方括号中的一个地址值和一个整型数字相加表示的地址所指向的变量     *(p+2)==p[2]    2[p]==p[ 2]    

int a[5];
int* p=&a[0];
p[0]==a[0];p[1]==a[1];//之后同理

数组名字和指针的不同:数组名字不能改名,指针可以改名

3、指针数组、地址数组

指针数组:数组中每一个变量都是相同类型的地址,也叫地址数组

int b,c,d,e,f;
int* a[5]={&b,&c,&d,&e,&f};

拉链结构

int b[3];
int c[4];
int d[5];
int* a[3]={b,c,d};

拉链结构与二维数组在形式上一致,但本质是不同的

4、数组指针:数组类型的地址

int a[5];
int (*p)[5]=&a;//意义是5个变量的int数组的指针叫p,其对应的数组为

数组指针的方括号中的数字要与后面赋值的数组相对应

二维数组指针

二维数组中有三个类型的地址:二维数组、一维数组、元素

定义:

int a[2][3]={{1,2,3},{4,5,6}};

int *p=&a[1][1];//元素
int (*p1)[3]=&a[1];//一维数组
int (*p2)[2][3]=&a;/二维数组

当不知道指针怎么定义时,随便定义一个指针,然后赋值,如果不报错,则定义正确,如果报错,则编译器会告诉你如何定义

数组名字就代表数组首元素的首地址

遍历二维数组

int a[2][3]={{1,2,3},{4,5,6}};
int i,j;

for(i=0;i<2;i++)
{
for(j=0;j<3;j++)
{
printf("%d",(*a)[i][j]);
}
}

使用指针遍历二维数组

int a[2][3]={{1,2,3},{4,5,6}};

int *p=&a[0][0];
for(int i=0;i<=6;i++)
{
printf("%d\n",*(p+i));
}

数组的内存是连续的

指针的大小

1、32位操作系统支持小于等于32位的软件,64位的操作系统支持小于等于64位的软件

2、32位的软件中指针大小为4字节,64位程序中指针大小为8字节