比较形象的指针的讲解带例程
指针
指针的意思就是地址的意思。
指针变量其实就是一种变量,不过这个变量指的内容时地址。
Int a =10;
Int *p = &a;
通过上面两行代码,我们可以得出
有一个整型变量a,它的大小是10,还有一个指针变量p,它指向的是一个整型数a的地址。
*号的使用:
在定义指针变量时用一个*号表示这是一个指针变量。
Int *p;
给指针变量赋值时不带*
p=&a;
修改指针变量里的数据时,带*
*p=20;
(这里的*p和定义时的*p不一样,这里的*p指的时指针变量p指向的地址里面的数据)
关于 * 和 & 的谜题
假设有一个 int 类型的变量 a,pa 是指向它的指针,那么*&a和&*pa分别是什么意思呢?
*&a可以理解为*(&a),&a表示取变量 a 的地址(等价于 pa)
*(&a)表示取这个地址上的数据(等价于 *pa),绕来绕去,又回到了原点,
*&a仍然等价于 a。
&*pa可以理解为&(*pa),*pa表示取得 pa 指向的数据(等价于 a),&(*pa)表示数据的地址(等价于 &a),所以&*pa等价于 pa。
二级指针(指向指针的指针)
指针变量也是一个变量,也有自己的地址,也可以被另一个指针变量指向。
比如:int a;
Int *p=&a;
Int **q=&p;
指针变量p指向整型变量a的地址
指针变量q指向指针变量p的地址
比如 int ***str;可以叫做这是一个指向一个指向指针变量的变量的变量。(经典绕口令)
指针作为函数的参数
指针作为函数参数的主要目的
我们知道函数里修改的数据只会在函数内部修改,函数结束后也就都释放了,但是如果我们在函数内部想要修改函数外部的数据,我们就可以把函数外部的数据的指针作为函数的参数传到函数里面,这些在函数内部也可以操作函数外面的数据。
典型例子:交换两个数的值
结果显而易见,你传入一个指针,是把地址里的数据改了,也就是在内存中就修改了这个地址里面的值。而普通的交换,在交换完毕后就释放掉了。
指针函数(指针作为函数的返回值)
指针作为函数的返回值的函数称为指针函数。
指针作为函数的返回值需要注意的一点是,函数运行结束后会销毁在它内部的定义的局部数据,包括局部变量,局部数组,形参,函数返回的指针尽量不要指向这些数据,C语言不会保证这些数据一直有效,后续运行过程中可能会发生运行错误
这个第一个是因为存放n的内存还没有被占用,所以输出结果是对的。第二个的话多加了一行代码,可能内存就已经被占用了,所以就会输出奇奇怪怪的东西。
函数指针(指向函数的指针)
一个函数总是占用一段连续的内存区域,函数名在表达式中有时也会被转换为该函数所在内存区域的首地址,这和数组名非常类似。我们可以把函数的这个首地址(或称入口地址)赋予一个指针变量
,使指针变量指向函数所在的内存区域,然后通过指针变量就可以找到并调用该函数。这种指针就是函数指针。指针数组
指针数组
如果一个数组里面的所有元素都是指针的话,那么这个数组叫做指针数组。
二维数组指针(指向数组的指针)
指针数组和数组指针的区别
前者是一个数组,数组内每一个元素都是指针。后者是一个指针,它指向的是一个数组,后者的意义和二维数组是一样的。不过用指针的形式表示的话就叫做二维数组指针。
Int *p[3];表示一个数组
数组名叫做p,它里面有三个元素
每个元素的类型都是 int * 也就是指针变量,指向的是一个整数型。
Int (*p)[3]表示一个指针。它指向的是一个数组,数组类型是 int[3].
也可以叫做二维数组指针。
Int a[3][3] 与 int(*p)[3]=a;是等价的。
例如: int a[3][3]={{0,1,2},{3,4,5},{6,7,8}};
Int (*p)[3]=a;
所以*p等于二维数组a的第一行(a[0])数据的地址。
Int **p为维数组a的第一行第一个元素的(a[0])的数据
p+1 /p-1 都应该是从指向a[0][0]到a[1][0]。前进或者后退的是4*3=12个字节。
*(p+1)单独使用时表示的是第 1 行数据,放在表达式中会被转换为第 1 行数据的首地址,也就是第 1 行第 0 个元素的地址,因为使用整行数据没有实际的含义,编译器遇到这种情况都会转换为指向该行第 0 个元素的指针;就像一维数组的名字,在定义时或者和 sizeof、& 一起使用时才表示整个数组,出现在表达式中就会被转换为指向数组第 0 个元素的指针。
*(p+1)+1=第一行第一个元素的地址
*(*(p+1)+1)=a[1][1]=3;第一行第一个元素的数据
根据上面所述,得到以下结论:
a+i == p+i
a[i] == p[i] == *(a+i) == *(p+i)
a[i][j] == p[i][j] == *(a[i]+j) == *(p[i]+j)
== *(*(a+i)+j) == *(*(p+i)+j)
指针的总结
指针(Pointer)就是内存的地址,C语言允许用一个变量来存放指针,这种变量称为指针变量。指针变量可以存放基本类型数据的地址,也可以存放数组、函数以及其他指针变量的地址。
程序在运行过程中需要的是数据和指令的地址,变量名、函数名、字符串名和数组名在本质上是一样的,它们都是地址的助记符:在编写代码的过程中,我们认为变量名表示的是数据本身,而函数名、字符串名和数组名表示的是代码块或数据块的首地址;程序被编译和链接后,这些名字都会消失,取而代之的是它们对应的地址。
常见指针变量的定义
-
指针变量可以进行加减运算,例如p++、p+i、p-=i。指针变量的加减运算并不是简单的加上或减去一个整数,而是跟指针指向的数据类型有关。
-
给指针变量赋值时,要将一份数据的地址赋给它,不能直接赋给一个整数,例如int *p = 1000;是没有意义的,使用过程中一般会导致程序崩溃。
-
使用指针变量之前一定要初始化,否则就不能确定指针指向哪里,如果它指向的内存没有使用权限,程序就崩溃了。对于暂时没有指向的指针,建议赋值NULL。
-
两个指针变量可以相减。如果两个指针变量指向同一个数组中的某个元素,那么相减的结果就是两个指针之间相差的元素个数。
-
数组也是有类型的,数组名的本意是表示一组类型相同的数据。在定义数组时,或者和 sizeof、& 运算符一起使用时数组名才表示整个数组,表达式中的数组名会被转换为一个指向数组的指针。