C/C++软件工程师就业求职手册学习笔记---第五章

  • 5.1 引用

  1. 引用可以看做是对象的别名,可以通过引用来操作对象,要注意,引用在声明时要初始化。

int a=10;
int&m=a;
int*p=&a;
int*&pa=p;

例子1:

char*p="abc";
char*q="def";
swap(p,q);
cout<<p<<","<<q<<endl;

输出:abc,def

因为,指针传入函数,函数内部会临时分配临时变量用于存储传进来的值,在函数返回后,临时变量销毁,不会对指针有任何操作。

若是要解决这个问题,则需要传递指针引用。

voidswap(char **,char**);

swap(&p,&q);

即可。

例子2:

float f=5;
floatf1()
{
         return f;
}
 
float&f2()
{
         return f;
}
voidmain()
{
         float c=f1();
         float &d=f2();
         float e=f2();
         float &h=f1();//error
}

其中,main 函数中第二行第三行效果相同,但是第四行会出现错误。提示为:非常量引用的初始值必须为左值。

这是因为 ,在函数内部,为全局变量f,会自动赋给临时变量,这就相当于h是对临时变量temp的引用,而临时变量用后会被销毁。

 

还有一种引用是常量引用,形如 constint &p=a;在这种情况下,不允许通过引用p修改变量a 的值,达到安全的目的。常量引用的引用对象可以是变量,

但是如果引用对象是常量,那么引用一定要为常量引用,即:

constint a=5;
int&p=a;//error
constint &p=a;//correct

例子3:

指针与引用的区别:

1、初始化要求不同。  引用在创建的同时必须初始化,而指针在创建的同时,可以不必初始化。

2、可修改性不同。    引用一旦确定,就不能再更改,而指针可以重新指向其他对象。

3、不存在NULL的引用。引用必须指向明确的对象,而指针则可以为空,也可以指向任意对象。

4、测试的区别。          引用不为空,所以测试是不需要验证其有效性,但是指针则不一定,所以需要验证其合法性。

5、应用的区别。      引用适用于指向对象后不需要更改的场景中,而指针适用于需要变换指定对象情况。

补充:指针由于存在隐患,所以安全性不如引用。

 

5.2 指针基础

例子4:

指针的定义声明:

int*p;           定义一个整型指针
int **p;         定义一个指向指针的指针
int*p[10];       定义一个有十个指针的指针数组
int(*p)[10];     定义一个有十个整数的数组指针
int*p(int a);    定义一个形参为整型的函数指针
int*p[10](int a);定义一个元素为形参是整型的函数的数组指针

 

例子5:

指针的比较:

void main()
{
         char str1[]="abc";
         char str2[]="abc";
        
         const char str3[]="abc";
         const char str4[]="abc";
        
         const char *str5="abc";
         const char *str6="abc";
        
         char *str7="abc";
         char *str8="abc";
        
         cout<<(str1==str2)<<endl;
         cout<<(str3==str4)<<endl;
         cout<<(str6==str7)<<endl;
         cout<<(str5==str6)<<endl;
         cout<<(str7==str8)<<endl;
 
}

输出为:0 0 1 1 1

这是因为“abc”是在栈中分配,是以\0结尾的字符串,所以str1和str2是不同的地址,对于str3和str4,const只是说明不可更改,不改变存储位置和方式,所以不同;

而指针str5,6,7,也在栈中分配,都指向“abc”,但是“abc”是放在数据区中的,是同一块区域。

对空指针进行内存读取会产生错误。如int*p=0;int a=*p;

注意 常量指针和 指针常量的区别: 常量指针是指向常量的指针,指针常量是类型为指针的常量。

5.2 this指针

在C++中,对象的this指针并不是对象的比部分,不会影响sizeof的结果。this 指针的作用域是累的内部,在累的静态成员函数中访问累的非静态成员时,编译器会自动将对象地址作为隐含参数传递给函数。

也就是说,没有this指针,编译器也会在运行的时候,为对象分配一个this指针。他作为非静态成员函数的隐含参数,对各个成员均可以通过this访问。

例如 : date.setMonth(9);在this指针的帮助下,可以转换为:

                  setMonth(&date,9);

this 指针的使用情况如下:

         一种是在类的非静态成员函数中返回类对象本身的时候,直接使用return *this;二是当参数名和成员变量名相同时,用来区分二者,如this->n=n;

         注意:this指针是存在于属于类的非静态成员函数中,而静态成员函数不属于类,所以不存在this指针。

例子6:

指针数组 与数组指针:

void main()
{
         char*str[]={"welcome","to","Fortemedia","Nanjing"};
         char **p=str+1;            //1
         str[0]=(*p++)+2;            //2
         str[1]=*(p+1);              //3
         str[2]=p[1]+3;              //4
         str[3]=p[0]+(str[2]-str[1]);//5
         cout<<str[0]<<","<<str[1]<<","<<str[2]<<",'<<str[3]<<endl;
}

