指针(2):关于数组指针和指向数组指针的指针及其new

来源:互联网 发布:windows窗口 编辑:程序博客网 时间:2024/05/02 07:53

今天在CSDN上看到了wp123456xt对我很久以前的一篇文章——方正面试的题-找出字符串最多的分解方法http://blog.csdn.net/shizhixin/article/details/4742687的评论,很高兴有人能够提出问题,正好今天有时间,所以回复了。


后来在wp123456xt的CSDN的博文上看到他的一篇求助文章——数组指针问题(求指教),http://blog.csdn.net/wp123456xt/article/details/7021496,也无人回答,闲来无事,就一一解释下吧,这些理解都属于一家之见,也许其中的一些理解上会有问题,还希望大家指出,共同进步嘛。


相关主程序和ex小例子代码可以在我的资源中下载:http://download.csdn.net/detail/shizhixin/3892608

[cpp] view plaincopyprint?
  1. #include<iostream>
  2. using namespace std;
  3. int main()
  4. {
  5. float(**q)[5];
  6. float a[1][5]={{1,2,3,4,5}};
  7. q=&new float [1][5];//编译可以通过
  8. //q=&a;//编译通不过
  9. //q=new float*;//此处我原本想先给q分配一个内存空间,用于存取二维数组a的地址
  10. //却找不到合适的数据类型
  11. *q=a;
  12. for(int i=0;i<5;i++)
  13. {
  14. cout<<*(**q+i)<<endl;
  15. printf("%p\n",**q+i);
  16. }
  17. cout<<endl;
  18. cout<<&q<<endl;
  19. return 0;
  20. }

/*
一一解析你的代码,你的代码用--标志的行


--float(**q)[5];
这里定义的q,是一个指向(数组指针)的指针,本质上它是一个二级指针,他的下一级是一个指向[5]大小的
数组的指针,最终才是一个二维的数组类型;如下图,如果真正理解了这个,基本上后面的就不难理解了;


--float a[1][5]={{1,2,3,4,5}};
a当然是一个1*5的二维数组;


--q=&new float [1][5];//编译可以通过
这句话可以拆分开来看,就比较容易理解为什么能编译通过了,拆分如下:
float (*b)[5] = new float[1][5]; //b是一个数组指针,指向了一个新开辟的数组,这个肯定没问题吧
q=&b; //用一个二级指针,就是指向(数组指针b)的指针即q,这样q这个指针里存储b的地址,这个当然是可以的啊。
如果还不理解的话看下面这段:
[cpp] view plaincopyprint?
  1. ex1:
  2. int ** pa; //相当于q
  3. int *pb; //相当于b
  4. int n=10; //相当于a
  5. pb=&n;
  6. pa=&pb;//这样没编译肯定没问题吧,并且**pa,*pb的值应该和n的值都相等吧。




--//q=&a;//编译通不过
自然,上面那个例子,pa=&n,这样可以么??


-- //q=new float*;//此处我原本想先给q分配一个内存空间,用于存取二维数组a的地址
-- //却找不到合适的数据类型
如果只是仅仅为了暂时存储二维数组a的地址方便操作二维数组之用,没必要new一个内存空间,如上面的代码中
pa也没有去new一个空间来存储a的地址,程序会自动在编译系统就为已定义的变量分配相应的内存单元的。
退一步说,如果你一定要new,比如同时操作多个,那应该怎么new呢,还是上面那个例子,
int * pb = new int;
int ** pa = new int*;
应该这么new吧,也就是定义的这个pb指针,他指向new的存储区的数据类型是int型的,同样,pb指向的是int*的
数据类型,那new的话应该new int*;所以对于我们的float(**q)[5],q开始说了是指向(数组指针b)的指针,而
b的类型是float (*b)[5],所以应该这么new:float(**q)[5] = new (float(*)[5]);如果你想同时new n个这样
指向数组指针的指针,那就int(**q)[5]=new (int(*[n])[5]); 不过这里释放的时候要注意,和new二维数组一样,
要先delete [] p[0--n];然后再delete [] p;例如:
[cpp] view plaincopyprint?
  1. ex2:
  2. int(**p)[2]=new (int(*[3])[2]);//注意new后面的括号
  3. p[0]=new int[2][2];
  4. p[1]=new int[2][2];
  5. p[2]=new int[2][2];
  6. delete [] p[0];
  7. delete [] p[1];
  8. delete [] p[2];
  9. delete [] p;
  10. int(**q)[2]=new (int(*)[2]);//一个的情形
  11. delete []q;




-- // *q=a;
编译上是可以通过的,毕竟相当于第一个例子中*pa=&n(*pa=pb,pb=&n),这里a也是代表其首地址,
但是需要注意的一个问题,直接把a的值赋予*q,*q所代表的是q所指向的内容,
而如果开始q指向哪里了都没定义,这样肯定编译没问题,但是程序运行有问题的。换句话说,如果程序如下:
[cpp] view plaincopyprint?
  1. ex3-1:
  2. float(**q)[5];
  3. float a[1][5]={{1,2,3,4,5}};
  4. *q=a;//能编译但这样是有问题的!!
  5. ex3-2:
  6. float(**q)[5];
  7. float a[1][5]={{1,2,3,4,5}};
  8. q=&new float [1][5];
  9. *q=a;//编译能通过,并且赋值也是正确的


-- for(int i=0;i<5;i++)
-- {
-- cout<<*(**q+i)<<endl;
-- printf("%p\n",**q+i);
-- }
-- cout<<endl;
-- cout<<&q<<endl;
这段代码应该不难理解,但是也需要注意的一个地方是
**q是获取a的首地址里面的内容,
**q+i是获取a的首地址然后偏移i个float单位,注意这里的偏移单位和数组指针直接+1不一样,这里是q
先获得首地址,然后偏移i个单位,通过下面这个例子慢慢体会:
[cpp] view plaincopyprint?
  1. ex4:
  2. float a[2][5]={{1,2,3,4,5},{7,8,9,0,1}};
  3. float (*b)[5];
  4. b=a;
  5. for (int i=0;i<2;i++)
  6. {
  7. cout<<**(b+i)<<endl; //output: 1,7
  8. cout<<**b+i<<endl; //output:1,2
  9. }

0 0
原创粉丝点击