深入C/C++系列:指针

来源:互联网 发布:陈意涵angelababy知乎 编辑:程序博客网 时间:2024/06/06 17:08

指针变量

一 :关于指针和堆(见C/C++程序中的堆与栈)的内存分配 先来介绍一下指针 :

指针一种类型,理论上来说它包含其他变量的地址,因此有的书上也叫它:地址变量。既然指针是一个类型,是类型就有大小,在达内的服务器上或者普通的 PC机上,都是4个字节大小,里边只是存储了一个变量的地址而已。不管什么类型的指针,char * ,int * ,int (*) ,string * ,float * ,都是说明了本指针所指向的地址空间是什么类型而已,了解了这个基本上所有的问题都好象都变的合理了。

但要注意的是:这种地址变量与普通变量有很大的不同,如:

       1、指针只能在各种类型的指针中进行转换,而不能将一个指针赋给一个整型或其他类型变量。

       2、指针不能像普通变量那样自由的进行各种算术运算,但可以进行自加、自减或加(减)一个整数。                       这是它具有独特的意义:将指针变量改变 “n×sizeof(type)"个字节,也就是说:这时的运算是将指针                       指向前一个,后一个或后(前)面第几个该类型的数据。

C++中,申请和释放堆中分配的存贮空间,分别使用newdelete的两个运算符来完成:

指针类型 指针变量名=new 指针类型 (初始化)

delete 指针名;

例如:1int *p=new int(0); 它与下列代码序列大体等价:

2int tmp=0, *p=&tmp;

区别:p所指向的变量是由库操作符new()分配的,位于内存的堆区中,并且该对象未命名。

下面是关于new 操作的说明 : 部分引自<<C++面向对象开发>>

1new运算符返回的是一个指向所分配类型变量(对象)的指针。对所创建的变量或对象,都是通过该指针来间接操作的,而动态创建的对象本身没有名字。

2、一般定义变量和对象时要用标识符命名,称命名对象,而动态的称无名对象(请注意与栈区中的临时对象的区别,两者完全不同:生命期不同,操作方法不同,临时变量对程序员是透明的)

3、堆区是不会在分配时做自动初始化的(包括清零),所以必须用初始化式(initializer)来显式初始化。new表达式的操作序列如下:从堆区分配对象,然后用括号中的值初始化该对象。

 

下面是从堆中申请数组

1、申请数组空间: 指针变量名=new 类型名[下标表达式];

注意:下标表达式不是常量表达式,即它的值不必在编译时确定,可以在运行时确定。这就是堆的一个非常显著的特点,有的时候程序员本身都不知道要申请能够多少内存的时候,堆就变的格外有用。

2、释放数组空间: delete [ ]指向该数组的指针变量名;

注 意:方括号非常重要的,如果delete语句中少了方括号,因编译器认为该指针是指向数组第一个元素的,会产生回收不彻底的问题(只回收了第一个元素所占 空间),我们通常叫它内存泄露,加了方括号后就转化为指向数组的指针,回收整个数组。delete [ ]的方括号中不需要填数组元素数,系统自知。即使写了,编译器也忽略。<<Think in c++>>上说过以前的delete []方括号中是必须添加个数的,后来由于很容易出错,所以后来的版本就改进了这个缺陷。

 

下面是个例子,VC上编译通过

#include<iostream>

using namespace std;

 //#include <iostream.h>

//for VC

 #include <string.h>

 void main()

{

int n;


char *p;

cout<<"请输入动态数组的元素个数"<<endl;

cin>>n; //n在运行时确定,可输入17

p=new char[n]; //申请17个字符(可装8个汉字和一个结束符)的内存空间

strcpy(p,“堆内存的动态分配”);//

cout<<p<<endl;

delete []p;//释放p所指向的n个字符的内存空间return ;

}

函数指针

#include "iostream.h"
void func(int i)
{
cout<<"This is for test "<<i<<"/r/n";
}
typedef void (*PFUNC)(int);
struct FUNC
{
PFUNC pfunc;
};
void callfunc(void pfunc(int),int i)
{
pfunc(i);
}
void funpt()
{
void (*pfunc)(int); //定义函数指针
pfunc=&func; //等同与pfunc=func;函数名本身就是地址常量
pfunc(1);
callfunc(pfunc,2);
FUNC sfunc;
sfunc.pfunc=&func;
sfunc.pfunc(3);
/*//
void *pf;//=NULL;//error
pf=func;
pf(1);
*/
int fn1(char x,char y);
int fn2(int a);
int (*fp1)(char a,char b);
int (*fp2)(int s);
fp1=fn1; //ok
// fp1=fn2; //error

fp2=fn2; //ok
// fp2=fn1; //error
}
int fn1(char x,char y)
{
cout<<"fn1"<<endl;
return 0;
}
int fn2(int a)
{
cout<<"fn2"<<endl;
return 0;
}
int main(int argc, char* argv[])
{
funpt();
int (*pf1)(char x,char y); //函数指针的定义
pf1=&fn1; //函数指针的赋值,同pf1=fn1;
int (*pf2)(int a)=fn2; //函数指针的初始化
pf1('x','a'); //函数指针的调用
pf2(1);
return 2;
}

原创粉丝点击