[TL][技术][c++]为何char**类型参数不能传二维数组

165 views
Skip to first unread message

jinhu wang

unread,
Nov 19, 2009, 12:56:29 AM11/19/09
to TopLanguage
void f(char**p);
这个函数为何不能传入下面这样的参数?
char ar[10][10];
f(ar);

alai

unread,
Nov 19, 2009, 1:13:49 AM11/19/09
to pon...@googlegroups.com
因为 ar 的类型不是 char**,而是 (char[10])*

2009/11/19 jinhu wang <wangji...@gmail.com>

Tinyfool

unread,
Nov 19, 2009, 1:29:48 AM11/19/09
to pon...@googlegroups.com
ar的其实就是char*,二维数组是说他的下标是两维,不是说有两重的指针。

如果你想给void f(char**p);传参数,你可以

char ar[]="test";
f(&ar);

2009/11/19 alai <ala...@gmail.com>



--
Tinyfool的开发日记 http://www.tinydust.net/dev/
代码中国网 http://www.codechina.org
myTwitter: http://twitter.com/tinyfool

alai

unread,
Nov 19, 2009, 1:35:14 AM11/19/09
to pon...@googlegroups.com
不能说 ar 就是 char*,如果是的话,那么 ar[0] 就是 char 了。

2009/11/19 Tinyfool <tiny...@gmail.com>

Tinyfool

unread,
Nov 19, 2009, 1:43:11 AM11/19/09
to pon...@googlegroups.com
按照c的逻辑确实可以这么说

2009/11/19 alai <ala...@gmail.com>

windstorm

unread,
Nov 19, 2009, 1:45:25 AM11/19/09
to pon...@googlegroups.com
但ar[0]显然不是char吧

----------------------------------------------------------------------------------
Yours Sincerely
Kun

www.forwind.cn
http://twitter.com/lk_517


2009/11/18 Tinyfool <tiny...@gmail.com>:

alai

unread,
Nov 19, 2009, 1:46:02 AM11/19/09
to pon...@googlegroups.com
没错,在C的底层实现和内存布局上,char[10][10]与char[100]是一样的。但是在语法上还是不能随便互转的。

2009/11/19 Tinyfool <tiny...@gmail.com>

Tinyfool

unread,
Nov 19, 2009, 1:48:21 AM11/19/09
to pon...@googlegroups.com
我说的是char ar[10];那么ar[0]当然是char。

char ar[10][10];的话,ar[0]就是char*,但是ar也还是char*。

2009/11/19 windstorm <likunar...@gmail.com>

Tinyfool

unread,
Nov 19, 2009, 1:49:27 AM11/19/09
to pon...@googlegroups.com
语法当然要注意,但是实质确实是一个东西

2009/11/19 alai <ala...@gmail.com>

windstorm

unread,
Nov 19, 2009, 1:52:13 AM11/19/09
to pon...@googlegroups.com
如果不规定讨论层面的话,很容易跑题的

如果要按照底层本质理解,多维和一维肯定都是一样的,存储同种类型的一片空间而已。

但这里的问题说为啥不能传,明显是语法层面上的问题

----------------------------------------------------------------------------------
Yours Sincerely
Kun

www.forwind.cn
http://twitter.com/lk_517


2009/11/18 Tinyfool <tiny...@gmail.com>:

Tinyfool

unread,
Nov 19, 2009, 1:59:55 AM11/19/09
to pon...@googlegroups.com
对啊,我已经说了怎么可以传了。。。

就我的经验而言,我觉得楼主是遇到了一个函数有char**p的参数,不知道传什么进去好。然后就以为ar[][]是char**的逻辑,所以就传了过去,但是结果不对。

我也给了一个例子,

char ar[]="test";
f(&ar);

在我的经验里面很多程序员都容易把二维数组理解为char**。

2009/11/19 windstorm <likunar...@gmail.com>

Tinyfool

unread,
Nov 19, 2009, 2:05:12 AM11/19/09
to pon...@googlegroups.com
我针对楼主问题写的例子

#include <stdio.h>
#include <string.h>
void f(char**p) {
    printf("%s\r\n",(char*)p);
    strcpy((char*)p,"test");
    printf("%s\r\n",(char*)p);
}

