在计算机的内存存储器中,拥有大量的存储单元。一般情况下,存储单元是以字节为单位进行管理的。为了区别内存中的每一个字节,就需要对每一个内存单元进行编号,且每个存储单元都有一个唯一的编号,这个编号就是存储单元的地址,称为内存地址。这样,当需要存放数据时,即可在地址所标识的存储单元中存放数据。当需要读取数据时,根据内存单元的编号或地址即可找到所需的内存单元。
根据内存地址就可以准确定位到对应的内存单元,因此内存地址通常也称为指针。
对一个内存单元来说,内存单元的地址即为指针,内存单元中存放的数据就是该内存单元的内容。
指针==地址
一、指针的定义
int *p; //定义一个整型指针变量p
取地址符 & 如:&a(得到a的地址)
int x = 10; //整型变量存放整型值
int *p = &a; //整型地址(指针)变量存放整型地址
int a;
int *p = &a; //定义一个整型指针变量p存放a的地址
*p = 100; //即a = 100; *p间接访问符,解引用
“*”所代表的意义如下:
(1)代表双目运算符里的乘法
(2)前面有数据类型(如int等),有进行定义。所指的是指针变量
(3)前面无数据类型,间接访问,代表解引用
指针变量比普通变量多了一个解引用。使用指针时,须要解引用才能使用。
printf("%d\n",sizeof(char *)); //这里的char是所有数据类型的一个例子
output: 4
说明:只要是输出指针,所输出的字节数都为4(在32位平台时输出4,在64位平台时输出为8) 可检测平台是多少位
X86-->32位平台 X64-->64位平台
二、指针的应用
1、求数组长度
错误求法如下:
void Show(int arr[10])//实际已经退化成指针
{
sizeof(arr)/sizeof(arr[0]); //==1,不能求数组的长度
}
int main()
{
Show(arr,sizeof(arr)/sizeof(arr[0])); //int *
return 0;
}
求数组长度的正确求法,代码如下:
void Show(int *arr,int len)
{
for(int i=0;i<len;i++)
{
printf("%d ",arr[i]);
}
printf("\n");
}
2、数组元素的逆置
定义一个数组 int arr[5]={1,2,3,4,5};将其中的元素按5,4,3,2,1输出。具体代码如下:
void Reverse(int *arr,int len)
{
int tmp;
for(int i=0;i<len/2;i++)
{
tmp = arr[i]; //arr[i] == *(arr+i)
arr[i] = arr[len-1-i];
arr[len-1-i] = tmp;
}
}
int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9,10};
Reverse(arr,sizeof(arr)/sizeof(arr[0]));
return 0;
}
3、将两值a、b进行交换
以下为三种错误操作代码示例
(1)error1 未建立联系
void Swap(int a,int b) //error1
{
int tmp = a;
a = b;
b = tmp;
}
int main()
{
int a = 10;
int b = 20;
Swap(a,b);
printf("%d,%d\n",a,b);
return 0;
}
上述代码错误原因说明:子函数swap()函数中虽然将a与b进行了交换,但在主函数main()中,又对a、b进行了赋值重新定义,使子函数swap()与主函数间没有构成联系。子函数的a、b与主函数的a、b只是恰巧变量的名称相同。要想使子、主函数间建立起联系就要使用指针进行操作。后面会有介绍。
(2)error2 未解引用
void Swap(int *p1,int *p2)
{
int tmp; //没有解引用
tmp = p1;
p1 = p2;
p2 = tmp;
}
说明:①使用指针时需要进行解引用操作,指针才会起作用;
②子函数里仅修改指针的指向,不会影响父函数。需传指针、解引用。
这里为了帮助理解,引出了“子函数”、“父函数”两个概念。若函数A调用了函数B,则称函数A为父函数,函数B为子函数。
(3)error3 野指针的出现
void Swap(int *p1,int *p2)
{
int *tmp; //野指针,悬挂指针
*tmp = *p1; //由此出错,解引用出错,系统崩溃
*p1 = *p2;
*p2 = *tmp;
}
无法运行,系统崩溃。
野指针:野指针是指向一个已删除的对象或未申请访问受限内存区域的指针。与空指针不同,野指针无法通过简单地判断是否为 NULL避免,而只能通过养成良好的编程习惯来尽力减少。对野指针进行操作很容易造成程序错误。
成因:①指针变量未初始化;②指针释放后未置空。
避免方法:①初始化时置NULL;②释放时置NULL。
指针未初始化,取随机值,无法访问其值地址,无操作权限,程序无法识别野指针。应养成良好的编程习惯对其进行规避。
(4)正确代码如下:
//子函数的改变要能改变父函数,需传指针,解引用
void Swap(int *p1,int *p2)
{
int tmp;
tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
int main()
{
int a = 10;
int b = 20;
Swap(&p1,&p2);
return 0;
}