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]