main()
{
    char ar[]="1111111111111";
    f((char**)&ar);
    printf("%s\r\n",ar);
}

当然我承认我对c/c++是半吊子,呵呵

2009/11/19 Tinyfool <tiny...@gmail.com>

jinhu wang

unread,
Nov 19, 2009, 2:05:41 AM11/19/09
to pon...@googlegroups.com
实际用的时候我是这么传的:
char p[100][100];
char *pp[100];
for(int i=0;i<100;++i)
{
 pp[i]=p[i];
}
f(pp);
如果直接强转换传p进去会crash掉,没想明白

2009/11/19 Tinyfool <tiny...@gmail.com>

windstorm

unread,
Nov 19, 2009, 2:42:24 AM11/19/09
to pon...@googlegroups.com
要想直接传p

把f的声明改为

void f(char p[][100])

你直接cast p成char **当然有问题,你只能把二维数组的首地址强制转换为一维指针。

----------------------------------------------------------------------------------
Yours Sincerely
Kun

www.forwind.cn
http://twitter.com/lk_517


2009/11/19 jinhu wang <wangji...@gmail.com>:

jun lin

unread,
Nov 19, 2009, 2:43:19 AM11/19/09
to pon...@googlegroups.com
想了一下,脑袋晕了。char ** argv == char * argv [], 为什么这里就不行?


2009/11/19 jinhu wang <wangji...@gmail.com>

Hook

unread,
Nov 19, 2009, 2:49:22 AM11/19/09
to pon...@googlegroups.com
但 char* [] 不等于 char[][] 啊


2009/11/19 jun lin <linjun...@gmail.com>

Hook

unread,
Nov 19, 2009, 2:56:26 AM11/19/09
to pon...@googlegroups.com
严格的说应该是:(C FAQ 7.3)

一个 T[] 类型的左值如果出现在表达式中,会蜕变为一个指向数组第一个成员的指针(除了三种例外情况)
结果指针的类型是 *T。

并不能说 char** == char* []

Angus Ho

unread,
Nov 19, 2009, 5:10:58 AM11/19/09
to TopLanguage
C中只有一维数组类型,二维数组只是一维数组的一维数组。
而在C中只有一维数组是可以decay成指针类型的
所以对于T[1][1]只能decay成T (*[1]).

kaiix

unread,
Nov 19, 2009, 6:33:17 AM11/19/09
to pon...@googlegroups.com
2009/11/19 Hook <hook.hu@gmail.com>
严格的说应该是:(C FAQ 7.3)

一个 T[] 类型的左值如果出现在表达式中,会蜕变为一个指向数组第一个成员的指针(除了三种例外情况)
结果指针的类型是 *T。

并不能说 char** == char* []

数组的decay规则只能应用一次 也就是蜕变成指向数组的第一个*元素*的指针 对于 char p[100][100] 在传参时会蜕变成char (*p)[100] 指向100个char元素数组的指针

--
Yours Sincerely,
Kai Hou

Fox

unread,
Nov 19, 2009, 9:17:51 PM11/19/09
to TopLanguage
p 是一个指向指针(地址)的指针,ar是一个二维数组的指针(地址),为了可以正确对ar操作,需要能够记录ar的维数信息(10*10),而此处p
做不到。

On 11月19日, 下午1时56分, jinhu wang <wangjinhu...@gmail.com> wrote:

Fox

unread,
Nov 19, 2009, 9:24:27 PM11/19/09
to TopLanguage
因为argv接收的不是二维数组(如args[10][20]),而且指针数组(如args *[20],注意这个20和前一个20是同一个概念),我
们知道作形参的时候,char argv[10]不会分配10B内存,argv只是一个指向一个10B数组的指针。和char *argv是一致的,同
理,char **argv和char *argv[]也是一致的。

On 11月19日, 下午3时43分, jun lin <linjunhal...@gmail.com> wrote:
> 想了一下,脑袋晕了。char ** argv == char * argv [], 为什么这里就不行?
>

> 2009/11/19 jinhu wang <wangjinhu...@gmail.com>


