什么是指针:
指针是一种特殊的数据类型,使用它可以定义指针变量,指针变量中存储的是整型数据,代表了内存的编号,通过这个编号可以访问到对应的内存。
为什么使用指针:
1、由于函数与函数之间是相互独立的,但是有些时候需要共享变量
传参是单向值传递
全局变量尽量少用,容易命名冲突
使用数组还需要传递长度
函数的命名空间是相互独立的,但是地址空间是同一个,所以指针可以解决这个问题
2、由于函数传参是值传递(内存拷贝),对于字节数较多的变量,值传递的效率比较低,如果传递的是变量的地址,只需要传递4|8个字节。
3、堆内存无法取名,它不像stack、bss、data让变量名和内存建立关系,只能使用指针来记录堆内存的地址编号从而使用该堆内存。
如何使用指针:
定义: 类型* 变量名_p;int* p;
1、指针变量与普通变量的用法上有很大的区别,为了以示区分,建议在变量名后面加上_p。
2、指针的类型表示该指针变量储存的是什么类型变量的地址,指针的类型决定了可以通过指针变量访问的字节数。
3、一个*只能定义一个指针变量
int* p1,p2,p3;(只有p1是指针,p2,p3 是int)
int* p1,*p2, *p3;(都是指针)
4、指针变量与普通变量一样的是默认值是随机的,一般初始化为NULL
赋值(引用): 变量名 = 地址;
指向栈内存:
int num;
int* p = & num;
int* p = NULL;
p = & num;
指向堆内存:
int* p = NULL;
p = malloc(4);
解引用: *p = 1000;
通过指针变量中记录的内存编号来访问对应的内存,该过程可能会产生段错误,但是原因是存储了非法的内 存编号。
注意:访问的字节数是由指针变量的类型解决的。
int num = 10;
int* p = NULL;//初始化
p = #//赋址
*p = 100;//赋值
num = 100;//*p就等于num
void func(int* p)
{
*p = 10;
printf("%d %p\n",*p,p);
}
int main()
{
int num = 0;
func(&num);
printf("%d %p\n",num,&num);
}
使用指针需要注意的问题:
空指针:
值是NULL的指针变量都是空指针,如果对空指针进行解引用产生段错误
NULL也是一种错误标志,如果一个函数返回值是指针类型时,当函数执行出错可以返回NULL表示该函数执行 错误。
注意:NULL在绝大多数的系统中都是0,在个别系统是1
if(NULL==p) 等价于 if(!p)
如何避免空指针带来的段错误:
使用来历不明的指针之前先做判断是否是空指针
1、当函数的参数是指针时,别人传给你的可能就是空指针
2、当函数获取返回值时,也有可能获取到空指针
野指针:
指针的指向不确定的内存的指针。
野指针的危害:
1、段错误
2、脏数据
3、一切正常
野指针危害比空指针更严重,因为它无法判断出来,而且可能是隐藏性的错误,短时间内不暴露
如何避免:
1、定义指针时一定要初始化
2、函数不返回局部变量地址
3、指针指向的内存被释放后,指针变量立即置空 = NULL
指针的运算:
绝大多数无意义。
指针+n: 指针+指针类型宽度*n
指针 -n: 指针 -指针类型宽度*n
指针-指针:(指针-指针)/ 指针类型宽度 计算出两个指针直接相隔多少个指针元素
指针与const
当我们为了提高传参效率而使用指针时,传参效率虽然提高了,但是变量也有被修改的风险,这种写法就可以保护指针不被修改。
const int* p; || int const* p
const 靠近谁就保护谁
int* const p;保护指针变量(地址)不被修改
const int* const p;都保护
int const * const p;都保护
练习:实现一个变量交换的函数,调用它对一个数组排序
#include <stdio.h>
void swap(int* a,int* b)
{
int t = 0;
t = *a;
*a = *b;
*b = t;
}
int main(int argc,const char* argv[])
{
int arr[10] = {5,62,9,3,1,4,7,484,69,32};
for(int i = 0;i<9;i++)
{
for(int j = i+1;j<10;j++)
{
if(arr[i]>arr[j])
{
swap(&arr[i],&arr[j]);
}
}
}
for(int i = 0;i<10;i++)
{
printf("%d ",arr[i]);
}
}
练习:实现一个函数,计算两个整数的最大公约数、最小公倍数,最大公约数用return返回,最小公倍数使用指针处理。
#include <stdio.h>
int com(int a,int b,int* p)
{
int max = 0,min = 0;
for(int i = 1;i <= a; i++)
{
if(0 == a%i && 0 == b%i)
{
max = i;
}
}
for(int i = a*b; i >= a; i--)
{
if(0 == i % a && 0 == i % b)
{
*p = i;
}
}
return max;
}
int main(int argc,const char* argv[])
{
int a = 28,b = 7;
int gbs = 0;
int gys = com(a,b,&gbs);
printf("%d %d",gbs,gys);
}
#include <stdio.h>
int com(int a,int b,int* p)
{
if(a>b)
{
int t = a;
a = b;
b = t;
}
int z = a;
int m = a,n = b;
while(a % b != 0)
{
z = a % b;
a = b;
b = z;//辗转相除法,z就是最小公因数
}
*p = z;
int x = m*n/z;
return x;
}
int main(int argc,const char* argv[])
{
int a = 0,b = 0;
printf("请输入两个数:");
scanf("%d%d",&a,&b);
int gbs = 0;
int gys = com(a,b,&gbs);//当需要返回两个值的时候使用指针
printf("%d %d",gbs,gys);
}