C语言精髓 指针

概念

指针:数据内存中的地址; 指针变量:如果一个变量存储了一份数据的指针;
指针的值是地址;
1、任何一个变量都有一个地址,变量类型不同占用的地址单元数量不同;
2、指针也是一个变量,所以它也有地址;
3、给指针赋值是让指针变量指向与其同类的一个数据变量的地址;
4、没有赋值的空指针其指向不确定,所以绝对不能在程序中使用;

定义&赋值

int *p;  //p是一个整数类型的指针变量
int a=5;
p=&a;   // &为取地址符号符
*p=5;   // *用来获取指针指向的数据

空类型指针

void指针是空类型指针,它不指向任何类型,即void指针仅仅是一个地址,所以空类型指针不能进行指针运算,也不能进行间接引用(因为指针运算和间接引用都需要指针的类型信息)。

数组指针和指针数组

int *p1[5]// 指针数组
int (*p2)[5]// 数组指针

语句“intp1[5]”,因为“[]”的优先级要比“”要高,所以 p1 先与“[]”结合,构成一个数组的定义,数组名为 p1,而“int*”修饰的是数组的内容,即数组的每个元素。也就是说,该数组包含 5 个指向 int 类型数据的指针,如图 1 所示,因此,它是一个指针数组。
在这里插入图片描述
语句“int(p2)[5]”,“()”的优先级比“[]”高,“”号和 p2 构成一个指针的定义,指针变量名为 p2,而 int 修饰的是数组的内容,即数组的每个元素。也就是说,p2 是一个指针,它指向一个包含 5 个 int 类型数据的数组,如图 2 所示。很显然,它是一个数组指针,数组在这里并没有名字,是个匿名数组。
在这里插入图片描述
代码示例:

int arr[5]={12345};
int (*p1)[5] = &arr;
/*下面是错误的*/
int (*p2)[5] = arr;

在 C 语言中,赋值符号“=”号两边的数据类型必须是相同的,如果不同,则需要显示或隐式类型转换。在这里,p1 和 p2 都是数组指针,指向的是整个数组。p1 这个定义的“=”号两边的数据类型完全一致,而 p2 这个定义的“=”号两边的数据类型就不一致了(左边的类型是指向整个数组的指针,而右边的数据类型是指向单个字符的指针),因此会提示错误信息。

值交换

事例一:
值仅在Swap函数里完成了交换
当形参和实参不是指针类型时,在该函数运行时,形参和实参是不同的变量,他们在内存中位于不同的位置,形参将实参的内容复制一份,在该函数运行结束的时候形参被释放,而实参内容不会改变。

void Swap(int *a1,int *b1)
{
    int *tmp=a1;
    a1=b1;
    b1=tmp;
    qDebug("a1:%d,a1:%x",*a1,a1); // a1:7,a1:80fd7c
    qDebug("b1:%d,b1:%x",*b1,b1); // b1:5,b1:80fd80
}

main()
{
	int de=5;
    int si=7;
    qDebug("de:%d,de:%x",de,&de); // de:5,de:80fd80
    qDebug("si:%d,si:%x",si,&si); // si:7,si:80fd7c 
    Swap(&de,&si);
    qDebug("de:%d,de:%x",de,&de); // de:5,de:80fd80
    qDebug("si:%d,si:%x",si,&si); // si:7,si:80fd7c
}

事例二:
值完成了交换
如果函数的参数是指针类型变量,在调用该函数的过程中,传给函数的是实参的地址,在函数体内部使用的也是实参的地址,即使用的就是实参本身

void Swap(int *a1,int *b1)
{
    int tmp=*a1;
    *a1=*b1;
    *b1=tmp;
    qDebug("a1:%d,a1:%x",*a1,a1);  // a1:7,a1:80fd80
    qDebug("b1:%d,b1:%x",*b1,b1);  // b1:5,b1:80fd7c
}

main()
{
    int de=5;
    int si=7;
    qDebug("de:%d,de:%x",de,&de);  //  de:5,de:80fd80
    qDebug("si:%d,si:%x",si,&si);  //  si:7,si:80fd7c
    Swap(&de,&si);
    qDebug("de:%d,de:%x",de,&de);  //  de:7,de:80fd80
    qDebug("si:%d,si:%x",si,&si);  //  si:5,si:80fd7c
}

形参和实参不是指针类型时,在该函数运行时,形参和实参是不同的变量,他们在内存中位于不同的位置,形参将实参的内容复制一份,在该函数运行结束的时候形参被释放,而实参内容不会改变。
如果函数的参数是指针类型变量,在调用该函数的过程中,传给函数的是实参的地址,在函数体内部使用的也是实参的地址,即使用的就是实参本身。所以在函数体内部可以改变实参的值。

附录A

  • 野指针:就是指针指向的位置是不可知的,指向的位置可能不能访问,触发段错误。
  • 怎么避免野指针:在指针解引用之前,要确保指针指向一个绝对可用的空间

1.在定义指针时,同时初始化为NULL;
2.在解引用之前先判断这个指针是不是NULL;
3.使用完后再将其赋值为NULL;
4.在使用指针前,先将其赋值绑定一个可用的地址空间

  • const: C语言中采用const修饰变量功能是对变量声明为只读特性,并保护变量值以防止修改。定义变量的同时,必须初始化。定义形式为 const int a=5;const修饰变量起到节约空间的目的,通常编译器并不给普通const只读变量分配空间,而是将它们保存在符号表中,无需读写内存操作,提高程序执行效率。

https://blog.csdn.net/wpx201314/article/details/50779437

附录B

内存泄漏

http://www.360doc.com/content/20/0331/13/64183406_902857437.shtml

附录C

二级指针
https://blog.csdn.net/majianfei1023/article/details/46629065
二级指针的三种用法
https://blog.csdn.net/qq_20079763/article/details/80612220

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值