指针

1.内存

在这里插入图片描述

2.指针

其实是一个内存地址,通过地址可以找到我们这个变量
我们可以将上面的100,101等,叫做一个指针
&:取地址运算符
通过&可以获取对应的地址
#include<stdio.h>
main()
{
	int a = 10, b = 20, c = 30;
	printf("a=%d,b=%d,c=%d\n", a, b, c);
	printf("a的地址:%d,b的地址:%d,c的地址:%d\n", &a, &b, &c);//没次运行结果不同,每次运行都会重新为abc分配地址
	//%p:打印一个地址(16进制)                                  
	printf("a的地址:%p,b的地址:%p,c的地址:%p\n", &a, &b, &c);
	return 0;
}

对a,b,c的地址不能赋值,&a,&b,&c等都是常量,称为指针常量
指针变量(容器):存储的是地址

char ch='A';
char* p;//p的类型就是char*, char*是指向char型的指针,即指向一个字符
short* p1;
int* p2;//指向三个不同类型的指针

*靠近char和靠近变量没区别

char* p; char *p;//没区别

区别typedef和define
起别名:typedef

#define MYINT int
typedef int MYPLUSINT;
MYINT m;    //该定义在预处理时MYINT会替换成int
MYPLUSINT n;//typedef不会进行替换,而是当做int进行使用

在有define定义的地方全部替换成原型
typedef已经定义了一个新类型,不会在预处理时替换
二者都是全局变量

#define PMYINT int*
PMYINT P1,P2,P3;//这里只定义了一个指针变量
typedef int PMYPIUSINT;
PMYPIUSINT p1,p2,p3;//这里定义了3个指针变量

指针初始化
没有初始化的指针不能用

int *p=&a;
int *p1=&b;//初始化

定义空指针(NULL)
不能进行间接访问

int *p=NULL;
printf("p=%d\n",p);

非法指针:没有定义指针指向的指针,也不能间接访问
在执行间接访问时,一定要进行判断指针是不是为NULL。
指针间接访问
*:间接访问运算符

int a=10,b=20,c=30;
int *pa=&a,*pb=&b,*pc=&c;
printf("*pa=%d\n",*pa);//*pa等价于a
*pc=*pa+*pb;//指针可以作为变量使用
*pa=100;//相当于将100赋给a
//*&a等于a
//&*pa是a的地址

指针改变指向

pa=&c;

二级指针
指向一级指针的指针,是常量,存储的是一级指针的地址

int **ppa=&pa,**ppb=&pb,**ppc=&pc;

在这里插入图片描述
二级指针也可以改变指向、

*ppc==pc;
*pc==c;
**ppc==*(*ppc)==*pc==c;

多级指针

int ***pppa=&ppa;
int ****ppppa=&pppa;

指针所占内存大小

不管什么类型的指针,多级指针,统统都占4个字节
指针只是一个地址编号
虚拟内存:windows编程
所有应用程序在系统里面都占用4G虚拟内存,c盘当中有一个非常大的隐藏文件pagefile.sys,该文件用来实现虚拟内存,实际上为每个应用程序分配的物理内存没有4G的,在磁盘当中给每个应用程序划分了一块空间,因为应用程序在内存当中运行的部分只有一小部分,用到的数据放到内存当中,不用的放入磁盘当中(相当于CPU的,一级缓冲,二级缓冲)
4G虚拟内存有232,分为4块:栈,堆,静态区,代码段(空指针赋值区,用户区,内核区)
在这里插入图片描述

3.指针的运算及指针偏移

指针+整数=指针
地址大小实际增加=整数*指针的类型

#include<stdio.h>
main()
{
	int a = 10, b = 20, c = 30;
	int *pa = &a, *pb = &b, *pc = &c;
	printf("pa=%d,pb=&d,pc=%d\n", pa, pb, pc);
	printf("pa+10=%d\n", pa + 10);//增加10*4
	//
	double d = 45.6;
	double *pdouble = &d;
	printf("pdouble=%d\n", pdouble);
	printf("pdouble+5=%d\n", pdouble + 5);//增加5*8
	//
	char ch = 'A'; 
	char *pch = &ch;
	printf("pch=%d\n", pch);
	printf("pch+5=%d\n", pch + 5);//增加5*1
	//实际增加=整数*指针的类型
	return 0;
}

在这里插入图片描述

指针-整数=指针
地址大小实际减少=整数*指针类型
指针-指针=单位长度
表示两个地址之间相差多少个单位,两个地址之间间隔有多远
以上三种运算要在一段连续的内存空间,数组,动态开辟的内存空间
指针指向不同的地方就是指针偏移

