指针
一、指针概述
-
内存以1个字节为单位分配内存。
-
每个字节的内存都有标号,这个标号就是地址,也叫指针。
-
地址需要存储,32位编译器用32位(4字节)存此地址,64位编译器用64位(8字节)存此地址。
&a是指取a的首地址。
1.内存
(1)内存含义
- 存储器:计算机的组成中,用来存储程序和数据,辅助CPU经行运算处理的重要部分。
- 内存:内部存储器,暂存程序/数据——掉电丢失SRAM、DRAM、DDR、DDR2、DDR3。
- 外存:外部存储器,长时间保存程序/数据——掉电丢失ROM、ERRROM、FLASH(NAND、NOR)、硬盘、光盘。
(2)内存是沟通CPU与硬盘的桥梁
- 暂存放CPU中的运算数据
- 暂存与硬盘等外部存储器交换的数据
2.指针和指针变量
- 内存区的每一个字节都有一个编号,这就是"地址"。
- 如果在程序中定义了一个变量,在对程序进行编译或运行时,系统就会给这个变量分配内存单元,并确定它的内存地址(编号)。
- 指针的实质就是内存"地址",指针就是地址,地址就是指针。
- 指针是内存单元的编号,指针变量是存放地址的变量。
二、指针的定义和使用
#include <stdio.h>
int main(int argc,char *argv[])
{
//指针也是一种数据类型
//p是一个变量,p的类型是int *
int *p;
p=123;
printf("%d\n",p);
//指针指向谁,就把谁的地址赋给指针
int a=10;
p=&a;//p保存了a的地址
//%p打印地址,是以16进制的方式打印
printf("%p,%p\n",p,&a);
//直接操作指针变量本身没有意义
p=345;
printf("p=%d\n",p);//345
//需操作*p,操作指针所指向的内存
*p=100;//*p相当于a
printf("%d %d\n",*p,a)//100 100
}
(1)指针变量和指针所指向的内存
#include <stdio.h>
int main(int argc,char *argv[])
{
int a=10;
//有2层含义
//定义变量时,*代表类型,它是指针类型int *
int *p;
p=&a;
*p=100;
printf("a=%d\n",a);
int b=11;
p=&b;
*p=200;
printf("a=%d,b=%d\n",a,b);
}
(2)野指针
这个指针变量保存了一个没有意义(非法)的地址
#include <stdio.h>
//只有定义后的变量,此变量的地址才是合法地址
//野指针就是保存没有意义地址的指针变量
//操作野指针变量本身不会有任何问题
//操作野指针所指向的内存才导致段错误
int main(int argc,char *argv[])
{
int *p;
p=0x1234;
printf("p=%d\n",p);
*p=100;
return 0;
}
(3)空指针
#include <stdio.h>
int main(int argc,char *argv[])
{
//空指针,给指针变量赋值为NULL
//NULL就是数字0
int * p=NULL;
int a=11;
p=&a;
if(p!=NULL)
{
*p=100;
}
}
三、指针大小
#include <stdio.h>
int main(int argc,char &argv[])
{
//32位编译器用32位大小(4字节)保存地址
//64位编译器用64位大小(8字节)保存地址
int a=sizeof(int *)
int b=sizeof(char *)
double *p;
int c=sizeof(p);
printf("a=%d,b=%d,c=%d",a,b,c);
}
四、多级指针
#include <stdio.h>
int main(int argc,char *argv[])
{
//如果定义一个合适类型的变量保存另一个变量的地址
//在需要保存变量地址的基础上加一个*
int a=10;
int *p=&a;
int **q=&p;
int ***t=&q;
int ****m=&t;
}
五、万能指针和指针步长
(1)万能指针
#include <stdiio.h>
int main(int argc,char *argv[])
{
//不可以定义void类型的普通变量
//void a;//err
//可以定义void *变量,void*指针也叫万能指针
//void *可以指向任何类型的变量
void *p=NULL;
int a=10;
p=&a;
*((int *)p)=222;
printf("*p=%d\n",*((int*)p));
return 0;
}
(2)指针步长
#inlcude <stdio.h>
//指针的加法,不是传统的加法
//步长由指针指向的数据类型决定
int main(int argc,char *argv[])\
{
int a;
int *p=&a;
printf("p:%d,p+1:%d\n",p,p+1);
char b;
char *p=&b;
printf("q:%d,q+1:%d\n",q,q+1);
printf("\n");
system("pause");
return 0;
//p:163816 p+1:163820
//q:1637795 q+1:1637796
}
六、const修饰的指针变量
#include <Stdio.h>
int main(int argc,char *argv[])
{
int a=10;
int *p1=&a;
*p1=100;//等价于操作啊,*p1操作指针所指向的空间
p1=NULL;//操作指针变量
//const修饰*,代表指针所指向的内存是只读
const int *p2=&a;
//*p2=100;//err
p2=NULL;//ok
//const修饰*,代表指针所指向的内存是只读
int const *p3=&a;
//*p3=100;//err
p=NULL;//ok
//const修饰指针变量,代表指针变量的值是只读
int * const p4=&a;
*p4=100;//ok
//p4=NULL;//err
const int * const p5=&a;
}
七、数组名
#include <stdio.h>
int main(int argc,char *argv[])
{
int a[10];
//数组名是数组首元素地址
printf("a=%p,&a[0]=%p\n",a,&a[0]);
//数组名是常量,不允许修改
}
(1)指向数组首元素的指针
#include <stdio.h>
int main(int argc,char *argv[])
{
int a[10]={1,2,3,4,5,6,7,8,9,10};
int *p=NULL;
//p指针变量指向首元素
p=&a[0];
//或者
p=a;
int i=0;
for(i=0;i<10;i++)
{
//printf("%d,",a[i]);
printf("%d,",*(p+i));
//p[i]等价于*(p+i),操作都是指针所指向的内存
printf("%d,",p[i]);
}
printf("\n");
}
(2)通过指针加减访问数组元素
#include <stdio.h>
int main()
{
int a[10]={1,2,3,4,5,6.7,8,9,10};
//定义一个指针,指向首元素
int *p=a;
p=&a[0];
int n=sizeof(a)/sizeof(*a);//a为数组大小,*a为首元素大小
int i=0;
for(i=0;i<n;i++)
{
printf("%d,",*p);
p++;
}
printf("\n");
}