指针是什么
在计算机科学中,指针(Pointer)是编程语言的一个对象,利用地址,它的值直接指向(Points to)
存在电脑存储器中另一个地方的值。由于通过地址能找到所需的变量单元,可以说,地址指向该变量
单元。因此,将地址形象化的成为“指针”。意思是通过它能找到以它为地址的内存单元。
- 指针
指针是个变量,存放内存单元的地址(编号)。
#include<stdio.h>
int main()
{
int a = 10;//在内存中开辟一块空间
int *p = &a;//这里我们对变量a,取出它的地址,可以使用&操作符。
//将a的地址存放在p变量之中,p就是一个指针变量
return 0;
}
- 一个地址是多大?
- 在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来储存,所以一个指针变量的大小就应该是四个字节。
- 那如果在64位机器上,如果有64个地址线,那一个指针变更的大小是8个字节,才能存放那一个地址。
- 注意:32位操作系统只有32位程序,64位系统既有32位程序,也有64位程序,(是由程序加编译器实现)。
指针和指针类型
- 变量有不同的类型,整型、浮点型等等,在指针当中也会有类型。指针定义方式:type + * 。其实:char 类型的指针是为了存放char类型变量的地址。short 类型的指针是为了存放short类型变量的地址。int*类型的指针是为了存放int类型变量的地址。
char *pc=NULL;
int *pi=NULL;
short *ps=NULL;
long *pl=NULL;
float *pf=NULL;
double *pd=NULL;
- 那么指针类型有什么意义呢?
- 指针±整数
//指针+—整数
#include<stdio.h>
int main()
{
int n=10;
int *pc = (char*)&n;
int *pi = &n;
printf("%p\n",&n);
printf("%p\n",pc);
printf("%p\n",pc+1);
printf("%p\n",pi);
printf("%p\n",pi+1);
return 0;
}
总结:指针的类型决定了指针向前或向后走一步有多大(距离)。
- 指针的解引用
#include<stdio.h>
int main()
{
int n = 0x11223344;
char *pc = (char *)&n;
int *pi = &n;
*pc = 0;
*pi = 0;
return 0;
}
总结:指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。比如:char的指针解引用就只能访问一个字节,而int的指针的解引用就能访问四个字节。
野指针
**概念:**野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
- 指针未初始化
#include<stdio.h>
int main()
{
int *p;//局部变量指针未初始化,默认为随机值。
*p = 20;
return 0;
}
- 指针越界访问
#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;
}
- 指针指向空间的释放
动态开辟内存的时候,可能会造成野指针。
如何规避野指针- 指针初始化
- 小心指针越界
- 指针指向空间释放即使置NULL
- 指针使用之前检查有效性
指针运算
- 指针±整数
#define N_VALUES 5
float values[N_VALUES];
float *vp;
for(vp = &valuas[0];vp < &valuas[N_VALUES];)
{
*vp++ = 0;
}
- 指针-指针
int my_strlen(char *s)
{
char *p = s;
while(*p != '\0')
p++;
return p-s;
}
- 指针的关系运算
for(vp = &values[N_VALUES];vp > &values[0];)
{
*--vp=0;
}
实际在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准并不保证它可性。
标准规定:允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个位置的指针进行比较。
指针和数组
-
数组名就代表数组的首地址。
-
但是在sizeof(arr)中的arr代表的是整个数组,计算出来是数组的大小。
-
所以说,
int arr[ ] = {1,2,3,4,5,6,7,8,9,0}; int *p = arr;
这里p+i其实计算的是数组arr下标为i的地址,那我们就可以使用指针来访问数组。
二级指针
指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?这就是二级指针。
int a = 10;
int *pa = &a;
int **pa = &pa;
a的地址存放在pa中,pa的地址存放在ppa中。
pa是一级指针,而ppa是二级指针。
对于二级指针的运算有:
-
*ppa通过对ppa中的地址进行解引用,这样找到的是pa,*ppa其实访问的就是pa。
int b = 20; *ppa = &b;//等价于pa = & b;
-
**ppa先通过*ppa找到pa,然后对pa进行解引用操作:*pa ,那找到的是 a。
**ppa = 30; //等价于*pa = 30; //等价于a = 30;
指针数组
指针数组是存放指针的数组
数组指针是一个指针,指向数组。
举例说明一下:
int* arr[5];
arr是一个数组,有五个元素,每个元素是整形指针。