我正在自学一点C,并且进行了一次练习,希望确保自己完全理解。练习要求我将指向多维整数数组的指针传递给函数,然后遍历该数组。因此,我先使用打印功能,然后再进行输入以填充数组。我尝试了各种方法,但是在类型转换和迭代指针上找到了一些代码之后,我有了下面的程序,该程序似乎可以工作,但我不太了解发生了什么。在我的评论中,我有标记为1-3的问题,是指代码下方的问题。我希望有人比我能启发我。
//passing multi-Array to a simple print function
#include <stdio.h>
//simple print function prototype
void printMyArr(int (*pt)[4]);
int main()
{
//declare and initialize a multi-array. I picked 4x4 and some arbitrary
//numbers for simplicity's sake
int myArr[4][4] = { {12, 16, 19, 20},
{5, 99, 102, 200},
{12, 20, 25, 600},
{65, 66, 999, 1000} };
//declare a pointer to an array of integers and an int for a loop counter
int (*pt)[4], counter;
//initialize the pointer
pt = myArr;
//for loop calling printMyArr function to iterate through arrays -- or this is what I understand it to mean
for(counter=0; counter<4; counter++)
printMyArr(pt++); //<-------------Question 1
return 0;
}
//function called to print array elements to the console
void printMyArr(int(*pt)[4])
{
//declare a counter....and apparently another pointer
int counter, *p;
//initialize new pointer to old pointer and type cast array as int
p = (int *)pt; //<-------------Question 2
//for loop to iterate through elements of array -- or this is what I understand it to mean
for(counter=0; counter<4; counter++)
printf("\n\n\n%d", *p++); //<------Question 3
}
问题1:在这里,我将指针传递给了函数,然后我一直在思考:“这个循环在迭代什么?”。我以为我要递增指向每个数组中每个第一个元素的指针(myArr[0][0]
,myArr[1][0]
,myArr[2][0]
,myArr[3][0]
)的正确性吗?另外,我是否假设此行的语法本质上是这样说的:“执行传递当前指针的函数,完成后传递当前指针,然后递增指针。”
问题2:这是我最困惑的地方。经过大量的挖掘之后,我发现该部分可以使其正确运行,并且我知道这是如何工作的,但是为什么呢?
问题3:我是否正确认为自己在这里增加了每个元素?
所以
1:传递指定的指针-> myArr[0][0]
,然后打印myArr[0][0]
,myArr[0][1]
,myArr[0][2]
和myArr[0][3]
中的值,然后递增指针{ {1}}
2:传递指定的指针-> myArr[1][0]
,然后将myArr[1][0]
,myArr[1][0]
,myArr[1][1]
和myArr[1][2]
增量指针中的值打印到{{1 }}
3:传递指定的指针-> myArr[1][3]
,然后将myArr[2][0]
,myArr[2][0]
,myArr[2][0]
和myArr[2][1]
增量指针中的值打印到{{1 }}
4:传递指定的指针-> myArr[2][2]
,然后将myArr[2][3]
,myArr[3][0]
,myArr[3][0]
和myArr[3][0]
增量指针中的值打印到{{1 }},如果是这种情况,那么由于不应该有myArr[3][1]
,指针指向什么呢?
答案 0 :(得分:2)
问题1:在这里,我将指针传递给了函数,然后我一直在思考:“这个循环在迭代什么?”。我是否认为我正在递增指向每个数组中每个第一个元素的指针(myArr [0] [0],myArr [1] [0],myArr [2] [0],myArr [3] [ 0])?
或多或少。 pt
从myArr
的地址开始。您知道数组中有4件事,因此您循环4次,每次访问pt
后都将printMyArr
递增一次,以传递给printMyArr
“顶层”,“外部”数组。然后pt
遍历内部数组的4个元素以显示每个数字。
此外,我是否假设此行的语法本质上是这样说的:“执行传递当前指针的函数,然后在完成后传递指针,然后递增指针。”
从功能上讲,是的。从技术上讲,操作顺序如下:
1)获得pt
的值
2)递增pt
3)调用函数,从步骤1开始传递pt
的先前值
pt++
作为pt++
调用的一部分而增加,但是pt++
的值为旧值。作为函子的参数,必须在传递给函数的函数运行前 评估p = (int *)pt;
for(counter=0; counter<4; counter++)
printf("\n\n\n%d", *p++);
。但是,时间与在针对您的案例运行该函数后立即进行评估的时间相同。
让我们一起回答问题2和3,因为它们都是答案的一部分。
问题2:这是我最困惑的地方。经过大量的挖掘之后,我发现该部分可以使其正确运行,并且我知道这是如何工作的,但是为什么呢?
问题3:我是否正确地认为我要在此处增加每个元素?
p
p
存储一个整数地址。您将其设置为内部数组第一个元素的地址(可以这么说,它是内部数组本身的地址)。然后,知道数组中有4个元素,就可以循环4次,对pt
进行类似于外部数组p
的指针后递增操作。>
第一次迭代pt
与*p
相同,即存储器中4个整数值中第一个整数的地址。 *p++
取消引用指针,将获取第一个整数。由于p
的运算顺序(++为最高优先级,而对*的引用为更低),它返回p
处的整数,而p
指向该地址的下一个整数地址下一个循环。
通常为casting values in C should be avoidid whenever possible。您只需要在这里进行解引用即可将pt
指向整数集。 *pt
在内存中包含4个整数(内部数组)的连续集合的4个地址(外部数组)之一的地址。 int* p=*pt;
处的值是内存中4个连续整数的“当前”组的地址。所以您可以简单地说,
USE
这不是任意转换类型,非常简单明了。 (感谢@WhozCraig)
答案 1 :(得分:1)
多个D数组作为连续数组保留在内存中,因此,如果您有数组[2] [2],它将分配4个连续的sizeof(int)。您需要定义array [] [COL]的原因是让编译器知道应该如何执行指针算术。
所以-对于Q1,您是对的,每次增加(sizeof(int)* COL)都这样做。因此,每次您移动一行。
现在Q2-对于要一次打印一个int值的每一行,因此当您有int * p-时,这意味着每个增量都由sizeof(int)完成。
Q3-增量是指针,而不是值,如果在主体中进行其他打印很容易自己看到。
希望有帮助,祝您好运!
答案 2 :(得分:0)
2D
myArr
数组的内存视图如下所示:
myArr
---------------------
myArr[0] | 12 | 16 | 19 | 20 |
---------------------
myArr[1] | 5 | 99 |102 |200 |
---------------------
myArr[2] | 12 | 20 | 25 |600 |
---------------------
myArr[3] | 65 | 66 |999 |1000|
---------------------
Question 1: Here, I've passed the pointer to the function and I keep thinking, "What is this loop iterating over?". Am I correct in thinking that I am incrementing the pointer to each of the first elements in each array (myArr[0][0], myArr[1][0], myArr[2][0], myArr[3][0])? Also, am I correct in assuming that the syntax of this line is in essence saying: "Execute the function passing the current pointer and THEN when it's done, increment the pointer."?
int (*pt)[4]
pt
是指向4
整数数组的指针。此声明
pt = myArr;
使pt
指向1D
myArr
数组的第一个2D
数组。它类似于:
pt = &myArr[0];
这两个语句的影响将是这样的:
pt--------|
\|/
---------------------
myArr[0] | 12 | 16 | 19 | 20 |
---------------------
当您递增指针时,它会按照指针可以指向的对象大小逐步递增。在这里
printMyArr(pt++);
首先将pt
指针值传递给printMyArr()
,然后将pt
递增,由于其类型为int (*)[4]
,这意味着它可以指向一个4
整数数组,因此在递增之后,pt
将指向地址(即address pointing to
+ size of array of 4 int
),即myArr[1]
地址。
请注意,
for(counter=0; counter<4; counter++)
printMyArr(pt++);
与此相同:
for(counter=0; counter<4; counter++)
printMyArr(&myArr[counter]);
^^^^^^^^^^^^^^^
Question 2: This is what has me the most confused. After quite a bit of digging I found this bit to make it run right and I realize this is how it works, but why?
这里
p = (int *)pt; // pt is pointer to an array of `4` integer
如果删除(int *)
强制转换,则会发现编译器在此语句上发出警告消息。原因是p
和pt
不是兼容的指针类型。 p
的类型为int *
,而pt
的类型为int (*)[4]
。这种不兼容的指针分配之所以起作用,是因为尽管类型不同,但数组的地址和数组的第一个元素的地址在数字上是相同的。相反,您应该
p = &(*pt)[0];
根据C Standards#6.5.2.1
下标运算符[]的定义是E1 [E2]等于(*(((E1)+(E2))))
按此规则
&(*pt)[0] --> &(*((*pt)+(0))) --> ((*p)+(0)) --> *p
The operator & is used to get the address and the operator * is used for dereferencing. These operators cancel the effect of each other when used one after another.
因此,此声明
p = &(*pt)[0];
与此声明相同
p = *pt;
Question 3: Am I correct thinking that I am incrementing each element here?
是的。
p
是指向4
整数数组的第一个元素的指针,其类型为int *
,即它可以指向一个int
的对象。当您执行*p++
时,这将首先取消引用p
并在其指向的地址处获取值,然后p
将递增并指向数组的下一个元素。>