输出为:空,Nanjing,jing,g

1行后,p指向了str[1],即“to”;

2行后,*p是指向"to"的,+2后,就指向了“to”的末尾"\0",也就是为空,然后p自增,指向了Fortemedia字符串,也就是str[2];

3行后,p+1指向Nanjing,所以str[1]为"Nanjing";

4行后,先计算等号右边,p[1]是指向“Nanjing”的,再移动三个位置,就是"jing",所以str[2]="jing",由于p此时也是指向str[2]的,所以p的内容也发生了变化,这一步的操作相当于把str[2]的子串赋给了str[2];

5行后,由于此时p指向了"jing",str[2]-str[1]=3,所以p右移三个位置的值就是str[3]的值,也就是g;

 

5.4 函数指针和指针函数

指针函数本身是一个函数,只是他的返回类型是指针,定义形式为:type *name(parameter){};

函数指针本身是一个指针,只是其类型为函数类型

5.5 野指针

野指针有两种:

1、没有初始化,默认值是随机的。

2、被free或delete后没有置为NULL,即悬垂指针。

 

new/delete和 malloc/free:

对于非内部数据类型的对象而言,对象在小王仟要自动执行析构函数。由于malloc/free函数是库函数而不是运算符,不在编译器控制权限内,不能够把执行构造函数和析构函数的任务强加给malloc/free函数是库函数而不是运算符,不在编译器控制权限内,不能够把执行构造函数和析构函数的任务强加给malloc/free

只能使用new/delete函数。

例子6:

char* get()
{
         char str[]="welcome";
         return str;
}
void main()
{
         char *p=get();
         cout<<p<<endl;
 }

输出 p可能会乱码!!!

 

void get(char *p)
{
         p=(char *)malloc(100);
}
void main()
{
         char *str=NULL;
         get(str);
}

str 并不会指向分配的存储空间,依然为NULL,而对应内存没有指针可以指向,这就会导致内存泄露。

 

例子7:

内存的分配方式:

内存分配一共有三种,分别是静态存储区、栈、堆的内存分配;

1、静态存储区分配内存。编译器在程序编译阶段就已经将内存分配好,并且在程序运行的整个过程中都一直存在。

2、栈上的内存分配。在执行函数时,函数内局部变量的存储单元可以在栈上创建,函数结束时这些存储单元自动被释放。处理器的制定集中有关于栈内存分配的运算,因此效率很高,但是分配的内存容量有限。

3、在堆上分配内存。也成为内存的动态分配。程序在运行的时候用malloc或new运算符申请任意大小的内存,程序员要用free函数或delete运算符来释放内存。动态内存分配很灵活,但问题也很多。

 

5.6 指针和句柄的区别

windows环境中,句柄是用来表示i项目的,这项目包括:

模块(module),任务(task),实力(instance),文件(file),内存块(blockofmemory),菜单(menu),控制(control),字体(font),资源(resource),包括图标,光标,字符串等,GDI对象,包括位图,画刷,原文件,掉色斑,画壁,区域以及设备描述表。

 

windows是以虚拟内存为基础的操作系统。在这种操作系统下,windows内存管理器在内存中来移动对象,从而满足各种应用程序的内存需要。对象被移动意味着他的地址发生变化。由于地址变化,windows专门为各应用程序留出一些内存储地址,

专门用来等级个应用对象在内存中的地址变化,而这些地址(存储单元)的地址本身是不变的。windows内存管理器在内存中移动对象后,把对象的新地址告知句柄地址来保存。这样只需要知道句柄的地址就可以间接的知道对象在内存中的地址,

这个地址在对象装在的时候由系统来分配,当系统卸载是有释放给系统。

因此,windows程序并不是通过物理地址来表示内存块、文件、任务或动态装入模块的,相反,windowsAPI给这些项目分配确定的句柄,并将句柄返回给应用程序,然后通过句柄来进行操作。

在windows变成中会大量使用句柄,HINSTANCE,HBITMAP,HDC(设备描述句柄),HICON图标句柄,还有一个通用句柄handle。c

程序执行的顺序是:

                                   句柄地址(稳定)-->记载对象在内存中的地址-->对象在内存中的地址(不稳定)-->实际对象

         每次程序重新启动后, 分配的句柄,并不一定是原来的句柄,很多情况下是不一样的。

 

不同之处:

 

1、句柄是一个复杂的结构,并且可以与系统有关,例如线程的句柄,他可以指向一个类或者结构,并且和系统有很密切的关系,当一个线程由于不可预料的原因二终止的时候,系统就可以返回他所占用的资料,如CPU,内存等

反之,句柄的某些项是与系统进行交互的。

2、指针也可以指向一个复杂的结构,但是通常是由晕乎定义的,所以必要的工作要由用户来完成,特别是删除部分。


第五章结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值