谈到指针,我就不得不说一下,在c语言中最让人头疼的一个话题那就是指针,在我看来,指针单独并不可怕,难就难在它与内存结合起来产生的一些新的知识让人头疼不已,但反过来说指针也方便了我们许多,他可以极大限度的让我们去操作内存,总而言之,指针非常重要,下面就让我来简单的说一下关于指针的一些小问题。
1.指针事实上是一种数据类型,和int 基本类型一样。指针也是一种变量,占有内存空间,保存的是内存地址。
2.关于*p操作
(1)在声明指针中,“*”号表示所声明的变量是一个指针。
(2) 在指针使用时,“*”号表示操作指针所指向的内存空间中的值。
(3)当*p放在等号的左边时,相当于给内存赋值。
(4)当*p放在等号的右边时,相当于从内存中获取值。
int *p = NULL;//声明p是一个指针变量
int i = 3,j = 0;
p = &i;//p指向i所在内存
*p = 5;将p所指的内存的值改变为5,此时变量i的值也是5
j = p;//将p把指的内存空间的值(i的值)赋值给j
注:指针变量和它所指向的内存块是两个不同的概念。
3.指针的数据类型是指它所指向的内存空间的数据类型。当指针步长自加的时候,是根据所指向的内存的数据类型来确定的。
若在32位的系统上,一个指向整型数据的指针,自加的话,是加4.
int *p = &I;
p ++;//<==>(unsigned int)p+sizeof(int);
4.通过指针来改变变量的值是指针的一个重要应用。这是指针作为函数参数的精华。函数调用时,用n指针(形参)改变n-1指针(实参)的值。如:1级指针形参改变0级指针实参的例子。
Swap(int*a,int *b)
{
Int p = *a;
*a = *b;
*b = p;
}//这样可以将实参的值也改变。
5.数组作函数参数的时候会退化为一个指针
void fun(int a[10])<<==>>void fun(int *a)//无论实参是包含多少个元素的数组,但作为函数参数只是把函数首地址传递给形参。
6.关于解决野指针的方案
(1)定义指针时,把指针变量赋值为null;
(2)释放内存时,先判断指针变量是否为null;
(3)释放内存完毕后,把指针变量重新赋值为null
指针运算
- 指针± 整数
- 指针-指针
- 指针的关系运算
- 指针±整数
- 指针-指针
指针的关系运算
代码简化, 这将代码修改如下:
实际在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准并不保证它可行。
标准规定:
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr;//p存放的是数组首元素的地址
#define N_VALUES 5
float values[N_VALUES];
float *vp;
//指针+-整数;指针的关系运算
for (vp = &values[0]; vp < &values[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;
}
for(vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
{
*vp = 0;
}
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一
个元素之前的那个内存位置的指针进行比较。
二级指针
指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里? 这就是 二级指针 。
对于二级指针的运算有:
*ppa 通过对ppa中的地址进行解引用,这样找到的是 pa , *ppa 其实访问的就是 pa .
**ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a .
指针数组与数组指针
注:在c语言中许多人都很容易将这两个概念搞混,那我就来说一说这两个的区别。指针数组它是一个数组,只不过数组中的每个元素都是一个指针,而数组指针它是一个指针,它指向一个数组。数组指针既然是一个指针,那么就是用来接收地址,在传参时就接收数组的地址,所以数组指针对应的是二维数组。指针数组常用在主函数传参,在写主函数时,参数有两个,一个确定参数个数,一个这是指针数组用来接收每个参数(字符串)的地址