传递多维数组的困难 [英] Difficulties with passing multi-dimensional arrays

查看:65
本文介绍了传递多维数组的困难的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将一个切片从一个较大的二维数组传递给一个

函数,该函数将在数组空间的较小区域上运行。下面的

代码是我想要完成的事情的升华。


// - - - - - - - - 开始代码 - - - - - - -

typedef int sm_t [4] [4];

typedef int bg_t [8] [8];


sm_t sm;

bg_t bg;


void set_slice(sm_t);


int main()

{

set_slice((sm_t *)& bg [0] [0]);

}


set_slice(sm_t my_sm)

{

static int i;

i ++;


my_sm [0] [0] =我;

}

// - - - - - - - - 结束代码 - - - - - - -


这个代码可以工作但是我必须注释掉原型才能在gcc下编译

。如果我添加原型,我会得到编译错误


mar.c:30:警告:从不兼容的

指针类型传递`set_slice'的arg 1

mar.c:41:`set_slice'的冲突类型'

mar.c:16:先前声明`set_slice''


提前感谢任何指导。

解决方案

> typedef int sm_t [4] [4];

typedef int bg_t [8] [8];

sm_t sm;
bg_t bg;

void set_slice(sm_t);

int main()
{
set_slice((sm_t *)& bg [0] [0]);
}


将typedef更改为内部的样式:


void set_slice(int(*)[4]);


set_slice((int(*)[4] [4])& bg [0] [0]);


你' '将指向4x4矩阵的指针传递给期望指向4元素数组的指针的函数,现在你可以看到编译器为什么会婊子。


6.7.5.2/6对于两个要兼容的数组类型,两者都应具有

兼容的元素类型,并且如果两个大小说明符都存在,并且

是整数常量表达式,那么两个大小说明符都应该具有相同的常量值

。如果两个数组类型在上下文中使用

,这要求它们兼容,如果

两个大小说明符计算为不相等的值,则它是未定义的行为。


使用这样的强制转换打破了C别名规则。 GCC很漂亮

关于别名的肛门,并且已知生成代码,这给了b
不小心程序员不正确的结果(甚至导致崩溃)。

set_slice(sm_t my_sm)




你错过了这里的void返回类型。 C99摆脱了隐含的int

(无论如何都与原型不兼容)。


我会这样做:


#define MAT_WIDTH(x)(sizeof(x [0])/ sizeof((x)[0] [0]))


void ones(int * mat,size_t height,size_t width,size_t pitch)

{

断言(宽度< =音高);


for(size_t h = 0; h< height; ++ h){

int * m = mat [h * pitch];

for(size_t w = 0 ; w< width; ++ w)

* m ++ = 1;

}

}


/ *

注意:你不能用mat + = pitch代替mat [h * pitch],一般来说这是非法的

因为C只能保证在

数组结束后1。

* /


int bg [8] [8] = {};

(& bg [4] [4],4,3,MAT_WIDTH(bg));


/ *

00000000

00000000

00000000

00000000

00001110

00001110

00001110
00001110

* /


truckaxle写道:

void set_slice(sm_t );
set_slice(sm_t my_sm)


第一个返回void。

第二个返回int。


这是一种类型不匹配,所以它还会抛出prev decl

错误,因为它认为你试图另外定义一个新的

函数预先存在的名字。

{
static int i;
i ++;

my_sm [0] [0] = i;
}
// - - - - - - - - 结束代码 - - - - - - -
mar.c:30:警告:从不兼容的br传递`set_slice'的arg 1 />指针类型


因为你试图将指针传递给

不想要指针的函数。

