一、内存管理: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. 最大堆的插入/删除/调整/排序操作(图解+程序)(JAVA)

    堆有最大堆和最小堆之分,最大堆就是每个节点的值都>=其左右孩子(如果有的话)值的完全二叉树.最小堆便是每个节点的值都<=其左右孩子值的完全二叉树. 设有n个元素的序列{k1,k2,..., ...

  2. JavaScript:引用js文件时的编码格式问题

    JavaScript:引用js文件时的编码格式问题 如果js文件的编码格式是utf-8,并且含有中文,那么按照正常的方法引用,就会出现乱码的情况. 方法/步骤   如果js文件的编码格式是utf-8, ...

  3. Linux技巧学习

    主要是收集一些Linux的技巧: 1.编写可靠shell脚本的八个建议 指定bash,推荐使用 /usr/bin/env bash 和 /bin/bash,不要使用/usr/bin/bash. set ...

  4. webdriver hangs when get or click

    Same times the webdriver hangs when get url or click some link,  webdriver executing (get or click) ...

  5. C语言编译器 cc 编译原理

    生成一个可执行的文件通常需要经过以下几个步骤: 预处理你的源代码,去掉注释,以及其他技巧性的工作就像在 C 中展开宏. 检查代码的语法看你是否遵守了这个语言的规则.如果没有,编译器会给出 警告. 把源 ...

  6. 能源项目xml文件标签释义--DataSource

    <bean id="dataSource1" class="org.apache.tomcat.jdbc.pool.DataSource" destroy ...

  7. 使用XIB实现一个简单view

    技术处女贴 欢迎来探讨 转帖请注明出处 http://www.cnblogs.com/andy-zhou/p/4962135.html 微信: @Andy 1. AppDelegate AppDele ...

  8. VS2012更改项目编译后文件输出目录

    1.现在我的解决方案里有存在两个项目,分别是类库项目ClassLibrary1和控制台项目ConsoleApplication1,默认情况下当解决方案重新生成后,这两个项目所对应的编译后文件分别会存在 ...

  9. thinkPHP开发基础知识 包括变量神马的

    hinkPHP框架开发的应用程序,一般都采用单一入口的方式,下面是在应用首页文件中实现的定义: 1.在首页定义thinkPHP框架路径 2.定义项目名称及路径,一般项目名称与项目文件夹名称保持一致 3 ...

  10. hdu-----(1151)Air Raid(最小覆盖路径)

    Air Raid Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Su ...