The two-dimensional pointer operation in C++

C中的二维指针问题总结:

概括的说,指针其实就是可变数组的首地址,说是可变数组,是
指其包含内容的数量的可变的,并且是可动态申请和释放的,从而充
分节约宝贵的内存资源。我一向喜欢一维数组,除非万不得已,我一
般是不用二维数组的,多维的则更是很少涉足了。因为一维简单,容
易理解,而用指针指向的多维数组就具有相当的复杂性了,也因此更
具有讨论的必要。
闲话少说,这里我就以三个二维数组的比较来展开讨论:
(1)
int **Ptr;
(2)
int *Ptr[ 5 ];
(3)
int ( *Ptr )[ 5 ];
以上三例都是整数的二维数组,都可以用形如 Ptr[ 1 ][ 1 ]
方式访问其内容;但它们的差别却是很大的。下面我从四个方面对它们
进行讨论:
一、内容:
它们本身都是指针,它们的最终内容都是整数。注意我这里说
的是最终内容,而不是中间内容,比如你写 Ptr[ 0 ],对于三者来说,
其内容都是一个整数指针,即 int *Ptr[ 1 ][ 1 ]这样的形式才
是其最终内容。
二、意义:
(1)
int **Ptr表示指向"一群"指向整数的指针的指针。
(2)
int *Ptr[ 5 ]表示指向 5个指向整数的指针的指针。
(3)
int ( *Ptr )[ 5 ]表示指向"一群"指向 5 个整数数
组的指针的指针。
三、所占空间:
(1)
int **Ptr (3)int ( *Ptr )[ 5 ]一样,在32位平
台里,都是4字节,即一个指针。
(2)int *Ptr[ 5 ]不同,它是 5个指针,它占5 * 4 = 20
个字节的内存空间。
四、用法:
(1)
int **Ptr
因为是指针的指针,需要两次内存分配才能使用其最终内容。
先,Ptr = ( int ** )new int*[ 5 ];这样分配好了以后,它和(2)
意义相同了;然后要分别对 5个指针进行内存分配,例如:
Ptr[ 0 ] = new int[ 20 ];
它表示为第 0 个指针分配 20 个整数,分配好以后,Ptr[0 ]为指
20个整数的数组。这时可以使用下标用法 Ptr[ 0 ][ 0 ]
Ptr[ 0 ][ 19 ]
了。
如果没有第一次内存分配,该 Ptr是个""指针,是不能使用
的,如果没有第二次内存分配,则 Ptr[ 0 ]等也是个""指针,也
是不能用的。当然,用它指向某个已经定义的地址则是允许的,那是另外
的用法(类似于"借鸡生蛋"的做法),这里不作讨论(下同)。
(2)
int *Ptr[ 5 ]
这样定义的话,编译器已经为它分配了 5个指针的空间,这相当
(1)中的第一次内存分配。根据对(1)的讨论可知,显然要对其进行一次
内存分配的。否则就是""指针。
(3)
int ( *Ptr )[ 5 ]
这种定义我觉得很费解,不是不懂,而是觉得理解起来特别吃力,
也许是我不太习惯这样的定义吧。怎么描述它呢?它的意义是"一群"
指针,每个指针都是指向一个 5个整数的数组。如果想分配 k个指针,
这样写: Ptr = ( int ( * )[ 5 ] ) new int[ sizeof( int ) * 5 * k ]
这是一次性的内存分配。分配好以后,Ptr指向一片连续的地址空间,
其中 Ptr[ 0 ]指向第 0 5 个整数数组的首地址,Ptr[ 1 ]指向第
1
5 个整数数组的首地址。
综上所述,我觉得可以这样理解它们:
int ** Ptr <==> int Ptr[ x ][ y ];
int *Ptr[ 5 ] <==> int Ptr[ 5 ][ x ];
int ( *Ptr )[ 5 ] <==> int Ptr[ x ][ 5 ];
这里 x y是表示若干的意思。


二、二维数组    *****和二维指针的关系

1.代码

[cpp] viewplaincopyprint?

1.  <span style="white-space: pre;"> </span>//test2

2.  cout<<"test2"<<endl;

3.  int b[10][10], i, j;

4.  for(i = 0; i < 10; i++)

5.  {

6.  for(j = 0; j < 10; j++)

7.  b[i][j] = i * 100 + j *10;

8.  }

9.  int (*pb)[10] = b;