mar.c:41:`set_slice'的冲突类型'
mar.c:16:之前的'set_slice'声明'

提前感谢任何指导。< /集团kquote>


这就是你想要的:


typedef int sm_t [4] [4];

typedef int bg_t [8] [8];


sm_t sm;

bg_t bg;


void set_slice (sm_t *);


int main(无效)

{

set_slice((sm_t *)& bg [0 ] [0]);


返回(0);

}

void set_slice(sm_t * my_sm)

{

static int i;

i ++;


* my_sm [0] [0] = i ;

}


2005年6月10日14:52:58 -0700, cl **** @ anodized.com 写道:

truckaxle写道:

void set_slice( sm_t);
set_slice(sm_t my_sm)
第一个返回void。
第二个返回int。

这是一个类型不匹配所以它还要扔掉关闭prev decl
错误因为它认为你试图另外定义一个ew
具有预先存在的名称的功能。



这是一种类型不匹配,必须进行诊断。你实际上是试图定义之前刚刚声明的函数
;如果

编译器认为它是正确的。

{
static int i;
i ++;

my_sm [0] [0] =我;
}
// - - - - - - - - 结束代码 - - - - - - -


mar.c:30:警告:从不兼容的
指针类型传递`set_slice'的arg 1



因为你试图将指针传递给一个不需要指针的函数。



实际上它确实需要一个指针,因为int [4] [4]作为参数是

''调整''到int(*)[4]。但正如诊断所说,它不希望你指示的_type_指针试图给它。

mar.c:41:'set_slice'的冲突类型'
mar.c:16:之前的'set_slice'声明'

提前感谢任何指导。



这就是你想要的:

typedef int sm_t [4] [4];
typedef int bg_t [8] [8];

sm_t sm;
bg_t bg;



似乎没有必要使用sm(在OP代码中)。

void set_slice(sm_t *);

int main(void)
{
set_slice((sm_t *)& bg [0] [0]);

返回(0);
}

void set_slice(sm_t * my_sm)
{
static int i;
i ++;

* my_sm [0] [0] = i;
}




这解析为*(my_sm [0] [0 ])因此仅适用于第0行。尝试

来执行* my_sm [1] [2]或类似会调用Undefi ned行为很可能

表现为访问(破坏)完全错误的存储。


(* my_sm)[x] [y]会正确访问sm_t对象嵌入在

中的bg_t对象bg - 但不是OP要求的_slice_:它将

从bg [4] [4]开始处理16个整数机智bg [4] [4:7] bg [5] [0:7]

bg [6] [0:3]作为4乘4矩阵,例如(* my_sm)[3] [1]在bg [6] [1]。


如果你真的想要一个(> 1D)_slice_,你必须做大步。 />
计算;可能手动地称为Me。做了nextthread,除了缺少

一个一元 - &和ptr + stride和

& ptr [stride]之间的错误区别 - 它们被定义为相同且超级优秀

两者都不能保证超出子阵列(行)但在实践中

他们(两者)都工作。


或者在C99或GNU C中作为扩展使用VLA来执行此操作

你。传递边界是最简单的_first_:

void set_slice(int fullwidth,int(* ary)[fullwidth])

/ *或int ary [] [全宽]如果你愿意,它完全相同* /

{... access ary [0:3] [0:3] ...}

.... set_slice(8,bg)/ *访问bg [0:3] [0:3] * /

/ *或更好地使用类似我的MAT_WIDTH宏* /

set_slice(8,& bg [2])/ *访问bg [2:5] [0:3] * /

set_slice(8,( int(*)[8])& bg [2] [2])/ * bg [2:5] [2:5] * /

/ *这最后一个案例是令人讨厌的,如果经常通过保存偏移指针

或通过下面的扁平指针来更好地处理
* /


如果你真的想要数组参数,你必须要回归

到K& R1语法:

void set_slice(ary,fullwidth)

int fullwidth;

int ary [] [fullwidth];

{...}


或仅在GNU C中使用他们的扩展语法:

void set_slice(int fullwidth; int ary [] [fullwidth],int fullwidth)

{...}


或通过flattened指针:

void set_slice(int * flat,int fullwidth)

{int(* ary)[fullwidth] =(int(*)[fullwidth])flat; ...}

/ *这里的非参数不能使用int ary [] [width] * /