>
> > 实际用的时候我是这么传的:
> > char p[100][100];
> > char *pp[100];
> > for(int i=0;i<100;++i)
> > {
> > pp[i]=p[i];
> > }
> > f(pp);
> > 如果直接强转换传p进去会crash掉,没想明白
>

> > 2009/11/19 Tinyfool <tinyf...@gmail.com>


>
> >> 对啊,我已经说了怎么可以传了。。。
>
> >> 就我的经验而言,我觉得楼主是遇到了一个函数有char**p的参数,不知道传什么进去好。然后就以为ar[][]是char**的逻辑,所以就传了过去,但是结果不对。
>
> >> 我也给了一个例子,
>
> >> char ar[]="test";
> >> f(&ar);
>
> >> 在我的经验里面很多程序员都容易把二维数组理解为char**。
>

> >> 2009/11/19 windstorm <likunarmstr...@gmail.com>


>
> >>> 如果不规定讨论层面的话,很容易跑题的
>
> >>> 如果要按照底层本质理解,多维和一维肯定都是一样的,存储同种类型的一片空间而已。
>
> >>> 但这里的问题说为啥不能传,明显是语法层面上的问题
>
> >>> ----------------------------------------------------------------------------------
> >>> Yours Sincerely
> >>> Kun
>
> >>>www.forwind.cn
> >>>http://twitter.com/lk_517
>

> >>> 2009/11/18 Tinyfool <tinyf...@gmail.com>:


> >>> > 语法当然要注意,但是实质确实是一个东西
>
> >>> > 2009/11/19 alai <ala...@gmail.com>
>
> >>> >> 没错,在C的底层实现和内存布局上,char[10][10]与char[100]是一样的。但是在语法上还是不能随便互转的。
>

> >>> >> 2009/11/19 Tinyfool <tinyf...@gmail.com>


>
> >>> >>> 按照c的逻辑确实可以这么说
>
> >>> >>> 2009/11/19 alai <ala...@gmail.com>
>
> >>> >>>> 不能说 ar 就是 char*,如果是的话,那么 ar[0] 就是 char 了。
>

> >>> >>>> 2009/11/19 Tinyfool <tinyf...@gmail.com>


>
> >>> >>>>> ar的其实就是char*,二维数组是说他的下标是两维,不是说有两重的指针。
> >>> >>>>> 如果你想给void f(char**p);传参数,你可以
> >>> >>>>> char ar[]="test";
> >>> >>>>> f(&ar);
>
> >>> >>>>> 2009/11/19 alai <ala...@gmail.com>
>
> >>> >>>>>> 因为 ar 的类型不是 char**,而是 (char[10])*
>

> >>> >>>>>> 2009/11/19 jinhu wang <wangjinhu...@gmail.com>


>
> >>> >>>>>>> void f(char**p);
> >>> >>>>>>> 这个函数为何不能传入下面这样的参数?
> >>> >>>>>>> char ar[10][10];
> >>> >>>>>>> f(ar);
>
> >>> >>>>> --
> >>> >>>>> Tinyfool的开发日记http://www.tinydust.net/dev/

> >>> >>>>> 代码中国网http://www.codechina.org


> >>> >>>>> myTwitter:http://twitter.com/tinyfool
>
> >>> >>> --
> >>> >>> Tinyfool的开发日记http://www.tinydust.net/dev/

> >>> >>> 代码中国网http://www.codechina.org


> >>> >>> myTwitter:http://twitter.com/tinyfool
>
> >>> > --
> >>> > Tinyfool的开发日记http://www.tinydust.net/dev/

> >>> > 代码中国网http://www.codechina.org

YY H

unread,
Nov 19, 2009, 1:31:49 AM11/19/09
to pon...@googlegroups.com
如果是这样的话,那么ar+1不是会移动char[10]这多的size?

2009/11/19 alai <ala...@gmail.com>:

YuanTuo

unread,
Nov 19, 2009, 1:14:51 AM11/19/09
to pon...@googlegroups.com

nod , 强制转换吧
2009/11/19 alai <ala...@gmail.com>

Cheng, Long