10. cout<<pb<<' '<<pb+1<<endl;

11. cout<<(*pb)<<' '<<(*pb+1)<<endl;

12. cout<<*pb<<' '<<*(pb+1)<<' '<<*(pb+1)+1<<endl;

13. cout<<**pb<<' '<<**pb+1<<endl;

14. cout<<(*(*pb))<<' '<<(*(*pb+1))<<' '<<(*(*pb+1)+1)<<endl;

15. cout<<**(pb)<<' '<<**(pb+1)<<' '<<**(pb+1)+1<<endl;

   //test2
   cout<<"test2"<<endl;
   int b[10][10], i, j;
   for(i = 0; i < 10; i++)
   {
     for(j = 0; j < 10; j++)
      b[i][j] = i * 100 + j * 10;
   }
   int (*pb)[10] = b;
   cout<<pb<<' '<<pb+1<<endl;
   cout<<(*pb)<<' '<<(*pb+1)<<endl;
   cout<<*pb<<' '<<*(pb+1)<<' '<<*(pb+1)+1<<endl;
   cout<<**pb<<' '<<**pb+1<<endl;
   cout<<(*(*pb))<<' '<<(*(*pb+1))<<' '<<(*(*pb+1)+1)<<endl;
   cout<<**(pb)<<' '<<**(pb+1)<<' '<<**(pb+1)+1<<endl;

 

2.输出结果

3.解释

第一行:

pb:b[0]的地址。pb是指向b[0]的指针,b[0]是一个int[10]数组。

pb+1:b[1]的地址。pb指向的对象是一个数组,所以pb和pb+1相差0x28

第二行:

*pb:b[0][0]的地址。*pb是指向b[0][0]的指针,b[0][0]是一个int。虽然b[0]和b[0][0]的地址是一样的,但是两个指针指向的对象是不一样的。

*pb+1:b[0][1]的地址。pb是指向b[0][1]的指针,b[0][1]是一个int。因此*pb和*pb+1相关4

第三行:

*pb:b[0][0]的地址。

*(pb+1):b[1][0]的地址。pb+1指向b[1]。

*(pb+1)+1:b[1][1]的地址。

第四行:

**pb:pb[0][0]。pb指向pb[0]。*pb指向pb[0][0]。**pb是pb[0][0]的内容。

**pb+1:b[0][0]+1。

第五行:

*(*pb):pb[0][0]

(*(*pb+1)):pb[1][0]

(*(*pb+1)+1):pb[1][1]

第六行:

**(pb):pb[0][0]

**(pb+1):pb[1][0]

**(pb+1)+1:pb[1][0]+1

 

 二维指针对字符串的操作:

1. #include<string>

2. using namespace std;

3. int main(){

4. char **mychr;

5. char chr[]={"I love cplusplus"};

6. char chrs[]={"I love cplusplus"};

7. char *p=chr;

8. mychr=&p;

9.  

10.if(strcmp(*mychr,chrs)==0)

11.{

12.cout<<"equal"<<endl;

13.}

14.else

15.{

16.cout<<"not equal"<<endl;

17.}

18. 

19.cout<<&chr[0]<<endl;

20.cout<<&p<<endl;

21.cout<<&(*mychr)<<endl;

22.cout<<**mychr<<endl;

23.system("pause");

24.return 0;

25.}

 

 

 

二维数组指针指向一维数组

#include<stdio.h>

int main()
{
int array[5]={1,2,3,4,5};

int (*p)[5]=&array;

for(int i=0;i<5;i++)
{
printf("%d ",*(*p+i));
}

printf("\n");

return 0;
}
在这里面我们定义了一个指针变量p,这个指针变量指向的是一个含有5个元素的一维数组,它指向的是一个一维数组的整体,所以将用&array赋值给它,*p其实是*(p+0),按照我们一维数组的理解,*(p+0)应该是指向我们数组的第一个元素,即p[0],也即我们所指数组的第一个元素&array[0],这个地址再后移i个元素后得到我们想要的地址,然后再加上*就得到本地址里面所存储的整形数据的内容。

博客:http://blog.csdn.net/zwb8848happy/article/details/7389622

对二维指针和二维数组讲解的非常详细

(二)二维数组和指针

(1)地址代表的意义
首先理解,二维数组,例如
int arry[2][3]={{2,3,1},
{23,45,6}};

