概念
指针:数据内存中的地址; 指针变量:如果一个变量存储了一份数据的指针;
指针的值是地址;
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]={1,2,3,4,5};
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