目录
指针是什么?
在计算机科学中,指针是编程语言中的一个对象,利用地址,它的值直接指向存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量单元。因此,将地址形象化的称为“指针”。意思是通过它能找到以它为地址的内存单元。
总结的来说:
指针就是变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)
细说指针
1.指针的大小:
在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所
以一个指针变量的大小就应该是4个字节。
那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地
址。
2.指针的类型:
char *pc = NULL;
int *pi = NULL;
short *ps = NULL;
long *pl = NULL;
float *pf = NULL;
double *pd = NULL;
指针的定义方式是: type + * 。 其实: char* 类型的指针是为了存放 char 类型变量的地址。short* 类型的指针是为了存放 short 类型变量的地址。 int* 类型的指针是为了存放,int 类型变量的地址。
那指针类型的意义是什么?
(1)
由上图可知:不同类型的指针决定了:指针向前或者向后走一步有多大(距离)。
(2)指针解引用:
对于这个代码:
总结:
指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。 比如: short* 的
指针解引用就只能访问两个字节,而 int* 的指针的解引用就能访问四个字节。
3.指针的两值:
对于*p=100;表示将p所指向的值(即10)用100来替换。
*s=&b:
*s指向的p中的值,将&b给*s表示的是将b的地址来替换*s指向的值(即p自身的值),也就是将p的指向改变了使它指向了b(*p表示位20)。
4.指针的运算:
1.指针+-整数:
#define N_VALUES 5
float values[N_VALUES];
float *vp;
//指针+-整数;指针的关系运算
for (vp = &values[0]; vp < &values[N_VALUES];)
{
*vp++ = 0;
}
2.指针-指针
指针-指针的绝对值指的是两个指针之间元素的个数。
前提:两个指针必须指向同一空间
int my_strlen(char *s)
{
char *p = s;
while(*p != '\0' )
p++;
return p-s; //返回的就是s的长度
}
标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许
与指向第一个元素之前的那个内存位置的指针进行比较
5.野指针
概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
野指针成因:
1. 指针未初始化
#include <stdio.h>
int main()
{
int *p;//局部变量指针未初始化,默认为随机值
*p = 20;
return 0;
}
2.指针越界访问:
#include <stdio.h>
int main()
{
int arr[10] = {0};
int *p = arr;
int i = 0;
for(i=0; i<=11; i++)
{
//当指针指向的范围超出数组arr的范围时,p就是野指针
*(p++) = i;
}
return 0;
}
3. 指针指向的空间释放
如何规避野指针:
1. 指针初始化
2. 小心指针越界
3. 指针指向空间释放即使置NULL
4. 指针使用之前检查有效性
6.指针和数组
数组名指的是什么:
可见数组名和数组首元素的地址是一样的。
结论:数组名表示的是数组首元素的地址。
2.数组和指针的区别:
void main()
{
int arr[10]={1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
arr[0]=100;
*(arr+0)=200; //相当于*arr
int *p=arr;
*(p+1)=20;
p[1]=200;
}
相同之处:
其中arr[0]=100在底层中是以指针的方式在运行,所以他就可以写成*(arr+0)=200 的样子进行编译。
同时指针也就可以写成p[1]=200 的方式进行编译。
不同之处:
指针可以随时改变指向,*p=&x;
但是数组不可以改变指向。*arr=&x(这就是不允许的)。
7.二级指针
int a=10;
int *pa=&a; //pa是什么类型:int*
int* *q=&pa;//int* 定义的是pa类型 ,第二个*指的是接收类型是指针变量
所以决定了pa的地址需要用该类型的指针接收
所以:a的地址存放在pa中,pa的地址存放在q中,pa是一级指针,q为二级指针。
*ppa 通过对ppa中的地址进行解引用,这样找到的是 pa , *ppa 其实访问的就是 pa
int b = 20;
*ppa = &b;//等价于 pa = &b
**ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a
**ppa = 30;
//等价于*pa = 30;
//等价于a = 30;
8.传值和传地址区别
1.一级指针
(1)传值:
(2)传地址:
2. 二级指针
(1)传值:
结论: 如果想要通过形参修改实参指针的指向,在传参时必须要传递实参的地址,形参必须要以二级指针的形式接收。
(2)传地址:
3.总结:
1.在c++/c中,不论以值的方式传递参数,还是以地址的方式传递参数,形参永远都是实参的一份拷贝。
2.假设实参是以值的方式传递,编译器会将实参中的数值拷贝一份交给形参,形参和实参没有任何关联性,在函数中将形参修改了,对实参没有任何影响。
3.假设实参是以地址的方式传递,编译器会将实参的地址拷贝一份交给形参,形参和实参就有关联性,可以通过形参去修改外部的实参。