这样写是最好理解的,也就是说2行3列。其中也可以看成是2个一维数组的整合,也就是
arry[0] = {2,3,1};
arry[1] = {23,45,6};

简单测试一下一些符号究竟代表的是什么意思
printf("n%x",arry);
printf("n%x",arry[0]);
printf("n%x",&arry[0][0]);
printf("n%x",arry+1);
printf("n%x",arry[1]+1);
printf("n%x",&arry[1][1]+1);
从编译运行的结果来看
12ff68
12ff68
12ff68
12ff74
12ff78
12ff7c
arry 是这个数组的名字,也就是代表着入口地址,刚才说了,二维数组实际可以看成N个
一维数组,例如本例中,arry[0] 代表着其中的第一个一维数组,那么 arry[1] 就代表着
第二个一维数组,而且这里是地址,注意 arry[0] 本身就代表着地址了。
arry[0][0]本身代表着这个元素,那么取地址之后 &arry[0][0] 就变成了,这个元素的地址
然而将每个地址加一后发现,这些地址代表的语义并不相同。
arry+1 之后地址变成 12ff68 到 12ff74 也就是说,指向了第二行第一个元素 23
arry[1]本身就代表着第二个一维数组的入口地址,加一之后就只想这个数组的第二个元素
那么就应该指向 45,从地址可以看出。
&arry[1][1]+1 这个是以元素为单位,首先 arry[1][1]这个元素为基准,也就是 45 ,然后
再后移一个元素,所以应该指向 6.
参考


(2)二维数组怎么传递参数

void disparry(int a[2][3])
{
printf("n%d,%d,%d",a[0][0],a[0][1],a[0][2]);
}

void main(void)
{
int arry[2][3]={{2,3,1},
{23,45,6}};
int (*c)[3]=arry;
int *p;

p =(int *)arry;
disparry((int (*)[3])p);

disparry(c);

}

可以通过两种办法,第一是通过 int * 类型的指针 *p 来处理。首先因为 p 是 int* 类型,
而 arry是二维数组,不等价不能直接赋值,那么就简单的将二维数组指针转换为 int* 类型
这样就匹配了,产生的效果是 p 指向了 arry 的入口。
然后 disparry 函数需要的参数的类型是 inta[2][3],很显然,这个时候 p又不能作为参数
了,当然直接传递的话,运行结果不错,但是会有 warning 的。于是再一次将 int * 转换为
需要的 int (*)[3] 类型,说白了,就是 数组指针。
那么第二种办法就很干脆,定义一个数组指针c指向 arry,那么 c就可以直接传递了。

(3)使用 typedef 定义二维数组
typedef int A[2];
A b[3]={32,11,23,45,6,7};
printf("n%d",b[1][0]);

可以看出,先定义一种新的数据类型 A,他是一个 2个元素的一维数组。然后再定义一个含有
3个 A 类型的一维数组b,这样b其实就是一个二维数组了,b[3]代表的是有3行这样的一维数组
所以这样下来实际上等效于 b[3][2]。