这也可以更容易地传递不在的切片

行的开头(第二个下标非零)。


- 来自worldnet.att.net的David.Thompson1


I am trying to pass a slice from a larger 2-dimensional array to a
function that will work on a smaller region of the array space. The
code below is a distillation of what I am trying to accomplish.

// - - - - - - - - begin code - - - - - - -
typedef int sm_t[4][4];
typedef int bg_t[8][8];

sm_t sm;
bg_t bg;

void set_slice (sm_t);

int main ()
{
set_slice( (sm_t *)&bg[0][0]);
}

set_slice (sm_t my_sm)
{
static int i;
i++;

my_sm[0][0] = i;
}
// - - - - - - - - end code - - - - - - -

This code works however I have to comment out the prototype to compile
under gcc. If I add the prototype I get compile errors with

mar.c:30: warning: passing arg 1 of `set_slice'' from incompatible
pointer type
mar.c:41: conflicting types for `set_slice''
mar.c:16: previous declaration of `set_slice''

Thanks in advance for any guidance.

解决方案

> typedef int sm_t[4][4];

typedef int bg_t[8][8];

sm_t sm;
bg_t bg;

void set_slice (sm_t);

int main ()
{
set_slice( (sm_t *)&bg[0][0]);
}
Changing the typedefs to what it looks like internally:

void set_slice(int (*)[4]);

set_slice( (int (*)[4][4]) &bg[0][0] );

You''re passing a pointer to a 4x4 matrix to a function expecting a
pointer to a 4 element array, now you can see why the compiler bitches.

6.7.5.2/6 "For two array types to be compatible, both shall have
compatible element types, and if both size specifiers are present, and
are integer constant expressions, then both size specifiers shall have
the same constant value. If the two array types are used in a context
which requires them to be compatible, it is undefined behavior if the
two size specifiers evaluate to unequal values."

Playing with casts like this breaks the C aliasing rules. GCC is pretty
anal about aliasing and has been known to generate code which gives
unwary programmers incorrect results (and even causes crashes).
set_slice (sm_t my_sm)



you''re missing the void return type here. C99 got rid of implicit int
(which is incompatible with the prototype anyway).

Here is how I would do it:

#define MAT_WIDTH(x) (sizeof(x[0])/sizeof((x)[0][0]))

void ones(int *mat, size_t height, size_t width, size_t pitch)
{
assert(width <= pitch);

for (size_t h = 0; h < height; ++h) {
int *m = mat[h*pitch];
for (size_t w = 0; w < width; ++w)
*m++ = 1;
}
}

/*
Note: you cannot replace mat[h*pitch] with mat += pitch, it is illegal
to do that in general because C only guarantees 1 past the end of the
array.
*/

int bg[8][8] = { };
ones(&bg[4][4], 4, 3, MAT_WIDTH(bg));

/*
00000000
00000000
00000000
00000000
00001110
00001110
00001110
00001110
*/


truckaxle wrote:

void set_slice (sm_t);
set_slice (sm_t my_sm)
First one returns void.
Second one returns int.

That is a type mismatch so it''s additionally throwing off the prev decl
error because it thinks you''re trying to additionally define a new
function with a pre-existing name.
{
static int i;
i++;

my_sm[0][0] = i;
}
// - - - - - - - - end code - - - - - - - mar.c:30: warning: passing arg 1 of `set_slice'' from incompatible
pointer type
Because you''re trying to pass a pointer to a function that
doesn''t want a pointer.
mar.c:41: conflicting types for `set_slice''
mar.c:16: previous declaration of `set_slice''

Thanks in advance for any guidance.



This is what you want:

typedef int sm_t[4][4];
typedef int bg_t[8][8];

sm_t sm;
bg_t bg;

void set_slice (sm_t *);

int main (void)
{
set_slice( (sm_t *)&bg[0][0]);

return (0);
}
void set_slice (sm_t *my_sm)
{
static int i;
i++;

*my_sm[0][0] = i;
}


