指针:
指针是一个无符号整数(unsigned int),它是一个以当前系统寻址范围为取值范围的整数。32位系统下寻址能力(地址空间)是4G-Byte(0~2^32-1)二进制表示长度为32bit(也就是4B),int类型也正好取值
按值传递:
C中函数掉用是按值传递的,传入参数在子函数中只是只是一个初值相等的副本,无法对传入参数做任何改动。但实际编程中,经常要改动传入参数的值,这点我们可以用传入参数的地址而不是原参数本身,当对传入参数(地址)取(*)运算时,就可以直接在内存中修改,从而改动原想作为传入参数的参数值
编程参数值
#include<stdio> void inc(int *val) { (*val)++; } main() { int a=3; inc(&a); printf("%d",a); }
在执行int(&a)时,系统在内存分配表里面增加了一行"inc中的val",其地址为新地址,值为&a。操作了*val就是操作a了。
*和&运算:
(*p)操作是这样一种运算,返回p的值作为地址的那个空间取值。(&p)则是这样一种运算,返回当时声明p时开辟的地址。显然可以用赋值语句对内存地址赋值
例:有下面一张表:
地址 | 0000 | .... | 2000 | 2001 | 2002 | 2003 | 2004 | .... | 3000 | 3001 | 3002 | 3003 | .... |
取值 | ???? | .... | 01 | 30 | 00 | 00 | 30 | .... | 00 | 03 | 20 | 9A | .... |
假设有下面一段代码:
int *p; p = 2003H; *P = 3000H;
**p的值是多少:
**p = *(*p) = *(*(p)) = *(*2003H) = *(3000H) = 0300H。(根据上表所述,地址3000的值为0300H)
那么&&p,*(&p),&(*p)呢
&&p = &(&p) = &(&(p)) = &(&2003H) = &(3001H) (程式报错,此时3001H指的是一地址常量,怎么可能会有地址呢)
*(&p) = *(&2003H) = *(3001H) = 2003H (*(&p) = p)
&(*p) = &(3000H),(程式报错,此时的3000H是一个地址常量,怎么会有地址呢)
另类*和&
两个地方需要注意:在程序声明变量时候的*,只是表明“它是一个无符号整数,这个整数指向某个内存地址,一次访问sizeof(type)长度”。这点不要和(*)操作符混淆;
在C++程序声明变量的时候的&,只是表明“它是一个引用,这个引用声明时不开辟新的空间,它在内存分配表加一行,该行的内存地址等于和调用时传入的对应参数内存地址”
双级指针
对于一棵树,我们通常用它的根节点地址来表示这棵树。这就是“擒贼先擒王”。找到了树的根,其每个节点都可以找到。但是有的时候我们需要对树进行删除节点,增加节点的操作,往往考虑删除根节点,增加的节点取代原来的根节点作为新根节点的情况。为了修改根节点这个“整数”,我们需要退一步,使用这“整数”的内存地址,也就是指向这个“整数”的指针。在声明时我们用2个*号,声明指向指针的指针。它的意思是“它是一个整数,这个整数指向某个内存地址,一次访问sizeof(int)长度,其值是一个整数,那个整数值指向某个内存地址,一次访问sizeof(BTree)的长度”。由于存放的指针变量的地址,因此是指向指针变量的指针变量,或称二级指针变量