>,<,==,!=
>,<这两个判断指针大小,也只有在一段连续的内存空间中比较才有意义
==!=这两个可以随便两个指针互相比较

4.指针与一维数组的关系

#include<stdio.h>
main()
{
	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	printf("arr=%d",arr);//arr表示数组的首地址,数组名
	printf("arr[0]的地址=%d\n", &arr[0]);//两者相等
	//arr=1561566不合法,地址是常量,不能改变
	//arrd的类型:指向int型的指针
	int *parr = arr;//一维数组指针
	printf("arr+1=%d\n", arr + 1);//实际+4个字节,&arr[1]的值
	printf("arr+2=%d\n", arr + 2);//实际+8个字节
	printf("arr+9=%d\n", arr + 9);//实际+36个字节
	printf("arr+10=%d\n", arr + 10);//越界,仍可以打印一个地址,但不属于数组内存,在数组外
	//指针后移
	printf("&arr[1]=%d\n", &arr[1]);
	printf("&arr[2]=%d\n", &arr[2]);
	return 0;
}

在这里插入图片描述
故:
arr+0=&arr[0];
arr+1=&arr[1];
arr+2=&arr[2];

arr+9=&arr[9];
继续推:
*(arr+0)=arr[0];–1
*(arr+1)=arr[1];–2
*(arr+2)=arr[2];–3

*(arr+9)=arr[2];–10

5.指针与二维数组的关系

#include<stdio.h>
main()
{
	int i, j;
	int arr2[4][5]=
	{
		{1,2,3,4,5},//第1个一维数组
		{6,7,8,9,10},
		{11,12,13,14,15},//第3个一维数组
		{16,17,18,19,20}
	};
	for (i = 0; i < 4; i++)
	{
		for (j = 0; j < 5; j++)
		{printf("%4d", arr2[i][j]);}
		printf("\n");
	}
	return 0;
}

arr2同一维数组一样,是二维数组的首地址
但是,arr2不是指向int型的指针,而是一个指向数组的指针
我们可以将二维数组当做一维数组开看,则该一维数组有4个元素,分别为arr2[0]={1,2,3,4,5}arr2[1]={6,7,8,9,10}arr2[2]={11,12,13,14,15}arr2[3]={16,17,18,19,20},4个元素,每个元素都是一个数组,这四个元素代表了四个数组,如arr2[0]表示1,2,3,4,5的数组名

printf("arr2+0=%d\n",arr2+0);
printf("arr2+1=%d\n",arr2+1);//偏移了5*4个字节,加1指向下一个一维数组
printf("arr2+2=%d\n",arr2+2);
printf("arr2+3=%d\n",arr2+3);

数组指针:是一个指针,指向一个数组
指针数组:是一个数组,数组里面存的都是指针

定义数组指针的两种方法

int(*parr2)[5]=arr2;//定义了一个数组指针
typedef int(*PARR2)[5];//PARR2是数组指针类型
PARR2 parr2=arr2;

二维数组的间接访问

arr2+n是一个指针,则该指针也可以进行间接访问

printf("arr2+0=%d\n",arr2+0);
printf("arr2+1=%d\n",arr2+1);//偏移了5*4个字节,加1指向下一个一维数组
printf("arr2+2=%d\n",arr2+2);
printf("arr2+3=%d\n",arr2+3);
printf("*(arr2+0)=%d\n",*(arr2+0));
printf("*(arr2+1)=%d\n",*(arr2+1));//输出整个数组
printf("*(arr2+2)=%d\n",*(arr2+2));//输出
printf("*(arr2+3)=%d\n",*(arr2+3));

以上两种输出的结果一样,但是类型不一样。
第一种是指向数组的指针,存的是数组的地址。
第二个得到的是数组,*(arr2+0)相当于是一维数组的数组名,相当于arr2[0]。
推导


*(arr2+0) => arr2[0]
*(arr2+1) => arr2[1]
*(arr2+2) => arr2[2]
*(arr2+3) => arr2[3]

arr2+0的类型:指向整个一维数组的指针
arr2[0]的类型:指向整形的指针

所以对*(arr2+0)还可以继续间接访问

*(*(arr2+0)+0)  =>  *(arr2[0]+0)//指向第一个数组的第一个元素
printf("*(*(arr2+0)+0)=%d\n", *(*(arr2 + 0) + 0));//输出1
printf("*(arr2[0]+0)=%d\n", *(arr2[0] + 0));//输出1
*(arr2+0)是个一维数组
则*(arr2+0)+2  =>  &arr2[0][2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值