传递2D数组结构
我从数组中处理卡片类型结构。
struct card deck[DECKSIZE]; //The deck is an array of cards structures
我正在使用2Darrays。 一组卡片类型结构的数组
struct card allHands[hands][cards];
我使用此函数将deck和数组作为指针传递给数组的参数。 我还改变了甲板指针的位置,以模拟在传递给玩家时丢失牌的牌组。
void dealHands(struct card *deck, struct card **handArray, int hands, int cards){ int players; int cardCount; int passCard = 0; struct card * thisDeck; thisDeck = deck; for(players = 0; players < hands; players++){ for(cardCount = 0; cardCount < cards; cardCount++){ handArray[players][cardCount] = thisDeck[passCard]; passCard++; } } deck = (deck + passCard); }
我用c编程了很长一段时间,所以我觉得这就是你做原型的方法吗?
void dealHands(struct card[], struct card*[], int, int);
这就像我主要是如何实现这个function的骨架。
int main(int argc, char *argv[]) { /* Declare and initialize variables */ int hands = atoi(argv[HANDSINPUT]); //How many players int cards = atoi(argv[CARDSINPUT]); //How many cards per hand struct card deck[DECKSIZE]; //The deck is an array of cards structures struct card allHands[hands][cards]; //Builds the deck //Shuffles deck with a RNG and swapping every card int players; int cardCount; int passCard = 0; dealHands(deck, allHands, hands, cards); }
我在编译期间得到以下2个语句
警告:从不兼容的指针类型[默认启用] dealHands(deck,allHands,hands,cards)传递’dealHands’的参数2; ^
注意:预期’struct card **’但参数类型为’struct card( )[(sizetype)(cards)]’void dealHands(struct card [],struct card [],int,int); ^
当我需要在函数中调用指针和数组时,我总是搞砸了。 所以我不确定我的逻辑在哪里有缺陷。 我在哪里传递地址而不是值,反之亦然?
将数组作为函数参数传递时最重要的是: 您不能将数组传递给函数或从函数传递数组 。
说,仔细阅读以下内容。 (为简单起见,我将使用int
,但当然你也可以使用其他类型。)
但是你可以传递一个数组的“指向第一个元素的指针”。 幸运的是,C会自动进行转换。 更重要的是,除了三个例外( sizeof
, _Alignof
, &
operators)之外,C会自动将数组的名称转换为这样的指针。 这通常被称为“数组衰减到指向第一个元素的指针”。
但这种衰退不是递归的。 因此,如果将2D数组传递给函数,它会衰减到指向1D数组的指针:
int a[1][2]; // 1 = outer dimension, 2 = inner
传递给函数时
void f(int a[1][2]);
变
int (*a)[2] // pointer to array of inner dimension
或者,可以明确地使用指针语法
void f(int (*a)[2]);
对于所有情况, a
的类型都是int (*)[2]
。 注意括号! 您使用的语法基本上是个人偏好。 我更喜欢所有维度的数组语法,因为它更清楚地记录了意图。
除最外层尺寸外,您必须始终传递所有尺寸。 这仅用于文档而不是必需的(参见下面的示例)。
在函数内部,您使用普通索引运算符:
int t, i; // index variable for ouTer, Inner a[t][i];
请注意,这可以应用于更高维度的数组。 对于1Darrays,这实际上也适用。 只需删除内部维度:
int a[1];
衰败到
int *a;
(我只使用常量1
和2
来标注尺寸;当然你可以使用你想要的尺寸。)
如果要传递具有可变长度的数组(VLA,_variable length array),则必须将除最外层维度之外的所有维度传递给函数:
f(int inner, a[][inner]);
但更好的检查等是通过所有维度:
f(int outer, int inner, a[outer][inner]);
所有这些都可能有点难以理解,但是一旦你试验它就很容易了。 你看,你永远不能将整个数组作为参数传递(我的意思是你可以通过传递每一个元素,但这不是重点)。 数组基本上是一种表格。 如果它是1D,你有一排盒子。 如果它是2D,你有一个盒子表。 如果它是3D,你有一个箱子(e / oid)。 你可以做的是利用数字如何在内存中布局并使用指针算法。 这很简单。
好的,我们走吧-
假设我们有一个函数set_up_array,它将指向2D数组的指针作为参数。
void set_up_array(int **array, int row_size, int column_size){ for(int i = 0; i < row_size; i++){ for(int j = 0; j < column_size; j++){ *((int*)array + i*row_size + j) = i + j + k; } } }
这可能会让你发疯,但在这里和我待在一起没关系。
现在,想象一下您作为表传递的2D数组。 它有行,然后它有列。 你会如何进入这样一个表中的下一个元素? 好吧,你有你的元素的索引,你发现它,对吧? 这就是我们在这里做的事情。
我将首先解释我们将数组转换为int *的原因。 这很简单。 每当我们进行指针数学运算时,C编译器会尝试简化我们的工作(就像一个真正的萌芽......),所以我们只需添加元素的数量,而不是将地址添加到指针中,而是基于此编译器会自动找出我们想要的地址。 现在,问题在于,C编译器通过找出指针所指向的类型的大小来计算出来。 所以,为了让我们的生活变得简单,并且让C编译器感到满意,我们将它转换为int *,这意味着,从这里开始,无论我们添加什么都会添加到初始地址,就像它使用int *一样秒。 现在让我们回到桌面比喻。 我们知道行号和列号。
您可能想要记住的一件事是,此图像的列和行标签相反
为了让我们的生活更加简单,让我们切换到笛卡尔视图(带有x和y坐标的图形视图)。 假设x是水平的,而y是垂直的。 然后我们可以把arrray写成
array[y][x]
这意味着我们想要的元素是x*row_size + y
元素。 我们基本上可以添加到我们函数中的指针,并取消引用它,就像它已经完成一样,只是在那里,我们使用了i和j。