二级指针
一级指针存放普通变量的地址
二级指针存放一级指针的地址
格式:存储类型 数据类型 **指针变量名
int **p;
int a=8;
int *p=&a;
int **q=&p;
访问a的值:a *p **q
访问a的地址:&a p *q
访问p的地址:q &p
q=&p;
*q=*&p=p=&a *q=&a
**q=*&a=a=*p
直接访问:
地址 | 数组 | 元素 | ||
a | &a[0] | 2 | a[0] | *a |
a+1 | &a[1] | 3 | a[1] | *(a+1) |
a+2 | &a[2] | 4 | a[2] | *(a+2) |
a+3 | &a[3] | 5 | a[3] | *(a+3) |
a+4 | &a[4] | 6 | a[4] | *(a+4) |
间接访问
地址 | 数组 | 元素 | ||||||
&p[0] | p | a | &a[0] | 2 | a[0] | *a | *p | p[0] |
&p[1] | p+1 | a+1 | &a[1] | 3 | a[1] | *(a+1) | *(p+1) | p[1] |
&p[2] | p+2 | a+2 | &a[2] | 4 | a[2] | *(a+2) | *(p+2) | p[2] |
&p[3] | p+3 | a+3 | &a[3] | 5 | a[3] | *(a+3) | *(p+3) | p[3] |
&p[4] | p+4 | a+4 | &a[4] | 6 | a[4] | *(a+4) | *(p+4) | p[4] |
a和p本质不同:a是地址常量,不能被赋值;p是指针变量,可以被重新赋值
运算方法:
1)*和 ++都是单目运算符,优先级相同
2)单目运算符从右向左运算
(*p)++:先算(*p)==取内容,对内容++
*p++:先算p++,由于++在后,对p取*,最后再p++(地址++)
*(p++):同上
++*p:先算*p得到内容,再去 ++内容
++(*p):同上
*++p:先算++p,由于++在前,p(地址)先自加,对自加后的地址取内容
*(++p):同上
补充:
char *p="hello";
//p在栈区开辟4字节的空间存放字符串常量"hello"的首地址
//"hello"存放在常量区
char a[]="world";
二维数组访问
二维数组数组名表示第一行的首地址
int a[2][3]={2,3,4,5};//a:第一行的首地址 a+1:第二行的首地址
a是行地址,如果想访问其中的列(行地址和列地址级别不同,一行可以有多列),需要对他加*降级处理
a: 第一行的首地址
a+1: 第二行的首地址
*a: 第一行第一列的地址
int a[2][3]={2,3,4,5,6,7};
printf("%p\n",a); //第一行的首地址
printf("%p\n",*a); //第一行第一列的地址
printf("%p\n",*a+1); //第一行第二列的地址
printf("%d\n",*(*a+1)); //取第一行第二列的内容
printf("%p\n",a+1); //第二行的首地址
printf("%p\n",*(a+1)); //第二行第一列的地址
printf("%p\n",*(a+1)+1); //第二行第二列的地址
printf("%d\n",*(*(a+1)+1)); //取第二行第二列的内容
地址 | 元素 | |||||
a[0] | *a | a | 2 | a[0][0] | **a | *a[0] |
a[0]+1 | *a+1 | 3 | a[0][1] | *(*a+1) | *(a[0]+1) | |
a[0]+2 | *a+2 | 4 | a[0][2] | *(*a+2) | *(a[0]+2) | |
a[1] | *(a+1) | a+1 | 5 | a[1][0] | *(*(a+1)) | *a[1] |
a[1]+1 | *(a+1)+1 | 6 | a[1][1] | *(*(a+1)+1) | *(a[1]+1) | |
a[1]+2 | *(a+1)+2 | 7 | a[1][2] | *(*(a+1)+2) | *(a[1]+2) |
访问a[i][j]的地址:
a[i]+j *(a+i)+j
访问a[i][j]的值:
*(a[i]+j) *(*(a+i)+j)
数组指针
美丽的人
本质是指针,指向数组
格式:存储类型 数据类型 (*指针变量名)[列数]
int a[2][3]={2,3,4,5,6,7};
int (*p)[3]=a; //3:要3个3个运算
printf("%p %p\n",a,p);
printf("%p %p\n",a+1,p+1);
p可以代替a进行元素访问,但是本质不同
地址 | 元素 | |||||||
p[0] | *p | a[0] | *a | a | 2 | a[0][0] | **a | *a[0] |
p[0]+1 | *p+1 | a[0]+1 | *a+1 | 3 | a[0][1] | *(*a+1) | *(a[0]+1) | |
p[0]+2 | *p+2 | a[0]+2 | *a+2 | 4 | a[0][2] | *(*a+2) | *(a[0]+2) | |
p[1] | *(p+1) | a[1] | *(a+1) | a+1 | 5 | a[1][0] | *(*(a+1)) | *a[1] |
p[1]+1 | *(p+1)+1 | a[1]+1 | *(a+1)+1 | 6 | a[1][1] | *(*(a+1)+1) | *(a[1]+1) | |
p[1]+2 | *(p+1)+2 | a[1]+2 | *(a+1)+2 | 7 | a[1][2] | *(*(a+1)+2) | *(a[1]+2) |
访问a[i][j]的地址:
p[i]+j *(p+i)+j
访问a[i][j]的值:
*(p[i]+j) *(*(p+i)+j)
数组指针的大小:
int a[2][3]={2,3,4,5,6,7};
int (*p)[3]=a;
printf("%d\n",sizeof(p)); //4
遍历二维数组:
int a[2][3]={2,3,4,5,6,7};
int (*p)[3]=a;
for(int i=0;i<2;i++)
{
for(int j=0;j<3;j++)
{
printf("%d\n",*(p[i]+j)); //*(*(p+i)+j)
}
}
指针数组
本质是数组,里边存放地址
格式:存储类型数据类型*数组名[元素个数]
应用:
存放普通变量的地址
int a=3,b=5,c=9;
int *p[3]={&a,&b,&c};
p[0]--->&a
p[1]--->&b
p[2]--->&c
访问b的值:
*p[1] //p[1]访问指针数组的第二个元素,但是第二个元素是个地址,*p[1]
*(*(p+1)) //p+1访问的数组第二个元素的地址 *(p+1)取第二个元素的内容==&b;*(*(p+1))
访问b的地址:
p[1]
*(p+1)
存放二维数组每一行第一列的地址
int a[3][4]={2,3,4,5,6,7,8,9};
int *p[3]={a[0],a[1],a[2]};
访问a[1][2]的值:
*(p[1]+2) p[1]访问数组中第二个元素(第二行第一列的地址),p[1]+2找到第二行第三列的地址,*(p[1]+2)
*(*(p+1)+2) //p+1找到数组中第二个元素的地址(a[1]的地址),*(p+1)==第二行第一列的地址,*(p+1)+2==第二行第三列的地址,*(*(p+1)+2)==元素内容
访问a[1][2]的地址:
p[1]+2
*(p+1)+2
printf("%d\n",sizeof(p)); //12 3个指针
存放字符串
char *p[3]={"hello","world","hqyj"};
打印world
printf("%s\n",p[1]);
printf("%s\n",*(p+1));
打印'd'
*(p[1]+4)
*(*(p+1)+4) p+1找到数组中第二个元素的地址, *(p+1)取数组中第二个元素的内容(world的首地址),*(p+1)+4访问到从w的位置移动4个字节到d的位置,*(*(p+1)+4)
p[1][4]
命令行参数
argv:就是一个指针数组,里面存放的是命令行传递的字符串
argc:表示argv指针数组里面存储数据的个数,即命令行传递字符串的个数
#include<stdio.h>
int main(int argc, char const *argv[])
{
printf("%s\n",argv[1]);
printf("%d\n",argc);
return 0;
}