Nic*_*nas 18 c++ arrays parameters data-structures
对不起这个菜鸟问题我只是有点困惑.
如果我在main中有一个结构数组,我想传递给一个函数:
struct MyStruct{
int a;
int b;
char c;
mayarray[5];
};
MyStruct StructArray[10];
myFunction(StructArray[])
Run Code Online (Sandbox Code Playgroud)
传递给一个函数:
void myFunction(struct MyStruct PassedStruct[])
{
PassedStruct[0].a = 1;
PassedStruct[0].b = 2;
// ... etc
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,会调用这样的函数修改数据StructArray
吗?我需要它.这可以通过参考来打电话吗?我有点困惑.我如何更改它,以便当我将结构数组传递给函数时,该函数将修改数组StructArray
?我正在使用视觉工作室顺便说一下.
谢谢.
kri*_*iss 27
struct MyStruct PassedStruct[]
Run Code Online (Sandbox Code Playgroud)
是大多的替代语法:
struct MyStruct * PassedStruct
Run Code Online (Sandbox Code Playgroud)
所以是的,您将访问并修改原始结构.
只需更改一个细节,对函数的正确调用不是
myFunction(StructArray[]);
Run Code Online (Sandbox Code Playgroud)
但:
myFunction(StructArray);
Run Code Online (Sandbox Code Playgroud)
现在我将尝试解释为什么我在上面的句子中主要使用了这个词:
我将对数组和指针之间的区别给出一些暗示,为什么你不应该混淆它们(即使我不会说它们是无关的,恰恰相反),以及上述MyStruct PassedStruct[]
参数传递语法的问题.
这不适合初学者,C++标准专家也应该避免阅读这个(因为我不想进入一些 - ISO Standard_ war,因为我进入ISO 未定义的行为领域 - 也就是禁止的领域).
让我们从数组开始:
想象一下简单的结构:
struct MyStruct{
int a;
int b;
char c;
};
Run Code Online (Sandbox Code Playgroud)
MyStruct a1[3];
是数组的声明,其项目具有上述结构类型.编译器在定义数组时最重要的事情是为它分配空间.在我们的例子中,它保留了3个结构的空间.此保留空间可以位于堆栈上,也可以来自全局内存资源,具体取决于声明语句的位置.
您也可以在声明它时初始化结构:
struct MyStruct a1[3] = {{1, 2}, {3, 4}, {5, 6}};
Run Code Online (Sandbox Code Playgroud)
请注意,在此示例中,我没有初始化c
字段,只是a
和b
.这是允许的.如果我的编译器支持它,我也可以使用指定语法:
struct MyStruct a1[3] = {{a:1, b:2}, {a:3, b:4}, {a:5, b:6}};
Run Code Online (Sandbox Code Playgroud)
现在,还有另一种使用空方形支持定义数组的语法,如:
struct MyStruct a2[] = {{1, 2}, {3, 4}, {5, 6}};
Run Code Online (Sandbox Code Playgroud)
这里的重点是,这a2
是一个完全正常的数组a1
.数组大小不是隐式的,它是通过初始化器给出的:我有三个初始化器,因此我得到一个包含三个结构的数组.
我可以用这种语法定义一个已知大小的未初始化数组.对于一个大小为3的未初始化数组,我会:
struct MyStruct a2[] = {{},{},{}};
Run Code Online (Sandbox Code Playgroud)
分配空间,与先前的语法完全一样,此处不涉及指针.
我们来介绍一个指针:
MyStruct * p1;
Run Code Online (Sandbox Code Playgroud)
这是一个指向MyStruct类型结构的简单指针.我可以通过通常的指针语法p1->a
或访问字段(*p1).a
.还有一个阵列风格的语法来执行与上面相同的操作p1[0].a
.仍然与上面相同.你只需要记住p1 [0]是一个简写(*(p1+0))
.
还要记住指针运算的规则:向指针添加1表示将sizeof
指向的对象添加到底层内存地址(使用%p printf format参数时得到的内容).指针算术允许访问连续的相同结构.这意味着,你可以通过索引访问与结构p1[0]
,p1[2]
等等.
不检查边界.记忆中指出的是程序员的责任.是的,我知道ISO的说法有所不同,但这就是我曾经尝试过的所有编译器所做的事情,所以如果你知道那些编译器没有,请告诉我.
要对p1做任何有用的事情,你必须指向一些类型的结构MyStruct
.如果你有像我们这样的结构数组a1
,你可以这样做p1=a1
,p1将指向数组的开头.换句话说,你也可以做到p1=&a1[0]
.有一个简单的语法是很自然的,因为它正是指针运算的设计目的:访问类似对象的数组.
该约定的优点在于它允许完全统一指针和数组访问语法.只有编译器才能看到差异:
当它看到时p1[0]
,它知道它必须获取名称所在的变量的内容p1
,并且它将包含某些内存结构的地址.
当它看到时a1[0]
,它知道a1
一些应该被理解为地址的常量(不是要在内存中获取的东西).
但是,一旦来自p1
或a1
可获得的地址处理相同.
一个常见的错误是写p1 = &a1
.如果你这样做,编译器会给你一些四个字母的单词.好的,&a1
也是一个指针,但是获取地址时得到的a1
是指向整个数组的指针.这意味着如果向此类型的指针添加1,则实际地址将一次以3个结构的步长移动.
这种指针的实际类型(让我们称之为p2
)将是MyStruct (*p2)[3];
.现在你可以写了p2 = &a1
.如果您要访问的第一个结构MyStruct
的内存块的开始指向p2
你将不得不写这样出头p2[0][0].a
或(*p2)[0].a
或(*(*p2)).a
或(*p2)->a
或p2[0]->a
.
由于类型系统和指针算法,所有这些都完全相同:获取p2中包含的地址,将该地址用作数组(已知的常量地址),如上所述.
现在你可以理解为什么指针和数组是完全不同的类型,不应该像有些人所说的那样混淆.简单来说,指针是包含地址的变量,数组是常量地址.请不要拍我的C++大师,是的,我知道这是不完整的故事和编译器保持许多其它信息与地址,尖(处理?)对象实例的大小一起.
现在你可能想知道为什么在参数传递上下文中你可以使用空方括号,它实际上意味着指针.?不知道.有人可能认为它看起来不错.
顺便说一下,至少使用gcc,你也可以在括号之间加一些值而不是保持空.它不会有所作为你仍然会得到一个指针,而不是一个数组,并没有完成边界或类型检查.我没有检查ISO标准是否应该完成,如果它是标准要求或者是否是特定行为.
如果要对边界进行类型检查,只需使用引用即可.这可能是令人惊讶的,但这是一个区域,如果您使用引用,参数的实际类型将从指针更改为数组(而不是从指针引用指向可能预期的指针).
MyStruct StructArray[10];
Run Code Online (Sandbox Code Playgroud)
void myFunction(struct MyStruct * PassedStruct)
myFunction(StructArray)
void myFunction(struct MyStruct PassedStruct[])
myFunction(StructArray)
void myFunction(struct MyStruct (& PassedStruct)[10])
myFunction(StructArray)
void myFunction(struct MyStruct (& PassedStruct)[11])
myFunction(StructArray)
void myFunction(struct MyStruct PassedStruct[10])
myFunction(StructArray)
void myFunction(struct MyStruct PassedStruct[11])
myFunction(StructArray)
虽然数组和指针在概念上是不同的东西,但水域却被功能参数弄得很混乱.您无法直接将数组传递给函数; 你只能传递一个指针.结果,语言"帮助"转换原型,如:
void foo (char arr[])
Run Code Online (Sandbox Code Playgroud)
进入这个:
void foo (char *arr)
Run Code Online (Sandbox Code Playgroud)
当你调用函数时,你没有传递一个完整的数组,你将指针传递给第一个元素.因此,在函数内部foo
,它将具有指向原始数组的指针,并且分配元素也arr
将改变调用者中的数组.
在函数参数之外的所有其他情况中,声明中的数组和指针语法不等效,并且在概念上引用不同的东西.但是在函数参数列表中,数组语法会创建指针类型.