精华内容
下载资源
问答
  • 检查站 堆栈和数组的大学项目
  • mfc实现迷宫程序(堆栈和数组)若有问题请发邮箱 yuanmao-benbenhu@163.com
  • /*_############################################################################ _## _## 一个链式堆栈模块的接口(和数组实现完全一样) _## Author: xwlee _## Time: 2006.12.31 _## Changan
    /*_############################################################################
    
      _##
      _##  一个链式堆栈模块的接口(和数组实现完全一样)
      _##  Author: xwlee                        
      _##  Time: 2006.12.31 
      _##  Chang'an University
      _##  Development condition: win2003 Server+VC6.0
      _##
      _##  stack.h 文件
      _##########################################################################*/

    // 堆栈所存贮的值的类型.
    #define STACK_TYPE  int 

    // --------------------------外部接口-------------------------------
    // 创建堆栈,参数指定可以保存多少个元素
    int create_stack( size_t size );

    // 销毁堆栈
    int destroy_stack( void );

    // 把一个新值压入堆栈.
    void push( STACK_TYPE value );

    // 从堆栈弹出一个值,并将其丢弃.
    void pop( void );

    // 返回堆栈顶部元素的值,但不对堆栈进行修改.
    STACK_TYPE top( void );

    // 如果堆栈为空,返回TRUE,否则返回FALSE.
    int is_empty( void );

    // 如果堆栈已满,返回TRUE,否则返回FALSE.
    int is_full( void );
    // --------------------------外部接口-------------------------------

     
    展开全文
  • 循环语句和数组

    2018-10-16 23:17:56
    这个赋值语句,其实是操作数栈中array2指向了堆栈中的array的地址,修改array中的元素的值,但是其地址没有变化,在输出array2的时候,array2还是先去找那个地址,然后再去访问地址所对应的数据,所以修改了array的...

    循环语句的理解

    1. do while 语句和while语句的区别:

    while语句在进入循环体之前要先判断条件是否成立,如果成立的话则进入循环体。
    而do…while语句则是先执行循环体,然后再判断条件是否成立,如果成立的话则继续循环体,如果不成立则跳出循环;
    也就是说do-while循环至少要执行一次循环语句。

    2.break和continue的区别:

    break和continue都是用来控制循环结构的,主要是停止循环。
    1.break
    有时候我们想在某种条件出现的时候终止循环而不是等到循环条件为false才终止。
    这是我们可以使用break来完成。break用于完全结束一个循环,跳出循环体执行循环后面的语句。
    2.continue
    continue和break有点类似,区别在于continue只是终止本次循环,接着还执行后面的循环,break则完全终止循环。
    可以理解为continue是跳过当次循环,执行下一次循环。

    数组

    建立一个一维数组有很多种写法:

    1. int[] array1 = {1,2,3,4,5};
      
    2. int[] array2 = new int[5];
      
    3. int[] array3 = new int[] {1,2,3,4,5};
      

    数组引用之间的赋值

     public static void main(String[] args) {
       int[] array = {1,2,3,4,5};
            int[] array2 = array;
            System.out.println(Arrays.toString(array));
            System.out.println(Arrays.toString(array2));
            array[0] = 6;
            System.out.println(Arrays.toString(array));
            System.out.println(Arrays.toString(array2));
     }
    

    输出结果为:
    在这里插入图片描述
    我们都知道通过array[0]=6; 修改的是array的中0下标的元素的值,但是
    第二次输出的array2的0元素的值也为 6;
    因为 int[] array2 = array; 这个赋值语句,其实是操作数栈中array2指向了堆栈中的array的地址,修改array中的元素的值,但是其地址没有变化,在输出array2的时候,array2还是先去找那个地址,然后再去访问地址所对应的数据,所以修改了array的值,array2的值也同样跟着改变。

    练习题:

    1、实现二分查找算法:有序的数组

    public static void main(String[] args) {
        int[] array=new int[]{1,2,3,4,5,6,7,8,9,10};
          System.out.println(binnary(array,6));
          }
     public static int binnary(int[] array,int key){
            int a=0;
            int b=array.length-1;
            int middie=(a+b)/2;
            if(key<array[a]||key>array[b]) {
                return -1;
            }
            while(a<=b){
                if(array[middie]==key){
                    return middie;
                }else{
                    if(array[middie]>key){
                        b=middie-1;
                    }
                    else{
                        a=middie+1;
                    }
                }
                }
            return -1;
        }
    

    2.求一个数组的连续子数组的最大和(最好输出最大的子数组)?

    public static void main(String[] args) {
         int[] array=new int[]{-1,2,5,-8,4,10};
         maxArray(array);
            }
     public static void maxArray(int[] array){
            int sum=array[0];
            int max=array[0];
            int s1=0;
            int start=0;
            int end=0;
            for(int i=1;i<array.length;i++) {
                    if (sum >0) {
                        sum = sum + array[i];
    
                    } else {
                        sum = array[i];
                        s1 = i;
                    }
                    if (sum >= max) {
                        max = sum;
                        start = s1;
                        end = i;
                    }
            }
                int[] array2=new int[end-start+1];
            for(int i=start;i<=end;i++){
                array2[i-start]=array[i];
            }
                System.out.println(max);
                System.out.println(Arrays.toString(array2));
        }
    

    3.交换两个数?

    public static void main(String[] args) {
          int[] a={20};
            int[] b={10};
            exchange(a,b);
            System.out.println(a[0]);
            System.out.println(b[0]);
            }
     public  static void exchange(int[] a,int[] b) {
            int c=0;
            c=a[0];
            a[0]=b[0];
            b[0]=c;
        }
    

    4.逆置数组?

    public static void main(String[] args) {
        int[] array=new int[]{1,2,3,4,5,6} ;
        change(array);
            }
     public static void change(int[] array) {
            int a=0,b=array.length-1;
            while (a<b){
                int c=0;
                c=array[a];
                array[a]=array[b];
                array[b]=c;
                a++;
                b--;
            }
            System.out.println(Arrays.toString(array));
        }
    
    展开全文
  • 一.栈的定义 栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。...本文分别用链表和数组实现了栈 2.1 链表实现 //节点类 public class Node { public Object data;

    一.栈的定义

    栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。(来源百度百科)

    二.本文内容

    本文分别用链表和数组实现了栈

    2.1 链表实现

    //节点类
    public class Node {
        public Object data;
        public Node next;
    
        public Node(Object data, Node next) {
            this.data = data;
            this.next = next;
        }
    
        public Node(Object data) {
            this.data = data;
        }
    }
    
    /**
     * 方式一: 链表实现
     */
    public class MyStack01<E> {
        //栈顶元素
        private Node top;
        //元素个数
        private int count = 0;
    
        /**
         * 进栈
         * @param element
         */
        public void push(E element){
            Node node = new Node(element);
            if (top != null){
                //若存在栈顶元素,则把新节点的下一个节点指向栈顶元素
                node.next = top;
            }
            //栈顶节点指向新节点
            top = node;
            count++;
        }
    
        /**
         * 出栈
         * @return
         */
        public E pop(){
            if (count < 1) throw new RuntimeException("栈顶无元素");
            Node node = top;
            top = top.next;
            count--;
            return (E)node.data;
        }
    
        /**
         * 返回栈内元素个数
         * @return
         */
        public int size(){
            return count;
        }
    
        /**
         * 打印栈内元素
         * @return
         */
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder("]");
            Node temp = top;
            while (temp != null){
                sb.append(temp.data+",");
                temp = temp.next;
            }
            sb.setCharAt(sb.length()-1 , '[');
            return sb.reverse().toString();
        }
    }
    
    //测试类
    public class TestMyStack {
        public static void main(String[] args) {
            MyStack01<String> myStack = new MyStack01<>();
            myStack.push("a");
            myStack.push("b");
            myStack.push("c");
            System.out.println("栈内元素为: " + myStack.toString());
            System.out.println("出栈的元素是: " + myStack.pop());
            System.out.println("栈内元素为: " + myStack.toString());
            System.out.println("栈内元素个数为: " + myStack.size());
        }
    }
    

    测试截图:

    在这里插入图片描述

    2.2 数组实现

    /**
     * 方式二: 数组实现
     */
    public class MyStack02<E> {
        //操作数组
        private Object[] data;
        //栈顶指针
        int top = -1;
        //数组大小
        int size;
    
        public MyStack02(int size) {
            this.size = size;
            data = new Object[size];
        }
    
        /**
         * 入栈
         * @param element
         */
        public void push(E element){
            if (top + 1 == size) throw new RuntimeException("栈已满");
            data[top + 1] = element;
            top ++;
        }
    
        /**
         * 出栈
         * @return
         */
        public E pop(){
            if (top < 0) throw new RuntimeException("栈内无元素");
            Object obj = data[top];
            data[top--] = null;
            return (E)obj;
        }
    
        /**
         * 返回栈内元素个数
         * @return
         */
        public int size(){
            return top+1;
        }
    
        /**
         * 打印栈内元素
         * @return
         */
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder("[");
            for (int i = 0; i <= top; i++) {
                sb.append(data[i] + ",");
            }
    
    
            sb.setCharAt(sb.length()-1,']');
            return sb.toString();
        }
    }
    
    //测试类
    public class TestMyStack {
        public static void main(String[] args) {
            MyStack02<String> myStack = new MyStack02<>(4);
            myStack.push("a");
            System.out.println("出栈的元素是: " + myStack.pop());
            myStack.push("b");
            myStack.push("c");
            System.out.println("栈内元素为: " + myStack.toString());
            System.out.println("出栈的元素是: " + myStack.pop());
            System.out.println("栈内元素为: " + myStack.toString());
            System.out.println("栈内元素个数为: " + myStack.size());
        }
    }
    

    测试截图:
    在这里插入图片描述

    展开全文
  • 指针数组和数组指针

    2011-07-16 23:32:02
    指针数组和数组指针下面就简单说说这两个概念:一:指针数组,顾名思义,就是说的首先是一个数组吧,然后数组的元素是指针而已。说明形式为:type *pointer_array[constant1][constant2]...[constantn];例如:int *...

    指针数组和数组指针

    下面就简单说说这两个概念:
    一:指针数组,顾名思义,就是说的首先是一个数组吧,然后数组的元素是指针而已。
    说明形式为:type *pointer_array[constant1][constant2]...[constantn];
    例如:int *pai[3];
    由于‘*’是自右向左结合,因此从右向左看,首先看到[3]说明是一个数组,是一个包含3个元素的数组,然后看到‘*’,显然是指针类型,由此可以看出数组中存放的是指针而不是一般的类型。同理,char*pac[2][3]是包含有6个元素,每一个元素都是一个字符型指针。再来说说他们的初始化:
    int *pai[3];既然是一个包含3个整形指针的数组那么其对应的将是一个二维整形数组,因为一个整形指针对应一个一维整形数组。那我就用一个二维整形数组来初始化它,事实上一般也都是这么做的,这里有一个二维数组,int arr[3][2]={{1,2},{3,4},{5,6}},一个三行两列的整形数组,注意这里的行必须和你的指针数组的维数一致,否则是不允许的,不信你可以试试。
    这个初始化有很多种选择,以下只列举常见的两中:
    第一种也是很好理解的:
    for(int i=0;i<3;i++)
      pai[i]=arr[i];
    显然arr[i]是每一行的首地址,相当于一个一维数组的数组名,如是把它送给一个整形指针pai[i]是理所当然的了。
    第二种方法:

    在说明指针数组时就初始化:

    int *ap[2] = {new int(1), new int(2)};

    注意:不能将二维数组的数组名赋给指针数组的数组名,pai=arr(错),因为两者的类型不一致,二维数组名的类型是指向int[][]型的指针,而指针数组的的数组名是指向 int*[]类型的指针。

    在c/c++语言中,指针数组最常用的场合就是说明一个字符串数组。即说明一个数组,它的每个元素都是一个字符串。

    二:数组指针:指向一个数组的指针。
    说明形式为:type (*pointer_array)[constant1][constant2]...[constantn];
    注意这里的圆括号是必须的,这是由于方括号[]较指针说明符“*”的优先级高,若无此圆括号,编译器将把上述说明解释成成了一个数组指针。
    例如:int (*ap)[2];
    这样就说明了一个指针ap,它指向包含有2个元素的整形数组,听起来确实有点别扭。不过仔细分析应该还是能理解的,就是说ap是一个指针,而它指向的对象是一个指针,注意不要将它和一个指向一个整形变量的指针搞混了。
    同样以一个二维数组来说明其初始化问题,
    int arr[3][2]={{1,2},{3,4},{5,6}};注意这里的列数必须和数组指针所指的数组的列数相同。
    第一种方法:
    ap=arr;
    为什么这里能这样将二维数组名送给ap呢,你可以这样理解,二维数组不就可以看成是一维数组的数组吗,而一个数组指针它指向的内容就是一个一维数组,那么你就可以把这个数组指针当做是一个数组名,只不过这个数组里的元素不是像int,char之类型的,而是一个数组,这样你就可以把它和二维数组的数组名联系在一起了吧。文笔不行,不知道是否说清楚了。
    第二种方法:
    ap=&arr[0];
    这里arr[0]其实就是一维数组的数组名,将它的地址给ap是很自然的,因为ap本来就是指向一个一维数组的。
    注意这里不能这样初始化:int (*a)[2]={{1,2},{3,4},{5,6}};大家可以想想为什么。
    当然他们也可以动态赋值,由于篇幅就不探讨了。
     
    一 :关于指针和堆的内存分配

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

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

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

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

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

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

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

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

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

    下面是从堆中申请数组

    1、申请数组空间:

    指针变量名=new 类型名[下标表达式];

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

    2、释放数组空间:

    delete [ ]指向该数组的指针变量名;

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

    下面是个例子,VC上编译通过
    #include <iostream>
    using namespace std;
    void main(){
         int n;
         char *p;
         cout<<"请输入动态数组的元素个数"<<endl;
         cin>>n; //n在运行时确定,可输入17
         p=new char[n];//申请17个字符(可装8个汉字和一个结束符)的内存空间strcpy(pc,“堆内存的动态分配”);//
         cout<<p<<endl;
         delete []p;//释放pc所指向的n个字符的内存空间return; 
    }

    通过指针使堆空间,编程中的几个可能问题
    1.动态分配失败。返回一个空指针(NULL),表示发生了异常,堆资源不足,分配失败。

       data = new double [m]; //申请空间
       if ((data ) == 0)…… //或者==NULL

    2.指针删除与堆空间释放。删除一个指针p(delete p;)实际意思是删除了p所指的目标(变量或对象等),释放了它所占的堆空间,而不是删除p本身,释放堆空间后,p成了空悬指针,不能再通过p使用该空间,在重新给p赋值前,也不能再直接使用p。

    3.内存泄漏(memory leak)和重复释放。new与delete 是配对使用的,delete只能释放堆空间。如果new返回的指针值丢失,则所分配的堆空间无法,称内存泄漏,同一空间重复释放也是危险的,因为该空间可能已另分配,而这个时候又去释放的话,会导致一个很难查出来的运行时错误。所以必须妥善保存new返回的指针,以保证不发生内存泄漏,也必须保证不会重复释放堆内存空间。

    4.动态分配的变量或对象的生命期。无名变量的生命期并不依赖于建立它的作用域,比如在函数中建立的动态对象在函数返回后仍可使用。我们也称堆空间为自由空间(free store)就是这个原因。但必须记住释放该对象所占堆空间,并只能释放一次,在函数内建立,而在函数外释放是一件很容易失控的事,往往会出错,所以永远不要在函数体内申请空间,让调用者释放,这是一个很差的做法。你再怎么小心翼翼也可能会带来错误。

    类在堆中申请内存 :
    通过new建立的对象要调用构造函数,通过deletee删除对象要调用析构函数。

    CGoods *pc;
    pc=new CGoods;      //分配堆空间,并构造一个无名对象
                                 //的CGoods对象;
    …….

    delete pc;  //先析构,然后将内存空间返回给堆;      

    堆对象的生命期并不依赖于建立它的作用域,所以需要显式地用delete语句析构堆对象,上面的堆对象在执行delete语句时,C++自动调用其析构函数。


    正因为构造函数可以有参数,所以new后面类(class)类型也可以有参数。这些参数即构造函数的参数。

    但对创建数组,则无参数,并只调用缺省的构造函数。见下例类说明:

    class CGoods{

              char Name[21];

              int  Amount;

              float Price;

              float Total_value;

    public:

     CGoods(){}; //缺省构造函数。因已有其他构造函数,系统不会再自动生成缺省构造,必须显式声明。  

     CGoods(char* name,int amount ,float price){

               strcpy(Name,name);

               Amount=amount;

               Price=price;

              Total_value=price*amount;  }

               ……};//类声明结束

    下面是调用机制 :

    void main(){

          int n;

          CGoods *pc,*pc1,*pc2;

          pc=newCGoods(“hello”,10,118000);

          //调用三参数构造函数   pc1=newCGoods();  //调用缺省构造函数 cout<<”输入商品类数组元素数”<<endl;

          cin>>n;

          pc2 = new CGoods[n];

         // 动态建立数组,不能初始化,调用n次缺省构造函数  

          ……

          delete pc;

          delete pc1;

          delete []pc2;  

    }

    申请堆空间之后构造函数运行;

    释放堆空间之前析构函数运行;

    再次强调:由堆区创建对象数组,只能调用缺省的构造函数,不能调用其他任何构造函数。如果没有缺省的构造函数,则不能创建对象数组。





    ---------------------下面我们再来看一下指针数组和数组指针―――――――――――――

    如果你想了解指针最好理解以下的公式 :

         (1)int *ptr;//指针所指向的类型是 int

       (2)char *ptr;//指针所指向的的类型是char

       (3)int **ptr;//指针所指向的的类型是int* (也就是一个int * 型指针)

       (4)int(*ptr)[3];//指针所指向的的类型是 int()[3] //二维指针的声明

    (1)指针数组:一个数组里存放的都是同一个类型的指针,通常我们把他叫做指针数组。

    比如 int *a[10];它里边放了10个int * 型变量,由于它是一个数组,已经在栈区分配了10个(int *)的空间,也就是32位机上是40个byte,每个空间都可以存放一个int型变量的地址,这个时候你可以为这个数组的每一个元素初始化,或者单独做个循环去初始化它。

    例子:
    int * a[2]={ new int(3),new int(4) };     //在栈区里声明一个int *数组,它的每一个元素都在堆区里申请了一个无名变量,并初始化他们为3和4,注意此种声明方式具有缺陷,VC下会报错

    例如 :

    int * a[2]={new int[3],new int[3]};
    delete a[0];
    delete a[1];

    但是我不建议这么写,可能会造成歧义,不是好的风格,并且在VC中会报错,应该写成如下 :

    int * a[2];
    a[0]= new int[3];
    a[1]=new int[3];
    delete a[0];
    delete a[1];

    这样申请内存的风格感觉比较符合大家的习惯;由于是数组,所以就不可以delete a;编译会出警告.
    注意这里是一个数组,不能delete [] ;

    ( 2 ) 数组指针 : 一个指向一维或者多维数组的指针;

    int * b=new int[10]; 指向一维数组的指针b ;
    注意,这个时候释放空间一定要delete [] ,否则会造成内存泄露, b 就成为了空悬指针.

    int (*b2)[10]=new int[10][10]; 注意,这里的b2指向了一个二维int型数组的首地址.

    注意:在这里,b2等效于二维数组名,但没有指出其边界,即最高维的元素数量,但是它的最低维数的元素数量必须要指定!就像指向字符的指针,即等效一个字符串,不要把指向字符的指针说成指向字符串的指针。这与数组的嵌套定义相一致。

    int(*b3) [30] [20];  //三级指针->指向三维数组的指针;
    int (*b2) [20];     //二级指针;
    b3=new int [1] [20] [30];
    b2=new int [30] [20];

         两个数组都是由600个整数组成,前者是只有一个元素的三维数组,每个元素为30行20列的二维数组,而另一个是有30个元素的二维数组,每个元素为 20个元素的一维数组。删除这两个动态数组可用下式:

    delete [] b3;  //删除(释放)三维数组;
    delete [] b2;  //删除(释放)二维数组;

    再次重申:这里的b2的类型是int (*) ,这样表示一个指向二维数组的指针。

    b3表示一个指向(指向二维数组的指针)的指针,也就是三级指针.

    ( 3 ) 二级指针的指针

    看下例 :

    int (**p)[2]=new (int(*)[3])[2];
    p[0]=new int[2][2];
    p[1]=new int[2][2];
    p[2]=new int[2][2];
    delete [] p[0];
    delete [] p[1];
    delete [] p[2];
    delete [] p;

    注意此地方的指针类型为int (*),碰到这种问题就把外边的[2]先去掉,然后回头先把int ** p=new int(*)[n]申请出来,然后再把外边的[2]附加上去;

    p代表了一个指向二级指针的指针,在它申请空间的时候要注意指针的类型,那就是int (*)代表二级指针,而int(**)顾名思义就是代表指向二级指针的指针了。既然是指针要在堆里申请空间,那首先要定义它的范围:(int(*) [n])[2],n个这样的二级指针,其中的每一个二级指针的最低维是2个元素.(因为要确定一个二级指针的话,它的最低维数是必须指定的,上边已经提到)。然后我们又分别为p[0],p[1],p[2]…在堆里分配了空间,尤其要注意的是:在释放内存的时候一定要为p[0],p[1],p[2],单独 delete[],否则又会造成内存泄露,在delete[]p 的时候一定先delete p[0]; deletep[1],然后再把给p申请的空间释放掉 delete [] p ……这样会防止内存泄露。

    (3)指针的指针;

    int ** cc=new (int*)[10]; 声明一个10个元素的数组,数组每个元素都是一个int*指针,每个元素还可以单独申请空间,因为cc的类型是int*型的指针,所以你要在堆里申请的话就要用int *来申请;

    看下边的例子  (vc & GNU编译器都已经通过);

           int ** a= new int * [2];     //申请两个int *型的空间

           a[1]=newint[3];        //为a的第二个元素又申请了3个int 型空间,a[1]指向了此空间首地址处

           a[0]=newint[4];        为a的第一个元素又申请了4个int 型空间,a[0] 指向了此空间的首地址处

           int * b;

           a[0][0]=0;

           a[0][1]=1;

           b=a[0];

           delete []a[0]       //一定要先释放a[0],a[1]的空间,否则会造成内存泄露.;

           delete [] a[1];

           delete [] a;

           b++;

           cout<<*b<<endl;      //随机数

    注意 :因为a 是在堆里申请的无名变量数组,所以在delete 的时候要用delete []来释放内存,但是a的每一个元素又单独申请了空间,所以在delete [] a之前要先delete [] 掉a[0],a[1],否则又会造成内存泄露.

    (4) 指针数组 :
    我们再来看看第二种 :二维指针数组

    int *(*c)[3]=new int *[3][2];

    如果你对上边的介绍的个种指针类型很熟悉的话,你一眼就能看出来c是个二级指针,只不过指向了一个二维int *型的数组而已,也就是二维指针数组。

    例子 :

     int *(*b)[10]=new int*[2][10];//

    b[0][0]=new int[100];

    b[0][1]=new int[100];

    *b[0][0]=1;

    cout <<*b[0][0]<<endl;    //打印结果为1

    delete [] b[0][0];

    delete [] b[0][1];

    delete [] b;

    cout<<*b[0][0]<<endl;    //打印随机数

     这里只为大家还是要注意内存泄露的问题,在这里就不再多说了。

    如果看了上边的文章,大家估计就会很熟悉,这个b是一个二维指针,它指向了一个指针数组

    第二种 :

            int**d[2]; 表示一个拥有两个元素数组,每一个元素都是int ** 型,这个指向指针的指针:)

       d不管怎样变终究也是个数组,呵呵,

       如果你读懂了上边的,那下边的声明就很简单了:

       d[0]=new int *[10];

       d[1]=new int * [10];

         delete [] d[0];

         delete [] d[1];

    具体的就不再多说了 :)

    二 : 函数指针 

    关于函数指针,我想在我们可能需要写个函数,这个函数体内要调用另一个函数,可是由于项目的进度有限,我们不知道要调用什么样的函数,这个时候可能就需要一个函数指针;

    int a();这个一个函数的声明;

    ing (*b)();这是一个函数指针的声明;

    让我们来分析一下,左边圆括弧中的星号是函数指针声明的关键。另外两个元素是函数的返回类型(void)和由边圆括弧中的入口参数(本例中参数是空)。注意本例中还没有创建指针变量-只是声明了变量类型。目前可以用这个变量类型来创建类型定义名及用sizeof表达式获得函数指针的大小:

    unsigned psize = sizeof (int (*) ()); 获得函数指针的大小

    // 为函数指针声明类型定义

    typedef int (*PFUNC) ();

    PFUNC是一个函数指针,它指向的函数没有输入参数,返回int。使用这个类型定义名可以隐藏复杂的函数指针语法,就我本人强烈建议我们大内弟子使用这种方式来定义;

    下面是一个例子,一个简单函数指针的回调(在GNU编译器上通过,在VC上需要改变一个头文件就OK了)

    #include              //GNU 编译器g++ 实现

    using namespace std;

    /*                             //vc 的实现

    #include "stdafx.h"

    #include

    */

    #define DF(F) int F(){  cout<<"this is in function"<<#F<<endl;\

          return 0;       \

    }

    //声明定义DF(F)替代 int F();函数;

    DF(a); DF(b); DF(c); DF(d); DF(e); DF(f); DF(g); DF(h); DF(i);    //声明定义函数 a b c d e f g h i

    // int (*pfunc)();             //一个简单函数指针的声明

    typedef int(*FUNC)();   //一个函数指针类型的声明

    FUNC ff[] = {a,b,c,d,e,f,g,h,i};  //声明一个函数指针数组,并初始化为以上声明的a,b,c,d,e,f,g,h,i函数

    FUNC func3(FUNC vv){   //定义函数func3,传入一个函数指针,并且返回一个同样类型的函数指针

          vv();

          return vv;

    }

    /*FUNC func4(int (*vv)()){      //func3的另一种实现

          vv();

          return vv;

    }*/

    int main(){

          for(int i=0;i

                  FUNC r=func3(ff[ i]);

                 cout<<r()<<endl;               //输出返回值,只是返回了0

          }

          return 0;

    }

    到目前为止,我们只讨论了函数指针及回调而没有去注意ANSI C/C++的编译器规范。许多编译器有几种调用规范。如在VisualC++中,可以在函数类型前加_cdecl,_stdcall或者_pascal来表示其调用规范(默认为_cdecl)。C++Builder也支持_fastcall调用规范。调用规范影响编译器产生的给定函数名,参数传递的顺序(从右到左或从左到右),堆栈清理责任(调用者或者被调用者)以及参数传递机制(堆栈,CPU寄存器等)。

    好了,先到此为止吧,写这篇文章耗费了基本上快半天的时间了,很多事情还没有做,等改天有时间再回来整理,所有的源程序都放在openlab3服务器上我的目录下lib/cpp下,大家可以去拿。不知道的登陆openlab3然后cd ~chengx/lib/cpp就可以看到了。

    还有很复杂的声明可能也是一种挑战 比如<<Think in c++>>里的

    int(* (*f4())[10]();的声明,f4是一个返回指针的函数,该指针指向了含有10个函数指针的数组,这些函数返回整形值;不是这个函数有特别之处,而是BruceEckel 说的“从右到左的辨认规则”是一种很好的方法,值得我们去学习,感谢他:)

    最后我想应该跟大家说一下,写程序应该就象JERRY所说的:简单就是美;我们应该遵循一个原则 : KISS (Keep ItSimple,Stupid ,尽量保持程序简单 出自 :《Practical Cprogramming》),把自己的程序尽量的简单明了,这是个非常非常好的习惯。
    展开全文
  • 集合和数组的区别

    2018-06-07 20:08:29
    数组和集合的定义一、数组数是java语言内置的数据类型,他是一个线性的序列,所有可以快速访问其他的元素,数组和其他语言不同,当你创建了一个数组时,他的容量是不变的,而且在生命周期也是不能改变的,还有JAVA...
  • 指针和数组存储区

    2019-09-22 12:37:42
     //字符数组,存放在堆栈中  char *p = quot;  while(*p != '\0'){  if(*p == '-'){  *p = '_'; //正确  }  p++;  } 转载于:https://www.cnblogs.com/onwalking/archive/2013/01/30/2883334.html
  • FIFO 队列的链表和数组实现

    千次阅读 2015-02-03 15:59:17
    FIFO (First-in, First-out,先进先出)队列:当执行delete操作时事删除那些呆在队列中时间最长的元素。 FIFO 队列是这样一个ADT,包含两个基本操作:插入(put)一个新的项、删除...FIFO 队列的链表实现和数组实现
  • java集合和数组

    2011-12-04 16:54:19
    Map接口提供3种集合的视图,Map的内容可以被当作一key集合,一value集合,或者一key-value映射。 HashMap类 HashMap和Hashtable类似,不同之处在于HashMap是非同步的,并且允许null,即null value和null ...
  • 更糟糕的是,尝试使用函数内部的固定大小创建非常大的矩阵可能会导致堆栈溢出,因为Eigen会尝试将数组自动分配为局部变量,而这通常是在堆栈上完成的。 最后,视情况而定,当使用动态尺寸时,Eigen还可以尝试进行...
  • 受APL和Forth启发的涉及串联,堆栈和数组的语言实验。 内建字词 IO =>打印顶部堆栈值。 控制流 ? 根据顶层堆栈元素的真实性,有条件地评估下一个代码。 如果错误,则从next- ->继续。 ->标记以标识分支结束。 ...
  • 原创文章,转载请注明:汇编入门之快速排序和数组遍历By Lucio.Yang 1.程序内容描述  将两个数组X、Y进行从小到大的快速排序后,将两个数组相同的元素按照从大到小的顺序输出到Z中。 2.程序流程图   3.源代码...
  • 前言:在上一篇文章中说到了指针变量和普通变量的区别,那么这一篇文章中就来说说指针和数组的关联。指针和数组有相似之处,却又不尽相同。
  • 和数组类似, List 可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变。    Set 和 List 具体子类:    Set   |————HashSet :以哈希表的形式存放元素,插入删除速度很快...
  • 用LinkedList构造堆栈stack、队列queue。 5、Map用 put(k,v) / get(k),还可以使用containsKey()/containsValue()来检查其中是否含有某个key/value。 6、Map中元素,可以将key序列、value序列单独抽取出来。 ...
  • 堆栈

    2019-09-27 23:11:46
    堆内存:堆内存用来存放由new创建的对象和数组。堆中的对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定,具有很大的灵活性。 栈内存:所有的方法运行的时候进入的内存,当没有调用时就被回收,缺乏灵活...
  • 字符串和数组实际上是一样的,只不过是字符串以0结尾 二维数组的形式 从汇编语言程序员的视角来看,二维数组是一维数组的高阶抽象。 对于二维数组在内存中行列的存储,高级语言一般采用下面的两种方法: 行主序( row-...
  • 数组和集合的定义一、数组数是java语言内置的数据类型,他是一个线性的序列,所有可以快速访问其他的元素,数组和其他语言不同,当你创建了一个数组时,他的容量是不变的,而且在生命周期也是不能改变的,还有JAVA...
  • 《高级程序设计》整理(一)- - -数据类型和数组篇 一、JavaScript六种数据类型 Undefined == Boolean ==》等于true Null:表示一个空指针对象 typeof(null)===&quot;object&quot; Boolean:true / false...
  • 对于基本类型,java采用与C,C++相同方法,这些并非引用的自动变量直接存储值,并置于堆栈中,注意堆栈即栈,不是堆空间;这些基本类型所占存储空间的大小,并不像其他大多数语言那样随机器硬件架构的变化而变化。 ...
  • 最简单的是用引号将一字符包含起来,可以将其赋值给一个字符串变量。var myStr = "Hello, String!";可以用双引号或单引号将字符串包含,但要注意,作为界定字符串的一对引号必须是相同的,不能混用。像var ...
  • 稠密矩阵和数组操作 http://eigen.tuxfamily.org/dox-devel/group__DenseMatrixManipulation__chapter.html 包含模块: 1.矩阵类 2.矩阵和向量的运算 3.数组操作 4.块操作 5.高级的初始化 6.减少,...
  • Map接口提供3种集合的视图,Map的内容可以被当作一key集合,一value集合,或者一key-value映射。 (1) Hashtable类 Hashtable继承Map接口,实现一个key-value映射的哈希表。任何非空(non-null)的对象都可作为...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 14,538
精华内容 5,815
关键字:

堆栈和数组