unread,
Nov 19, 2009, 1:52:48 AM11/19/09
to pon...@googlegroups.com
c语言的数组是没有携带大小信息的。如果这里让你传进去了,你在里面写“p[2]
[3]”这样的语句,编译器就算知道你char**p是个二维数组,也无法知道你这个
char**p的参数每一个数组维度分别是多少,自然也就无法计算p[2][3]的正确地址。

jinhu wang 写道:

Li Yang

unread,
Nov 19, 2009, 1:09:59 AM11/19/09
to pon...@googlegroups.com
类型都不一样,怎么能传呢,
建议你看看 The C++ programming language 的函数那一章

2009/11/19 jinhu wang <wangji...@gmail.com>



--
While(!success=try())

darkraven

unread,
Nov 19, 2009, 7:25:53 AM11/19/09
to pon...@googlegroups.com
char *ar[]={
"a","b","c"};
f(ar);

CPU rong

unread,
Nov 19, 2009, 10:33:36 PM11/19/09
to pon...@googlegroups.com
严格来说,指针和数组是不一样的,在2个地方的时候他们可以等同的(只是等同)
1.函数的形参(编译会自动的把一维数组变成一个指针)
2.在表达式里也是可以等同,比如像a[i]就是被编译器翻译成*(a+i)的,所以这时候数组和指针可以等同,不过也有表达式中是不能等价的。(a[2]和2[a]这样两个是一样,而且还可以运行正确)

而现在的问题是为什么char** p不能接受char  ar[10][10]

我先说说规定是怎么样的哦
1.数组的数组,也是是 char ar[10][10]   ,与他相适应的形参应该是  char (*p)[10](这个叫做数组指针)
2.指针数组   (char* ch[10])  ,与他相适应的形参是  char**p (指针的指针)比如在C++main函数的形参是char **argv 与char*argv[],
3.如果是数组指针话,那他的形参是不变的,必须还是数组指针
4.如果是指针的指针(char **ch),形参也就是指针的指针了。

说说为什么不一样吧?
在p[10][10]中要去p[i][j]这个数话,编译器会把它翻译成*(*(p+i)+j)这样的形式,关键在于这个的p[i](这个会随着p[i]的定义不同而不一样的)
假设p的地址是5000吧
第一步:取i的值,长度已经调整为一行的宽度(这里是10),然后把i*10加到5000
第二步:取j的值。长度调整为一个元素的宽度(这里是1),然后就加到前面的那个值上。
第三补:就是把5000+i*10+j*1这个地址的内容取出来就可以了。

而指针数组(char* p[10])假设他的p也是5000,他去数的过程却去上面的不一样的。
1.先去i值,这里的长度是指针的长度为4字节,然后把4*i加到5000,
2.然后从这个(5000+4*i)地址中取出内容,假设是6789
3.取j值,长度是为一个元素的长度(1个字节),然后吧j*1+6789
4.然后就取出这个地址的内容就可以了。

讲上面这些主要是为了说明为什么char  p[i][j]和 char **p(char* p[10])是不一样的,因为他们取数的过程是不一样的,一个是要知道一行的宽度才能进行地址的运算然后找出你所要的那个值,而指针数组,则不用,给他他就是能找到这个数的。

如果你一定要使用char **ch当形参的话,方法可以是:
在构建数组的时候使用动态分配就可以了

char **p=new char*[10];
for(int i=0;i<10;i++)
{
  p[i]=new char[10];
}
这样也是可以的。
2009/11/20 Fox <yul...@gmail.com>

jinhu wang

unread,
Nov 22, 2009, 8:45:14 PM11/22/09
to pon...@googlegroups.com
用c的感觉真是不爽,还是用c++好,把接口改成vector<string>&就了事了。呵呵

2009/11/19 darkraven <drdar...@gmail.com>

Justin Turner

unread,
Nov 21, 2009, 8:06:32 PM11/21/09
to pon...@googlegroups.com
对于一维数组,如:
char arr[10];
 