C/C++中的二维指针问题--转载 (内存分配

 指针是可变数组的首地址。正因为是可变数组,所以一般使用指针时都是采用动态内存分配和释放的方式。一维指针形式简单,容易理解。平时应用较多。二维数组和二维指针比较复杂,并且在动态内存分配与释放方面比较复杂且难以理解。但是二维数组和二维指针是非常有用的。

     考虑以下应用:对一幅图像进行模板运算。这必然会牵涉到对图像的各象素点的操作。此时使用一维指针进行图像传递时,不可避免的会使用形如*(p+i*width+j)的方式完成对图像象素点的访问。这种方式很不直观并且编写程序时容易出错。如果使用二维指针进行图像数据的传递,则会收到很好的效果。可以采用p[i][j]的方式直接操作象素点,直观又便于维护。因此掌握二维数组和二维指针是必要的。

使用http://www.wangchao.net.cn/bbsdetail_59038.html中的示例。

定义如下3个二维数组和二维指针进行说明:

1.         int** ptr;

2.         int *ptr[M];

3.         int (*ptr)[M];

以上都是存放整数的二维数组,并且都可以通过ptr[i][j]的形式访问内容。但是它们之间有很大的差别。以下依照文中提到的方面进行分析。

l         内容
三个ptr本身都是指针,并且是二维指针,但是它们的最终内容总是整数。但中间内容,形如ptr[i]并不是整数,而是指针int *.

l         意义
1. int** ptr 表示指向(一组指向整数数据指针)的指针;
2. int *ptr[M] 是指针数组,表示指向(M个指向整数指针)的指针;
3. int (*ptr)[M]表示指向一组(指向包含M个整型数据的指针)的指针。

l         所占空间
1和3占用一个内存空间,在32位平台上为4个字节,也就是一个指针。
2是M个指针,在其定义过程中编译器即对其进行了分配,占用4*M共4M个字节。

l         用法
1. int** ptr 表示指向(一组指向整数数据指针)的指针,是一个二维指针。在其定义过程中,编译器并不对其进行内存的分配,因此必须自己管理其内存的分配与释放。典型使用如下:

     
使用上述方法分配内存,最终ptr耗费的内存空间为M*sizeof(int*)+M*N*sizeof(int)

2. int *ptr[M] 是指针数组,表示指向(M个指向整数指针)的指针。是一个二维指针。但是在定义的时候,编译器已经为ptr指向的M个指向整数的指针ptr[0:M-1]分配了内存。也就是说,定义之后即可得到ptr的地址以及用于存放ptr[0:M-1]的内存空间4MB。要使用ptr必须对ptr[i]分配内存。分配内存后,ptr地址相应内存空间填入ptr[i]指向内存地址。使用如下操作:

使用上述方法分配内存,最终ptr耗费的内存空间为M*sizeof(int*)+M*N*sizeof(int),其中M*sizeof(int*)为编译器分配,M*N*sizeof(int)为程序员自己分配。

3. int (*ptr)[M]表示指向一组(指向包含M个整型数据的指针)的指针。该定义限定了ptr[i][0:M-1],所有指针ptr[i]必须指向长度为M的数组。使用方式如下:
  
使用上述方法分配内存后,ptr所占内存空间为M*N*sizeof(int)(不考虑不同操作系统用于管理的内存)。ptr内存空间中保存的为最终内容而非ptr[i]地址。

    

         最后回到开始考虑的应用,使用以下解决方案:

        

[cpp]  view plain copy
  1. // Function Prototype: int test( char* data,  
  2. // const int N_H, const int N_V);  
  3. // Function name: test  
  4. // Return type: int  
  5. // Argument: char* data 输入图像数据  
  6. // Argument: const int N_H, const int N_V 图像尺寸  
  7. int test( char* data, const int N_H, const int N_V);  
  8. {  
  9.     char** ppData = NULL;  
  10.     int i = 0;  
  11.   
  12.     ppData = (char**)malloc(sizeof(char*)*N_V);  
  13.   
  14.     if (ppData == NULL)  
  15.     {  
  16.         printf("Error in mem location!/n");  
  17.         return 0;  
  18.     }  
  19.   
  20.     for (i=0;i<N_V;i++)  
  21.     {  
  22.         ppData[i] = data + i * N_H;  
  23.     }  
  24.            
  25.          //其他操作  
  26.     free(ppData);  
  27.     return 1;  
  28. }  

C++中用new给二维指针分配内存及delete删除


C++中用new可以通过以下方法为二维指针分配内存,例如分配整型5*4的空间:

1、化二维为一维

int *p;

p=new int[5*4];

2、可以直接定义二维指针,通过两步申请内存,但是从二维数组的角度看内存不连续。

int **p;
int x;
p=new int*[5];
for (int i=0;i<5;i++)
{
p[i]=new int[4];
}

使用时:

for(int i=0;i<5;i++)
for(int j=0;j<4;j++)
p[i][j]=i+j;
for(int i=0;i<5;i++)
for(int j=0;j<4;j++)
{
std::cout<<p[i][j];
if(j==3)
std::cout<<std::endl;
}

释放内存时应该注意释放方法:

for(int i=0;i<5;i++)

delete[] p[i];

delete[] p;

3、可以先定义一维指针并分配够需要的空间,然后自己根据情况映射到二维指针。

int *p1=new int[5*4];
int **p;
int x;
p=new int*[5];
for (int i=0;i<5;i++)
{
p[i]=p1+i*4;
}

使用时仍然是:

for(int i=0;i<5;i++)
for(int j=0;j<4;j++)
p[i][j]=i+j;
for(int i=0;i<5;i++)
for(int j=0;j<4;j++)
{
std::cout<<p[i][j];
if(j==3)
std::cout<<std::endl;
}

此时释放空间:

delete[] p;





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值