指针
- 内存,以一个字节为单位来分配内存
- 每个字节的内存都有标号,这个标号就是指针
- 指针需要存储,32位的编译器用32位(4字节)存储此地址,64位的用64位的(8字节)存储此地址
- 编码:为每个物理存储单元(一个字节)分配一个号码
- 寻址:根据分配的号码找到相应的存储单元,完成数据读写
char:占一个字节,分配一个地址
int:占四个字节,分配四个地址 定义一个变量,在程序编译或运行时,系统给这个变量分配内存的单元,并且确定他的内存地址
指针是内存的单元的编号,指针变量是存放地址的变量;我们通常把指针变量和指针都叫做指针;
int a = 10;
int* p = &a; //取出a的地址,赋值给p
printf("%p\n%p\n",p,&a); //%p是打印地址,以十六进制的方式
printf("结束"); //&a和p的值相同
int b = *p;
printf("%d\n",b); //*p是访问p位置的值,这里打印出a的值10
*p = 200;
printf("%d\n",b); //b的值是10
printf("%d\n",a); //a的值是200
int a =10;分配一个空间给a,a的地址编号是0X123456,把10存放到a的空间;
int *p = &a;分配一个空间给p,把a的地址编号0x123456存放到p的空间;
野指针
段错误就是指访问的内存超出了系统所给这个程序的内存空间;在编程中以下几类做法容易导致段错误,基本上是错误地使用指针引起的。 1)访问系统数据区,尤其是往系统保护的内存地址写数据最常见就是给一个指针以0地址。 2)内存越界(数组越界,变量类型不一致等): 访问到不属于你的内存区域。
野指针就是指向了一个非法的位置,例如你直接写了int* p = 0x12345;这就是非法的,若使用就会发生段错误;
//*p等价于*(p+0),同时等价于p[0];
//p[1]就是越界了,操作野指针指向的内存,等价于*(p+1)
万能指针
//不可以定义void类型的变量
//void a; 不知道分配多大空间
//可以定义void*,这种指针叫万能指针
//void*可以指向任何类型
int a = 10;
void* p = &a;
//*p = 20;报错,因为使用指针操作内存,但是不知道分配多大空间
//把万能指针转换成确定的类型
* ((int*)p) = 20;
printf("%d",* ((int*)p));
int a = 10;
int* p = &a; //取出a的内存首地址,如果是万能指针,就不知道走多久是结束;
//这叫不知道指针步长
指针步长
int a = 10;
char c = 'c';
int* p = &a;
char* q = &c;
//指针的加法不是传统的加法
//加的1个单位是1个步长
//步长是指针指向的数据类型决定的,int的步长是4个字节,char的步长是1个字节
printf("%p,%p\n",p,p+1); //p和p+1相差4个字节 0X...3C,0X...40
printf("%p,%p\n",q,q+1); //q和q+1相差1个字节 0X...3B,0X...3C
const修饰指针
int a = 10;
int* p1 = &a;
*p1 = 20; //修改a的值,OK
p1= null; //修改指针的值,OK
//------------------
const int* p2 = &a; //const修饰*,代表指针指向的内存只读
*p2 = 20; //error
p2 = null; //OK
//------------------
int const *p3 = &a; //const修饰*,代表指针指向的内存只读
*p3 = 20; //error
p3 = null; //OK
//------------------
int* const p4 = &a; //const修饰指针变量,代表指针变量的值是只读
*p4 = 20; //OK
p4 = null; //error
//------------------
const int* const p5 = &a; //都修饰,指针变量和指向的内存都是只读
int a[10];
//数组名是数组元素的首地址,a = &a[0]
printf("%p,%p",a,&a[0]);
//数组名是常量,不允许修改。类似于int* const p;
//a=10; //error
指针和数组
int a[10] = {0,1,2,3,4,5,6,7,8,9};
printf("%d\n",a[4]); //打印第五个元素,输出4
int* p = a; //等价于p = &a[0]
printf("%d\n",p[4]); //打印第五个元素,输出4; p[i]等价于a[i]
printf("%d\n",*(p+4) );//打印第五个元素,输出4; *(p+4)是首地址加四个步长,取出第五个元素
int a[10] = {0,1,2,3,4,5,6,7,8,9};
int* p = a;
int len = sizeof(a) / sizeof(*a); //*a访问首地址存放的0,等价于a[0],*p
for(int i=0;i<len;i++)
{
printf("%d, ",*p);
p++; //不可以写a++,因为数组名是常量,不可变
}
int a[10] = {0,1,2,3,4,5,6,7,8,9};
int len = sizeof(a) / sizeof(*a); //*a访问首地址存放的0,等价于a[0],*p
int* p = a+len-1;
for(int i=0;i<len;i++)
{
printf("%d, ",*p);
p--; //使用指针,从最后一个向前访问
}
来源:oschina
链接:https://my.oschina.net/u/3687912/blog/3186706