C++C++ 指针(二)--c++ 指针(二)--c++
一、内存管理:new和delete
1、new操作符:从操作系统获得内存块,并返回该内存块的首地址。
delete操作符:将new申请的内存返还给操作系统。
开始一个简单的例子:
#include <iostream>#include<cstring>using namespace std;int main(){ char* str="it is a good job!"; int len=strlen(str); char* ptr=new char[len+1]; strcpy(ptr,str); //ptr=str; //错误,这样是ptr和str都指向字符串。这里ptr和str应该指向不同的地址。 cout<<"ptr="<<ptr<<endl; delete[] ptr; return 0;} |
| char* | ptr | = | new | char | [len+1] |
|
指针 |
= |
关键字 |
变量的数据类型 |
char类型变量的数目(方括号) |
new和malloc:new方法可以返回适当的数据类型的指针;而malloc返回的指针是void类型的指针,必须强制转化才能转化成适当的数据类型指针。
2.使用new的类
#include<iostream>using namespace std;class String{public: String(char* s) { int len=strlen(s); str=new char[len+1]; strcpy(str,s); } ~String() { cout<<"where?"<<endl; delete[] str; } void display() { cout<<str<<endl; }private: char* str;};int main(){ String str="hello! word!"; str.display(); return 0; } |
1)在构造函数中使用new获得内存空间。
2)既然使用new来分配内存空间,因而析构函数也变得很重要。(因为在创建对象的时分配了内存空间,则当这些对象不再需要时就很有必要释放这些空间)。析构函数在对象销毁时自动调用的例程,所以放入delete恰好。
问题:如果一个类的两个对象执行了s1=s2这样的操作(即出现两个对象的指针指向同一个内存地址),而此时一个对象被删除(如含有其中一个对象的调用函数结束后返回时),这样申请的内存地址被收回,这样就导致另一个对象的是一个无效的指针了。
这个错误一定要重视,因为很容易疏忽。怎样才能写一个更聪明的析构函数呢?? 后面揭晓…
二、对象与指针
1、对象指针
有时在程序的编写时并不知道需要创建多少个对象。当出现这中情况时,就可以在程序运行中使用new来穿件对象。这里,new返回的是一个指向未命名对象的指针。
例子:
#include<iostream>using namespace std;class Distance{public: void getdist(); void showdist();private: int feet; float inches;};void Distance::getdist(){ cout<<"Enter the feet:"; cin>>feet; cout<<"Enter the inches:";cin>>inches;}void Distance::showdist(){ cout<<"The feet:"<<feet<<endl; cout<<"The inches:"<<inches<<endl;}int main(){ Distance dd; dd.getdist(); dd.showdist(); Distance* ptr=new Distance; // pointer to Distance,points to new Distance object ptr->getdist(); //这里如果是点运算符就会出错 ptr->showdist(); //因为点运算符要求它的左运算符是一个变量,而ptr为一个指针。 return 0;} |
上面标注的地方除了用成员访问运算符(->)表示之外,我们还可以这样(*ptr).getdist(); //ok,but inelegant (圆括号是必须的,因为点运算符的优先级比间接引用运算符要高).
2、对象指针数组
Distance* distptr[100];distptr[j]=new Distance;//*(distptr+j)=new Distance;distptr->getdist();distptr->showdist(); |
注意:数组表示法distptr[j]等价于指正表示法*(distptr+j),由于是指针数组,上面两种表示的方法的元素还是指针(指向对象的指针)
distptr->getdist(); 表示执行了由数组distptr的第j个元素 所指向的Distance对象的成员函数。
三、链表
链表提供了一种不使用数组但更为灵活的存储系统,每个数据项都是按照需要通过new来获取的,且数据之间是通过指针链接起来的。
单个数据项之间并不需要和数组元素一样在内存中相邻分配,相反他们可以分散到任何地方。
例子:
#include <iostream>using namespace std;struct link{ int data; //表示对象的单个数据项 link* next; //指向下一个链接项};class linklist{public: linklist():first(NULL) {} void addlist(int d); //增加链接项 void display(); //显示链接内容private: link* first;};void linklist::addlist(int d) //增加链接项{ link* newptr=new link; //创建一个新的link结构类型 newptr->data=d; //将参数的值传递给结构变量data newptr->next=first; //指针next指向first指向的任何地址(在这里是链表头) first=newptr; //将指针first指向这个新的链接项}void linklist::display(){ link* nowptr=first; while (nowptr!=NULL) { cout<<nowptr->data<<endl; nowptr=nowptr->next; //指针移动到下一个链表的地址 }}int main(){ linklist ll; ll.addlist(22); ll.addlist(33); ll.addlist(44); ll.display(); return 0;} |
注意:在使用link结构的时候含有一个指向同类型结构的指针。同样的在类中也可以这么使用:
class sampleclass{ sampleclass* ptr; //this is fine! sampleclass obj; //can't do this!!}; |
但是这里要特别注意:虽然类中可以包含一个指向同类型对象的一个指针,但不能包含一个同类的对象。
四、指向指针的指针
看个例子:
#include<iostream>#include <string>using namespace std;class person{public: void SetName() { cout<<"Enter name:"; cin>>name; } void PrintfName() { cout<<name; } string GetName() { return name; }private: string name;};int main(){ void bsort(person**,int); //排序 person* perptr[100]; int n=0; char ch; do { *(perptr+n)=new person; (*(perptr+n))->SetName(); n++; cout<<"Enter another?"; cin>>ch; } while (ch=='y'); cout<<"姓名排序前:"; for (int j=0;j<n;j++) { perptr[j]->PrintfName(); cout<<" "; } bsort(perptr,n); cout<<"\n姓名排序后:"; for (int j=0;j<n;j++) { perptr[j]->PrintfName(); cout<<" "; } cout<<endl; return 0;}void bsort(person** ptr,int n) //排序{ void order(person**,person**); int j,k; for(j=0;j<n-1;j++) for(k=j+1;k<n;k++) order(ptr+j,ptr+k);}void order(person** ptr1,person** ptr2) //比较{ if((*ptr1)->GetName()>(*ptr2)->GetName())) { person* tem; tem=*ptr1; *ptr1=*ptr2; *ptr2=tem; }} |
1)注意到数据类型person**,表示这些参数被用来传递perptr指针数组的地址。本身perptr数组中存的就是指针,因此指针数组的地址是一个指向指针的指针。
2)因为数组perptr包含的是指针,因而:perptr[j]->PrintfName(); 表示执行perptr数组的j号元素所指向的对象的PrintfName()成员函数。
3)(*ptr1)->GetName();
其中ptr1是一个指向指针的指针,因此(*ptr1)表示指针数组的元素。总体意思就是执行perptr数组的元素(*ptr1)所指向的对象的PrintfName()成员函数。
C++C++ 指针(二)--c++ 指针(二)--c++的更多相关文章
- 转: 浅谈C/C++中的指针和数组(二)
转自:http://www.cnblogs.com/dolphin0520/archive/2011/11/09/2242419.html 浅谈C/C++中的指针和数组(二) 前面已经讨论了指针和数组 ...
- C++实现离散余弦变换(参数为二维指针)
C++实现离散余弦变换(参数为二维指针) 写在前面 到目前为止已经阅读了相当一部分的网格水印等方面的论文了,但是论文的实现进度还没有更上,这个月准备挑选一些较为经典的论文,将其中的算法实现.在实现论文 ...
- c指针与数组,传参问题,指针数组与数组指针的区别,二维数组动态内存分配
一 数组的结构:顺序存储,看谭浩强中的图,牢记 1.数组名指代一种数据结构:数组 现在可以解释为什么第1个程序第6行的输出为10的问题,根据结论1,数组名str的内涵为一种数据结构,即一个长度为10的 ...
- C语言里的指针探析——type *name[] 在函数参数里面,是一个二维指针
type *name[] 在函数参数里面声明和不在函数里面声明其实不一样. type *name[] 如果在函数参数里声明,则name 是一个二维指针,并不是一个指针数组,而如果不在函数参数里声明,则 ...
- 通过数组初始化链表的两种方法:指向指针的引用node *&tail和指向指针的指针(二维指针)node **tail
面试高频题:单链表的逆置操作/链表逆序相关文章 点击打开 void init_node(node *tail,char *init_array) 这样声明函数是不正确的,函数的原意是通过数组初始化链表 ...
- 二维指针*(void **)的研究(uC/OS-II案例) 《转载》
uC/OS-II内存管理函数内最难理解的部分就是二维指针,本文以图文并茂的方式对二维指针进行了详细分析与讲解.看完本文,相信对C里面指针的概念又会有进一步的认识. 一.OSMemCreate( ) 函 ...
- C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com
原文:C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | I ...
- C/C++——二维数组与指针、指针数组、数组指针(行指针)、二级指针的用法
本文转载自:https://blog.csdn.net/qq_33573235/article/details/79530792 1. 二维数组和指针 要用指针处理二维数组,首先要解决从存储的角度对二 ...
- c/c++指针详解(二)
指针的概念 指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址.要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指向的类型,指针的值或者叫指针所指向的内存区,还有指针本身所占 ...
- C 二维指针难点详解。
关于 指向二维数组的指针. int a[2][3]; int *p; int (*p_1)[3]; 可以用p_1 = a ,但是不能用p = a : 因为此时数组a的数据类型是 int (* ...
随机推荐
- 转载---jboss简单使用
初学Jboss,对于Jboss的基础认识以及配置做一些记录 Jboss基础: JBoss是什么–基于J2EE的应用服务器–开放源代码–JBoss核心服务不包括支持servlet/JSP的WEB容器,一 ...
- mybatis动态sql中的trim标签的使用
trim标记是一个格式化的标记,可以完成set或者是where标记的功能,如下代码: 1. select * from user <trim prefix="WHERE" p ...
- Ajax中eval的使用详解
定义和用法 Eval它是用来计算某个字符串,并且执行其中的JavaScript代码. 语法 1) eval函数接受一个string这个参数,并且这个参数是必须的,这个参数就是要计算的这个字符串.它里面 ...
- [转]Android WebView播放视频(包括全屏播放),androidwebview
Android WebView播放视频(包括全屏播放),androidwebview 最近项目开发中用到了WebView播放视频的功能,总结了开发中犯过的错误,这些错误在开发是及容易遇到的,所以我这里 ...
- 求出数组前面k个元素或数组中元素大于一半的元素(快速排序与堆排序的灵活运用)
写这个的目的在于,说明快速排序的灵活运用.我们来看下关于快速排序中的一部分关键代码: 快速排序代码: int a[101],n;//定义全局变量,这两个变量需要在子函数中使用 void quickso ...
- openmpi出现Segmentation Fault而终止运算
欢迎关注我的社交账号: 邮箱: jiangxinnju@163.com 博客园地址: http://www.cnblogs.com/jiangxinnju GitHub地址: https://gith ...
- JS预解析
1.在逐行读js代码前,解析器会先提取所有声明的var变量和函数 js解析器会先把脚本里所有var变量声明读一遍,但是它只读变量名字,不读变量值,一开始它会赋给所有读到的var变量一个[未定义]的值. ...
- laravel 中 与前端的一些事1
首先安装node.js 在命令行中敲node -v 可以查看node的版本信息 还需要安装npm,相当于php中的composer node.js中5.0版本后的都已经将npm打包进node了 还要安 ...
- Android FloatingActionButton(FAB) 悬浮按钮
FloatingActionButton 悬浮按钮 ...
- 谈谈JPA-04-JPA的常用API
JPA相关接口/类: Persistence Persistence 类是用于获取 EntityManagerFactory 实例.该类包含一个名为 createEntityManagerFacto ...