一、内存管理: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;
}
1) new格式:

char* ptr = new char [len+1]
 

指针

=

关键字

变量的数据类型

char类型变量的数目(方括号)

new和malloc:new方法可以返回适当的数据类型的指针;而malloc返回的指针是void类型的指针,必须强制转化才能转化成适当的数据类型指针。

C中的realloc函数可以改变已分配内存空间的大小。C++中没有这样的函数,只能通过new重新申请一个更大或者更小的空间。
2) delete格式:delete【】 要删除的指针
如果new创建的是一个简单的对象,则在删除的时候可不加方括号,如果是数组就必须加括号。
 

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++的更多相关文章

  1. 转: 浅谈C/C++中的指针和数组(二)

    转自:http://www.cnblogs.com/dolphin0520/archive/2011/11/09/2242419.html 浅谈C/C++中的指针和数组(二) 前面已经讨论了指针和数组 ...

  2. C++实现离散余弦变换(参数为二维指针)

    C++实现离散余弦变换(参数为二维指针) 写在前面 到目前为止已经阅读了相当一部分的网格水印等方面的论文了,但是论文的实现进度还没有更上,这个月准备挑选一些较为经典的论文,将其中的算法实现.在实现论文 ...

  3. c指针与数组,传参问题,指针数组与数组指针的区别,二维数组动态内存分配

    一 数组的结构:顺序存储,看谭浩强中的图,牢记 1.数组名指代一种数据结构:数组 现在可以解释为什么第1个程序第6行的输出为10的问题,根据结论1,数组名str的内涵为一种数据结构,即一个长度为10的 ...

  4. C语言里的指针探析——type *name[] 在函数参数里面,是一个二维指针

    type *name[] 在函数参数里面声明和不在函数里面声明其实不一样. type *name[] 如果在函数参数里声明,则name 是一个二维指针,并不是一个指针数组,而如果不在函数参数里声明,则 ...

  5. 通过数组初始化链表的两种方法:指向指针的引用node *&tail和指向指针的指针(二维指针)node **tail

    面试高频题:单链表的逆置操作/链表逆序相关文章 点击打开 void init_node(node *tail,char *init_array) 这样声明函数是不正确的,函数的原意是通过数组初始化链表 ...

  6. 二维指针*(void **)的研究(uC/OS-II案例) 《转载》

    uC/OS-II内存管理函数内最难理解的部分就是二维指针,本文以图文并茂的方式对二维指针进行了详细分析与讲解.看完本文,相信对C里面指针的概念又会有进一步的认识. 一.OSMemCreate( ) 函 ...

  7. C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com

    原文:C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | I ...

  8. C/C++——二维数组与指针、指针数组、数组指针(行指针)、二级指针的用法

    本文转载自:https://blog.csdn.net/qq_33573235/article/details/79530792 1. 二维数组和指针 要用指针处理二维数组,首先要解决从存储的角度对二 ...

  9. c/c++指针详解(二)

    指针的概念 指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址.要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指向的类型,指针的值或者叫指针所指向的内存区,还有指针本身所占 ...

  10. C 二维指针难点详解。

    关于   指向二维数组的指针. int  a[2][3]; int *p; int (*p_1)[3]; 可以用p_1 = a ,但是不能用p = a : 因为此时数组a的数据类型是  int (* ...

随机推荐

  1. android坐标

    说来说去都不如 画图示意 简单易懂啊!!!真是的! 来吧~~先上张图~~! (一)首先明确一下 android 中的坐标系统 :      屏幕的左上角是坐标系统原点(0,0)      原点向右延伸 ...

  2. 网络性能测试工具iperf详细使用图文教程【转载】

    原文:http://blog.163.com/hlz_2599/blog/static/142378474201341341339314/ 参考:http://man.linuxde.net/iper ...

  3. linux 后台执行命令

    本文主要内容: 1. 设置ctontab文件,并用它来提交作业. 2. 使用at命令来提交作业. 3. 在后台提交作业. 4. 使用nohup命令提交作业. 名词解释: cron 系统调度进程.可以使 ...

  4. 转!大端模式&小端模式

    大端模式&小端模式   在C语言中除了8位的char型之外,还有16位的short型,32位的long型(要看具体的编译器),对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器 ...

  5. spring 编程式事务管理和声明式事务管理

    编程式事务管理 Spring 的编程式事务管理概述 在 Spring 出现以前,编程式事务管理对基于 POJO 的应用来说是唯一选择.用过 Hibernate 的人都知道,我们需要在代码中显式调用be ...

  6. xcode 真机调试 failed to get the task for process xxx

    xcode 真机调试 failed to get the task for process xxx 此错误原因是,使用 in house profile 签名了真机调试的证书: 在 target--- ...

  7. 【bzoj1041】圆上的整点

    题意 给定一个圆\(x^2+y^2=z^2\),求圆周上有多少个点的坐标是整数. \(r\leq 2*10^9\) 分析 这道题目关键要知道一些勾股数的性质,剩下的就很好处理了. 勾股数的性质 参考: ...

  8. 20145218 《Java程序设计》第二周学习总结

    Java中的注释格式 单行注释 //注释文字 多行注释 /注释文字/ 文档注释 /**注释文字*/ 注释不仅仅是对代码进行解释,在上一篇博客中也写过,注释也可以用来检查程序中的错误,可以说是一个小窍门 ...

  9. 如何使用Retrofit获取服务器返回来的JSON字符串

    有关Retrofit的简单集成攻略,大家可以参考我此前的一篇文章有关更多API文档的查阅请大家到Retrofit官网查看. 在大家使用网络请求的时候,往往会出现一种情况:需要在拿到服务器返回来的JSO ...

  10. MySQL忘记密码怎么办

    1. 关闭正在运行的MySQL服务2. 打开DOS窗口,转到mysql\bin目录3. 输入mysqld --skip-grant-tables 回车       --skip-grant-table ...