On 10 Jun 2005 14:52:58 -0700, cl****@anodized.com wrote:

truckaxle wrote:

void set_slice (sm_t);
set_slice (sm_t my_sm)
First one returns void.
Second one returns int.

That is a type mismatch so it''s additionally throwing off the prev decl
error because it thinks you''re trying to additionally define a new
function with a pre-existing name.


It''s a type mismatch and must be diagnosed. You are in fact trying to
define the function which was previously just declared; if the
compiler believes that it is correct.

{
static int i;
i++;

my_sm[0][0] = i;
}
// - - - - - - - - end code - - - - - - -


mar.c:30: warning: passing arg 1 of `set_slice'' from incompatible
pointer type



Because you''re trying to pass a pointer to a function that
doesn''t want a pointer.


Actually it does want a pointer, because int[4][4] as a parameter is
''adjusted'' to int(*)[4]. But it doesn''t want the _type_ of pointer you
are trying to give it, as the diagnostic says.

mar.c:41: conflicting types for `set_slice''
mar.c:16: previous declaration of `set_slice''

Thanks in advance for any guidance.



This is what you want:

typedef int sm_t[4][4];
typedef int bg_t[8][8];

sm_t sm;
bg_t bg;


There doesn''t seem any need for sm (in the OP code).
void set_slice (sm_t *);

int main (void)
{
set_slice( (sm_t *)&bg[0][0]);

return (0);
}
void set_slice (sm_t *my_sm)
{
static int i;
i++;

*my_sm[0][0] = i;
}



This parses as * (my_sm [0] [0]) and so works only for row 0. Trying
to do *my_sm[1][2] or such would invoke Undefined Behavior most likely
manifested as accessing (clobbering) totally wrong storage.

(*my_sm)[x][y] would correctly access an sm_t object embedded within
the bg_t object bg -- but not a _slice_ as the OP asked for: it will
treat the 16 ints starting at bg[4][4] to wit bg[4][4:7] bg[5][0:7]
bg[6][0:3] as a 4 by 4 matrix with e.g. (*my_sm)[3][1] at bg[6][1].

If you really want a (>1D) _slice_ you have to do the stride
calculation; possibly manually as "Me" did nextthread, except missing
one unary-& and the false distinction between ptr + stride and
&ptr[stride] -- they are defined as identical and hyperpedantically
neither is guaranteed to work beyond a subarray (row) but in practice
they (both) work.

Or in C99 or in GNU C as an extension use a VLA which does this for
you. It''s easiest to pass the bound(s) _first_:
void set_slice (int fullwidth, int (*ary) [fullwidth] )
/* or int ary [] [fullwidth] if you prefer, it''s exactly equivalent */
{ ... access ary[0:3][0:3] ... }
.... set_slice (8, bg) /* accesses bg[0:3][0:3] */
/* or better use something like Me''s MAT_WIDTH macro */
set_slice (8, &bg[2]) /* accesses bg[2:5][0:3] */
set_slice (8, (int(*)[8])&bg[2][2]) /* bg[2:5][2:5] */
/* this last case is yucky and if at all frequent
would be handled better by saving an offset pointer
or by going through a flattened pointer as below */

If you really want the array parameter first, you must either regress
to K&R1 syntax:
void set_slice (ary, fullwidth)
int fullwidth;
int ary [] [fullwidth];
{ ... }

or in GNU C only use their extension syntax:
void set_slice (int fullwidth; int ary [] [fullwidth], int fullwidth )
{ ... }

or go through a "flattened" pointer:
void set_slice (int * flat, int fullwidth)
{ int (* ary) [fullwidth] = ( int (*) [fullwidth] ) flat; ... }
/* here for a nonparameter canNOT use int ary [] [width] */
which also makes it easier to pass a slice that is not at
the beginning of a row (second subscript nonzero).

- David.Thompson1 at worldnet.att.net


这篇关于传递多维数组的困难的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