1)  类型分析:arr类型为char [10], 作为参数传递时会根据decay规则退化成char *
函数原型void  f(char arr[10])  或  void  f(char *arr) (根据语境可以进一步变为 void f(const char * arr)void f(char * const arr)void f(const char * const arr))。如若不希望参数退化为“4字节”(32位系统)的指针,则原型可以写为 void f(char (&arr)[10])
调用方法f(arr)
 
2) 类型分析:&arr类型为char (*)[10], 它本质上是一个指针,指向具有10个元素的char型数组
函数原型: void  f(char (*arr)[10])(根据语境可以进一步变为 void f(const char (*arr)[10])void f(char (* const arr)[10])void f(const char (* const) arr[10]))。由于&arr已经是一个指针,所以这里不存在退化的问题。
调用方法f(&arr)
 
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 
对于二维数组,如:
char arr[10][10];
 
1)  类型分析:arr类型为char [][10], 作为参数传递时会根据decay规则退化成char (*)[10]
函数原型void  f(char arr[][10])  或  void  f(char (*arr)[10]) (根据语境可以进一步变为 void f(const char (*arr)[10])void f(char (* const arr)[10])void f(const char (* const arr)[10]))。如若不希望参数退化为“4字节”(32位系统)的指针,则原型可以写为 void f(char (&arr)[10][10])
调用方法f(arr)
 
2) 类型分析:&arr类型为char (*)[10][10], 它本质上是一个指针,指向具有10个元素类型为char(*)[10]的数组
函数原型: void  f(char (*arr)[10][10])(根据语境可以进一步变为 void f(const char (*arr)[10][10])void f(char (* const arr)[10][10])void f(const char (* const) arr[10][10]))。由于&arr已经是一个指针,所以这里不存在退化的问题。
调用方法f(&arr)
 
 
 
 

Alex Lee

unread,
Nov 22, 2009, 5:48:53 AM11/22/09
to pon...@googlegroups.com
说得很全面。

2009/11/20 CPU rong <smy19...@gmail.com>



--
Nick Name:cayenne
Website:http://hi.csdn.net/forever_feng
Blog: http://blog.csdn.net/forever_feng

Haibo Huang

unread,
Dec 1, 2009, 11:06:38 PM12/1/09
to TopLanguage
语法是一回事,不过其实从汇编的角度考虑,这样设计语法是必然的。
char **是指向char*类型(数组)的指针。而实际实现二维数组的时候完全是另一套实现机制。不可能有直接的转换方法。

Zhiming G

unread,
Dec 2, 2009, 11:39:52 AM12/2/09
to pon...@googlegroups.com
对, 类似 下面两个的区别
extern char A[];
extern char B*;

2009/12/2 Haibo Huang <hng...@gmail.com>

xiaofei huang

unread,
Jan 11, 2010, 1:45:58 AM1/11/10
to pon...@googlegroups.com
其实在早期的C编译器里面二维数组和char **是等价的。我记得严蔚敏的《数据结构》里面霍夫曼树的那个例子里貌似还这么用过。不过C++的话可能编译器对这个等价并不赞同,毕竟直接使用"指向指针的指针”还是不太安全的,容易造成访问的混乱。

Zhiming G

unread,
Jan 11, 2010, 10:42:36 AM1/11/10
to pon...@googlegroups.com
现在他们在"某些"情况下也是等价的~

2010/1/11 xiaofei huang <huangxia...@gmail.com>

Xpol Wan

unread,
Jan 13, 2010, 6:11:22 AM1/13/10
to pon...@googlegroups.com


2010/1/11 Zhiming G <gao...@gmail.com>

现在他们在"某些"情况下也是等价的~

2010/1/11 xiaofei huang <huangxia...@gmail.com>

其实在早期的C编译器里面二维数组和char **是等价的。我记得严蔚敏的《数据结构》里面霍夫曼树的那个例子里貌似还这么用过。不过C++的话可能编译器对这个等价并不赞同,毕竟直接使用"指向指针的指针”还是不太安全的,容易造成访问的混乱。

我不知道你说的是什么早期编译器啊。
这个如果双指针和指向二位数组的指针等价的话,那么:
对于双指针执行pp[10][5]
 该怎么对10和5进行指针调整呢?

--
Best Regards!

Xpol Wan
Reply all
Reply to author
Forward
0 new messages