【摘要】
指针可以指向变量、数组、字符串、函数、甚至结构体。即指针可以指向不同数据对象。指针问题 包括 常量指针、数组指针、函数指针、this指针、指针传值、指向指针的指针 等。主要知识点包括:1.指针与引用在概念上的三个区别及其在const、sizeof、自增运算上的差异;2.熟记经典swap函数的指针实现与引用实现,并能反映输出错误的两个函数的思想弊端;3.熟记GetMem函数的错误形式以及错误产生的原因;4.比较数组、指针与静态变量作为函数返回值的差异;5.str、*str以及&str三者的关系;6.指针继承复指向中虚函数、实函数及变量间的关系;7.写出const指针,指向const的指针,指向const的const指针;8.分析高维数组指针与高维数组在取址上的差别;9.区分悬浮指针与空指针;10.new和malloc的常见问题,本质区别,为什么产生new,为什么不提出malloc;11.this指针3个点,为什么会有this,this什么时候用,this怎么传给函数的;12.句柄和智能指针。考点:指针与引用的区别
int &ref; // 错误,引用不能为空且需要同时初始化,因此错误! int *p = 5; // 错误,指针位置向实际内存空间,赋值之后不知道存放的地址,没有指向,因此错误! int *ptra,*ptrb; int ptra = *ptrb; // 错误,指针位置向实际内存空间,赋值之后不知道存放的地址,因此错误! const int num; // 错误,const 常量赋值必须同时初始化,因此错误!考点:经典的 swap(int &a,int &b)函数
void GetMemA(char *p,int num) { p = (char*)malloc(sizeof(char)*num); } void GetMemB(char **p,int num) { *p = (char*)malloc(sizeof(char)*num); }
【解析】
因为,函数不能传值只能传址,所以,在函数内采用指针申请内存空间(即,void GetMem(char *p,int num))是不会成功的。那么为实现空间申请我们应该采用指向指针的指针(即,void GetMem(char **p,int num))。
假设,在 main() 函数中,变量 p 地址为 1 指向地址为 2(可以想象成变量 p 值为 2),*p 地址为 2 指向地址为 3(可以想象成变量 *p 值为 3),**p 地址为 3 存放一 char 型变量。
在 void GetMemA(char *p,int num)中,暂时称函数变量为 GetMemA.p 吧,很明显 GetMemA.p 是一个地址,指向一个 char 型变量。函数申请栈区进入函数后,GetMemA.p 地址为 4 ,指针变量获取一块长度为 num 的 char 型内存空间。函数调用结束,弹栈销毁 变量GetMemA.p 及其申请的空间,那么,主函数中的变量 p 没有得到任何改变;
在 void GetMemB(char **p,int num)中,暂时称函数变量为 GetMemB.*p 吧,很明显 GetMemB.*p 是一个地址,指向一个 char 型变量。函数申请栈区进入函数后,GetMemB.*p 地址为 5 ,指针变量获取一块长度为 num 的 char 型内存空间。函数调用结束,弹栈销毁 变量 GetMemB.p 及其申请的空间(注意,这里是变量 GetMemB.p 而不是 变量 GetMemB.*p),那么,GetMemB.*p 自然而然的保留了申请得到的内存空间,主函数中的变量 p 没有得到任何改变,而 *p 获得了一段长度为 num 的 char 型内存空间;
当然,函数还可写成这样直接返回内存空间。
char* GetMemC(char *p,int num) { p = (char*)malloc(sizeof(char)*num); }【整型数据的源码传递】
#include <iostream> using namespace std; void GetMemory2(int *z) { *z=5; }; int main() { int v; GetMemory2(&v); cout << v << endl; return 0; }【注】
char *strA() { char str[] = "hello world"; return str; }解析:
char *strA() { char *str = "hello world"; return str; }首先要搞清楚char *str 和 char str[] :
char *strA() { static char str[] = "hello world"; return str; }通过static开辟一段静态存贮空间。
【另】
char *str = “hello”;#include ... class A{ ... }; class B{ ... }; int main( ) { A a; B *pb = (B*)(&a); }【解析】
#include ... int main( ) { int *ptr; ptr = (int*)0x8000; *ptr = oxaabb; }【解析】
#include<iostream> using namespace std; struct S { int i; int *p; } main( ) { S s; int *p = &s.i; p[0] = 1; p[1] = 5; cout<<"s 的地址 \t"<<&s<<endl; cout<<"s.i 的地址 \t"<<&s.i<<endl; cout<<"p 的值 \t\t"<<p<<endl; cout<<"p[0] 的地址 \t"<<&p[0]<<endl; cout<<"s.p 的地址 \t"<<&s.p<<endl; cout<<"p[1] 的地址 \t"<<&p[1]<<endl; cout<<"s.i 的值 \t"<<s.i<<endl; cout<<"s.p 的值 \t"<<s.p<<endl; cout<<"*s.p 的值 \t"<<"报错"<<endl; cout<<"s.*p 的值 \t"<<"报错"<<endl; cout<<"&s.*p 的值 \t"<<"报错"<<endl; s.p = p; cout<<"************************"<<endl; cout<<"执行s.p = p; \t"<<"之后"<<endl; cout<<"************************"<<endl; cout<<"s 的地址 \t"<<&s<<endl; cout<<"s.i 的地址 \t"<<&s.i<<endl; cout<<"p 的值 \t\t"<<p<<endl; cout<<"p[0] 的地址 \t"<<&p[0]<<endl; cout<<"s.p 的值 \t"<<s.p<<endl; cout<<"s.p 的地址 \t"<<&s.p<<endl; cout<<"s.p[0] 的值 \t"<<s.p[0]<<endl; cout<<"s.p[1] 的值 \t"<<s.p[1]<<endl; cout<<"p[1] 的地址 \t"<<&p[1]<<endl; cout<<"p[0] 的值 \t"<<p[0]<<endl; cout<<"p[1] 的值 \t"<<p[1]<<endl; s.p[1] = 1; cout<<"************************"<<endl; cout<<"执行s.p[1] = 1;\t"<<"之后"<<endl; cout<<"************************"<<endl; cout<<"s.p = "<<s.p<<endl; cout<<"s.p+1 = "<<s.p+1<<endl; // cout<<"*s.p = "<<*s.p<<endl; // 崩溃 }【代码输出】
s 的地址 0018FF40 s.i 的地址 0018FF40 p 的值 0018FF40 p[0] 的地址 0018FF40 s.p 的地址 0018FF44 p[1] 的地址 0018FF44 s.i 的值 1 s.p 的值 00000005 *s.p 的值 报错 s.*p 的值 报错 &s.*p 的值 报错 ************************ 执行s.p = p; 之后 ************************ s 的地址 0018FF40 s.i 的地址 0018FF40 p 的值 0018FF40 p[0] 的地址 0018FF40 s.p 的值 0018FF40 s.p 的地址 0018FF44 s.p[0] 的值 1 s.p[1] 的值 1638208 p[1] 的地址 0018FF44 p[0] 的值 1 p[1] 的值 1638208 ************************ 执行s.p[1] = 1; 之后 ************************ s.p = 00000001 s.p+1 = 00000005 Press any key to continue【代码分析】
int *p = &s.i; // 等价于 p = &p[0] = &s = &s.i // 且还有 p+1 = &p[1] = &s+1 = &s.i+1 = &s.p s.p = p; // 要知道 (s.*p) = s.p = p // 等价有 *(p+1) = *&p[1] = *&s+1 = *&s.i+1 = *&s.p = p // 简化得 *(p+1) = p[1] = s+1 = s.i+1 = s.p = p // 已知道 p = &p[0] = s.p = &s.p[0] // 所以有 &p[0] = p[1] 和 &s.p[0] = s.p[1] s.p[1] = 1 // 此时再给,s.p[0]或者p[0]赋值,等价于在内存地址为 1 的空间写入变量。 // 所以,此句暂时不会报错,一旦对指向地址赋值,就会导致程序崩溃。考点:各种类型的指针表示
注
函数指针声明方式int *ptr(int,int) = &max;
详见:
详址:
http://blog.csdn.net/u013630349/article/details/44998689
http://blog.csdn.net/u013630349/article/details/44195523
http://blog.csdn.net/u013630349/article/details/45098899
int a[] = {1,2,3,4,5};
int *ptr = (int*)(&a+1);
printf("%d %d", *(a+1), *(ptr-1));
说明:*(a+1) 直接就为2 简单&a+1 由于本身a就为数组名也就是指针,加上& 相当于双指针 也就相当于**(a+1) 所以加1 就是数组整体加一行,ptr指向a的第6个元素,所以*(ptr-1)为5
详址:http://blog.csdn.net/u013630349/article/details/45098899
悬浮指针为申请了内存,经过一系列操作,释放内存后的指针。指针虽不再指向固定内存,但是,指针还是存在,且指向随机区域,此时对指针操作十分危险的。
malloc free new delete 的区别、比较、分析
详见:C++ 中 malloc/free 与 new/delete 浅析
详址:http://blog.csdn.net/u013630349/article/details/44947255
详址:http://blog.csdn.net/u013630349/article/details/46412485
C++的编译系统只用了一段空间来存放在公共函数代码,在调用各个对象的成员函数时,都要调用这个公共的函数代码版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/u013630349/article/details/47457303