将结构数组传递给函数 C++
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3613302/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Passing array of structures to function c++
提问by Nick Sinas
Sorry for the noob question I'm just a little confused.
If I have an array of structures in main that I want to pass to a function:
对不起,菜鸟问题我只是有点困惑。
如果我在 main 中有一个结构数组,我想传递给一个函数:
struct MyStruct{
int a;
int b;
char c;
mayarray[5];
};
MyStruct StructArray[10];
myFunction(StructArray[])
Pass to this to a function:
将此传递给一个函数:
void myFunction(struct MyStruct PassedStruct[])
{
PassedStruct[0].a = 1;
PassedStruct[0].b = 2;
// ... etc
}
My question is, will calling the function like this modify the data in StructArray
? I need it to. Would that be call by reference? I'm a little confused. How would I change it so that when I pass the array of structures to the function, the function will modify the array StructArray
? I'musing visual studio btw.
Thanks.
我的问题是,调用这样的函数会修改中的数据StructArray
吗?我需要它。这会是引用调用吗?我有点困惑。我将如何更改它以便当我将结构数组传递给函数时,函数将修改数组StructArray
?顺便说一句,我在思考视觉工作室。
谢谢。
回答by kriss
struct MyStruct PassedStruct[]
is mostlyan alternative syntax for:
是大多的替代语法:
struct MyStruct * PassedStruct
So yes, you will access and modify the original structure.
所以是的,您将访问和修改原始结构。
Just one detail to change, the correct call to to the function is not
只需更改一个细节,对函数的正确调用不是
myFunction(StructArray[]);
but:
但:
myFunction(StructArray);
Now I will try to explain why I used the word mostlyin the above sentence:
现在我将尝试解释为什么我在上面的句子中主要使用这个词:
I will give some hint at the difference between arrays and pointers, why you shouldn't confuse them (even if I would not say they are unrelated, quite the opposite), and the problem with the above MyStruct PassedStruct[]
parameter passing syntax.
我将给出一些关于数组和指针之间差异的提示,为什么你不应该混淆它们(即使我不会说它们不相关,恰恰相反),以及上述MyStruct PassedStruct[]
参数传递语法的问题。
This is not for beginners, and C++ standard experts should also avoid reading this (because I don't want to get in some - ISO Standard_ war as I enter ISO undefined behaviorterritory - a.k.a. forbidden territory).
这不适合初学者,C++ 标准专家也应该避免阅读这篇文章(因为我不想在进入 ISO未定义行为领域 - 又名禁止领域时陷入一些 - ISO 标准_War)。
Let's begin with arrays:
让我们从数组开始:
Imagine a simple structure:
想象一个简单的结构:
struct MyStruct{
int a;
int b;
char c;
};
MyStruct a1[3];
is the declaration of an array whose items are of the above structure type. The most important thing the compiler does when defining an array is to allocate space for it. In our example it reserved space for 3 structs. This reserved space can be on stack or from global memory resources depending where the declaration statement is.
MyStruct a1[3];
是其项为上述结构类型的数组的声明。定义数组时,编译器所做的最重要的事情就是为其分配空间。在我们的示例中,它为 3 个结构保留了空间。这个保留空间可以在堆栈上或来自全局内存资源,具体取决于声明语句的位置。
You can also initialize the struct when declaring it like in:
您还可以在声明结构时初始化结构,如下所示:
struct MyStruct a1[3] = {{1, 2}, {3, 4}, {5, 6}};
Notice that in this example, I didn't initialize the c
field but just a
and b
. This is allowed. I could also use designator syntax if my compiler supports it like in:
请注意,在这个例子中,我没有初始化c
场,但只是a
和b
。这是允许的。如果我的编译器支持它,我也可以使用指示符语法,例如:
struct MyStruct a1[3] = {{a:1, b:2}, {a:3, b:4}, {a:5, b:6}};
Now, there is another syntax for defining an array using empty square backets like in:
现在,还有另一种使用空方形 backets 定义数组的语法,例如:
struct MyStruct a2[] = {{1, 2}, {3, 4}, {5, 6}};
The point here is that a2
is a perfectly normal array just like a1
. The array size is not implicit, it is given through the initializer: I have three initializers therefore I get an array of three structs.
这里的重点是这a2
是一个完全正常的数组,就像a1
. 数组大小不是隐式的,它是通过初始化程序给出的:我有三个初始化程序,因此我得到了一个包含三个结构的数组。
I could define an uninitialized array of known size with this syntax. For an uninitialized array of size 3 I would have:
我可以用这个语法定义一个已知大小的未初始化数组。对于大小为 3 的未初始化数组,我将有:
struct MyStruct a2[] = {{},{},{}};
Space is allocated, exactly as with the previous syntax, no pointer involved here.
空间被分配,与前面的语法完全一样,这里不涉及指针。
Let's introduce one pointer:
让我们介绍一个指针:
MyStruct * p1;
This is a simple pointer to a structure of type MyStruct. I can access fields through usual pointer syntax p1->a
or (*p1).a
. There is also an array flavored syntax to do the same as above p1[0].a
. Still the same as above. You just have to remember that p1[0] is a shorthand for (*(p1+0))
.
这是一个指向 MyStruct 类型结构的简单指针。我可以通过通常的指针语法p1->a
或(*p1).a
. 还有一个数组风格的语法来做与上面相同的事情p1[0].a
。还是和上面一样。你只需要记住 p1[0] 是(*(p1+0))
.
Also remember the rule for pointer arithmetic: adding 1 to a pointer means adding the sizeof
the pointed object to the underlying memory address (what you get when you use %p printf format parameter). Pointer arithmetic allows access to successive identical structs. That means that you can access structs by index with p1[0]
, p1[2]
, etc.
还要记住指针算术的规则:向指针加 1 意味着将sizeof
指向的对象添加到底层内存地址(使用 %p printf 格式参数时得到的结果)。指针算术允许访问连续的相同结构。这意味着你可以通过索引访问与结构p1[0]
,p1[2]
等等。
Boundaries are not checked. What is pointed to in memory is the programmer's responsibility. Yes, I know ISO says differently, but that is what all compilers I ever tried do, so if you know of one that does not, please tell me.
不检查边界。在内存中指向的是程序员的责任。是的,我知道 ISO 的说法不同,但这是我尝试过的所有编译器所做的,所以如果您知道有一个没有,请告诉我。
To do anything useful with p1, you have to make it point to some struct of type MyStruct
. If you have an array of such structs available like our a1
, you can just do p1=a1
and p1 will point to the beginning of the array. In other words you could also have done p1=&a1[0]
. It's natural to have a simple syntax available as it's exactly what pointer arithmetic is designed for: accessing arrays of similar objects.
要对 p1 做任何有用的事情,您必须使其指向某个类型为 的结构体MyStruct
。如果你有一个像我们这样的结构数组a1
,你可以这样做p1=a1
,p1 将指向数组的开头。换句话说,你也可以做到p1=&a1[0]
。使用简单的语法是很自然的,因为它正是指针算法的设计目的:访问相似对象的数组。
The beauty of that convention is that it allows to completely unify pointer and array access syntax. The difference is only seen by the compiler:
该约定的美妙之处在于它允许完全统一指针和数组访问语法。差异仅由编译器看到:
when it sees
p1[0]
, it knows it has to fetch the content of a variable whose name isp1
and that it will contain the address of some memory structure.when it sees
a1[0]
, it knowsa1
is some constant that should be understood as an address (not something to fetch in memory).
当它看到 时
p1[0]
,它知道它必须获取名称为 的变量的内容p1
,并且它将包含某个内存结构的地址。当它看到时
a1[0]
,它知道a1
是一些应该被理解为地址的常量(不是要在内存中获取的东西)。
But once the address from p1
or a1
is available the treatment is identical.
但是,一旦地址来自p1
或a1
可用,则处理是相同的。
A common mistake is to write p1 = &a1
. If you do so the compiler will give you some four letter words. Ok, &a1
is also a pointer, but what you get when taking the address of a1
is a pointer to the whole array. That means that if you add 1 to a pointer of this type the actual address will move by steps of 3 structures at once.
一个常见的错误是写p1 = &a1
. 如果你这样做,编译器会给你一些四个字母的单词。好吧,&a1
也是一个指针,但是取地址时得到的a1
是指向整个数组的指针。这意味着如果你给这种类型的指针加 1,实际地址将一次移动 3 个结构的步骤。
The actual type of a pointer of that kind (let's call it p2
) would be MyStruct (*p2)[3];
. Now you can write p2 = &a1
. If you want to access the first struct MyStruct
at the beginning of the memory block pointed to by p2
you will have to write somethings like p2[0][0].a
or (*p2)[0].a
or (*(*p2)).a
or (*p2)->a
or p2[0]->a
.
这种指针的实际类型(我们称之为p2
)将是MyStruct (*p2)[3];
. 现在你可以写p2 = &a1
. 如果您要访问的第一个结构MyStruct
在由指向内存块的开始p2
,你将不得不写出头像p2[0][0].a
或(*p2)[0].a
或(*(*p2)).a
或(*p2)->a
或p2[0]->a
。
Thanks to type system and pointer arithmetic all of these are doing exactly the same thing: fetch the address contained in p2, use that address as an array (a known constant address) as explained above.
多亏了类型系统和指针算法,所有这些都在做完全相同的事情:获取包含在 p2 中的地址,将该地址用作数组(一个已知的常量地址),如上所述。
Now you can understand why pointers and arrays are totally different types that should not be confusedas some may say. In plain words pointers are variable that contains an address, arrays are constant addresses. Please don't shoot me C++ Gurus, yes I know that is not the full story and that compilers keep many other informations along with address, size of pointed (addressed ?) object for example.
现在您可以理解为什么指针和数组是完全不同的类型,不应像某些人所说的那样混淆。简单来说,指针是包含地址的变量,数组是常量地址。请不要向我开枪 C++ Gurus,是的,我知道这不是完整的故事,并且编译器保留了许多其他信息以及地址、指向(寻址?)对象的大小。
Now you could wonder why in parameter passing context you can use empty square brackets and it really means pointer. ? No idea. Someone probably thought it looked good.
现在你可能想知道为什么在参数传递上下文中你可以使用空方括号,它真的意味着指针。? 不知道。有人可能认为它看起来不错。
By the way, at least with gcc, you can also put some value between brackets instead of keeping them empty. It won't make a difference you'll still get a pointer, not an array, and boundaries or type checking are not done. I didn't checked in ISO standard was should be done and if it is required by the standard or if it is a specific behavior.
顺便说一句,至少对于 gcc,您还可以在括号之间放置一些值,而不是将它们留空。它不会有什么区别,您仍然会得到一个指针,而不是一个数组,并且不会进行边界或类型检查。我没有检查 ISO 标准是否应该完成,如果标准要求或者它是特定行为。
If you want type checking for boundaries, just use a reference. That may be surprising but this is an area where if you use a reference, the actual type of the parameter is changed from pointer to array (and not from pointer to reference to pointer as may be expected).
如果您想对边界进行类型检查,只需使用引用即可。这可能令人惊讶,但这是一个区域,如果您使用引用,则参数的实际类型会从指针更改为数组(而不是像预期的那样从指针到引用更改为指针)。
MyStruct StructArray[10];
- header:
void myFunction(struct MyStruct * PassedStruct)
- caller:
myFunction(StructArray)
- status: works, you work with a pointer in PassedStruct
- 标题:
void myFunction(struct MyStruct * PassedStruct)
- 呼叫者:
myFunction(StructArray)
- 状态:有效,您使用 PassedStruct 中的指针
- header:
void myFunction(struct MyStruct PassedStruct[])
- caller:
myFunction(StructArray)
- status: works, you work with a pointer in PassedStruct
- 标题:
void myFunction(struct MyStruct PassedStruct[])
- 呼叫者:
myFunction(StructArray)
- 状态:有效,您使用 PassedStruct 中的指针
- header:
void myFunction(struct MyStruct (& PassedStruct)[10])
- caller:
myFunction(StructArray)
- status: works, you work with a reference to an array of size 10
- 标题:
void myFunction(struct MyStruct (& PassedStruct)[10])
- 呼叫者:
myFunction(StructArray)
- 状态:有效,您使用对大小为 10 的数组的引用
- header:
void myFunction(struct MyStruct (& PassedStruct)[11])
- caller:
myFunction(StructArray)
- status: does not compile, type of array mismatch between prototype and actual parameter
- 标题:
void myFunction(struct MyStruct (& PassedStruct)[11])
- 呼叫者:
myFunction(StructArray)
- 状态:未编译,原型和实际参数之间的数组类型不匹配
- header:
void myFunction(struct MyStruct PassedStruct[10])
- caller:
myFunction(StructArray)
- status: works, PassedStruct is a pointer, size provided is ignored
- 标题:
void myFunction(struct MyStruct PassedStruct[10])
- 呼叫者:
myFunction(StructArray)
- 状态:有效,PassedStruct 是一个指针,提供的大小被忽略
- header:
void myFunction(struct MyStruct PassedStruct[11])
- caller:
myFunction(StructArray)
- status: works, PassedStruct is a pointer, size provided is ignored
- 标题:
void myFunction(struct MyStruct PassedStruct[11])
- 呼叫者:
myFunction(StructArray)
- 状态:有效,PassedStruct 是一个指针,提供的大小被忽略
回答by Philip Potter
Although arrays and pointers are conceptually different things, the waters are very much muddied by function parameters. You can't directly pass an array to a function; you can only pass a pointer. As a result, the language "helpfully" converts a prototype such as this:
虽然数组和指针在概念上是不同的东西,但函数参数的问题非常混乱。您不能直接将数组传递给函数;你只能传递一个指针。结果,该语言“有帮助地”转换了这样的原型:
void foo (char arr[])
into this:
进入这个:
void foo (char *arr)
And when you call the function, you don't pass it a complete array, you pass a pointer to the first element. As a result, inside the function foo
, it will have a pointer to the originalarray, and assigning to elements of arr
will change the array in the caller as well.
当你调用这个函数时,你不会传递一个完整的数组,而是传递一个指向第一个元素的指针。因此,在函数内部foo
,它将有一个指向原始数组的指针,并且分配给 的元素arr
也会改变调用者中的数组。
In allother situations outside of function parameters, array and pointer syntax in declarations are notequivalent, and refer to conceptually different things. But inside function parameter lists, array syntax creates pointer types.
在函数参数之外的所有其他情况下,声明中的数组和指针语法并不等效,并且指的是概念上不同的事物。但是在函数参数列表中,数组语法创建了指针类型。
回答by Falmarri
You could use a std::vector instead. Arrays are very much C constructs, C++ has wrapper classes to prevent exactly these kind of ambiguities
您可以改用 std::vector 。数组是非常多的 C 构造,C++ 有包装类来防止这种歧义
回答by Aaron Anodide
I believe the x[] means the same thing as x* which means "pointer to the type". Since this is the case, you will be modifying the object you pass (you'll need to call it using the &, or 'address of' operator), and you can think of it as a reference.
我相信 x[] 与 x* 意思相同,这意味着“指向类型的指针”。由于是这种情况,您将修改传递的对象(您需要使用 & 或“address of”运算符来调用它),您可以将其视为引用。
回答by cake
When you pass an array as an argument to a function, the array decays to a pointer to the first element of the array.
当您将数组作为参数传递给函数时,数组会衰减为指向数组第一个元素的指针。
So, when inside your function you use [] to access the elements of the array, you are really only doing pointer arithmetics with your initial pointer to get the elements of the ORIGINAL array.
因此,当您在函数内部使用 [] 访问数组元素时,您实际上只是使用初始指针进行指针算术运算以获取原始数组的元素。
So, yeah, you are modifying the original array. And this answer is pretty much independent of what compiler you are using (Although it's good practice, IMHO, to state the compiler in the question like you did)
所以,是的,您正在修改原始数组。而且这个答案几乎与您使用的编译器无关(尽管这是一种很好的做法,恕我直言,像您一样在问题中说明编译器)