综述
指针在c++学习中一直是难点和重点,由于在项目中指针应用比较灵活,所以指针所引发的问题比较多,最近针对指针进行重点学习。有人说,掌握指针,也就掌握c语言的精髓。c++中当然也有指针,同时还包括继承、多态等等。
内存四区
没有内存,就没有指针,在理解指针的开始阶段,先重点讲解内存五区。
如上图所示:一般下理解内存分为栈、堆、常量区、代码区、全局区。
栈:程序中局部变量、参数包括形参、数组、指针存放在栈中,编译器在函数调用结束后,自动释放,所以注意指针的指向。
堆:程序员手工申请的内存(molloc,new),一般堆内存比栈内存大,在大数据处理中,可以利用堆,进行数据存储、计算。
常量区:包括常量、字符串常量,指针指向此区,不能修改常量值
代码区:存放函数体的二进制代码。
全局区:全局变量和静态变量存储放在一块,在程序结束后自动释放。
int a = 0;//a全局初始化区 char * p ;//全局未初始化区 int main() { int b;//因为在函数中,在栈中申请内存 int inum = 0;//首先在常量区分配内存存放0,然后在栈中分配内存存放inum,最后将0赋值给inum。0 在程序结束后自动释放。 int a[10];//在栈中分配了一个数组,有连续的内存空间放int型数据,内存为40字节 char *p1;//在栈分配内存,指针是四个字节,此时没有向指针变量中赋值,也就是没有指向内存,此时操作这个指针会报错。 char *p3 = "1234124";//首先常量区分配内存存放字符串常量,用指针*p3,指向这块内存空间,只能访问。如果用 *p3 = "23";编译会报错,常量区不可修改啊 static int a1 = 0;//全局去(静态区) p1 = new char(); //通过了new和molloc 了在分配字节在堆中,当然指针在栈中。 int *p4 = new int[10];//在堆中分配内存为40字节。 }
栈和堆
堆和栈在程序到底有什么不同,当然从表面上可以看到两者因为申请方式不一样,可以清晰知道两者的区别。那在内存中具体的不同有哪些。
1. 管理方式不同
栈是编译器自动管理,堆需要我们手工创建,手工释放。在程序中,一般通过内存的指针进行释放,所以指向堆的指针指向千万不能变化。要有一个指针保存申请内存的首地址。
- 空间大小不同
一般在32位操作系统下,栈的内存一般都是一定的空间的大小的,在vc6下面默认的空间大小是1M,而堆的大小可以达到4G空间,从这个角度上讲堆内存几乎没有限制。 - 碎片问题
对于堆来讲,因为经常new/delete操作,造成内存空间不连续,造成大量的内存碎片,使程序效率低下。栈就没有这种问题。 - 生长方向
堆是向上生长,栈向下生长。意味在程序中申请栈和堆的内存时,内存地址变化方向不一样。栈中变量申请越往后,地址越小。 - 分配方式
堆是动态分配,没有静态分配的堆。栈有2中分配方式,静态分配就是常见的局部变量声明。动态分配有alloca分配,系统自动回收。 - 分配效率
栈由机器系统提供的数据结构,计算机底层对栈支持:专门的寄存器存放栈的地址,有压栈出栈指令执行,决定栈的效率较高。堆是由c++函数库提供,机制比较复杂,如果没有足够内存空间(碎片过多),极有可能调用系统功能去增加程序数据段的内存空间,然后再返回。显然堆的效率比较低下。
在程序中大量使用new/delete,容易造成大量内存碎片,效率低下。栈在程序中应用最广泛,就是函数调用也是通过栈完成,函数调用过程的参数,返回地址和局部变量采用栈的方式存放。
指针理解
没有内存,就没有指针,这句话充分说明指针的本质和作用。在系统中如果指针指向的内存空间没有内存,肯定报错,另一方面,利用指针去修改只读内存的内容,也是报错的。如果理解指针,必须从四个方面理解:1、指针类型;2、指针指向变量的类型;3、指针的值或者说指向内存空间地址;4、指针本身占据的内存区。
- 指针类型和指针指向的类型
首先指针是变量,是一种特殊的变量,它里面存储的数值被解释为内存里的一个地址,在指针变量加*后,就可以获取或操作指向内存空间的值。这样通过指针操作内存中数据便很方便。
下面举例说明下
int* ptr;//指针的类型是:int* char* ptr;//指针的类型是:char* int ** ptr;//指针的类型是:int** int (*ptr)[];//指针的类型是:(*)[] int *(*ptr)[];//指针的类型是:*(*)[]
找出指针的类型很简单,关键是指针指向的类型。当你同过指针来访问指针所指向的内存区时,指针指向的类型决定了编译器吧内存里内容当做什么看待。从语法看看,只需要把指针声明语句中*,去掉,便得知。
int (*ptr)[3]//指针指向类型为int()[3],意味着*(ptr+1)时,内存跳转大小是3*sizeof(int),而不是sizeof(int)了,这是指向数组的指针。
指针的类型和指针指向的类型很不一样,我们常常关心指针指向的类型。
- 指针的值和指针指向的值
指针的值是指指针本身存储的数值,由于在32位程序中,指针的值就是个32位整数,所以指针占据4个字节。我们说指针的值是XX,就是指针指向了以XX为首地址的一片内存区域。
指针指向的值就是指向内存空间中的值,也可以是函数指针奥。
指针常量和常量指针
在C/C++中关键字const用来定义一个只读的变量或者对象,有如下优点
(1)便于类型检查,如函数的函数 fun(const int a) a的值不允许变,这样便于保护实参。
(2)功能类似与宏定义,方便参数的修改和调整。如 const int max = 100;
(3)节省空间,如果再定义a = max,b=max。。。就不用在为max分配空间了,而用宏定义的话就一直进行宏替换并为变量分配空间
(4)为函数重载提供参考
首先一定要明白哪种定义方式是常量指针,哪种是指针常量,这里可以记住三句话加深记忆:
- (指针)和 const(常量) 谁在前先读谁 ;*象征着地址,const象征着内容;谁在前面谁就不允许改变。
int a =3; int b = 1; int c = 2; int const *p1 = &b;//const 在前,定义为常量指针 int *const p2 = &c;//*在前,定义为指针常量
常量指针p1:指向的地址可以变,但内容不可以重新赋值,内容的改变只能通过修改地址指向后变换。
p1 = &a是正确的,但 *p1 = a是错误的。
指针常量p2:指向的地址不可以重新赋值,但内容可以改变,必须初始化,地址跟随一生。
p2= &a是错误的,而*p2 = a 是正确的。
版权声明:本文为博主原创文章,未经博主允许不得转载。