gpt4 book ai didi

c++ - 将结构数组传递给函数C++

转载 作者:行者123 更新时间:2023-12-02 22:24:18 26 4
gpt4 key购买 nike

很抱歉这个菜鸟问题,我只是有些困惑。
如果我要传递给函数的主要结构是数组:

struct MyStruct{
int a;
int b;
char c;
mayarray[5];
};
MyStruct StructArray[10];

myFunction(StructArray[])

传递给函数:
void myFunction(struct MyStruct PassedStruct[])
{
PassedStruct[0].a = 1;
PassedStruct[0].b = 2;
// ... etc
}

我的问题是,这样调用函数会修改 StructArray中的数据吗?我需要可以引用引用吗?我有点困惑。我将如何更改它,以便在将结构数组传递给函数时,该函数将修改数组 StructArray?我在视觉工作室。
谢谢。

最佳答案

struct MyStruct PassedStruct[]

通常是以下内容的替代语法:
struct MyStruct * PassedStruct

是的,您将访问和修改原始结构。

只需更改一个细节,就不能正确调用该函数
myFunction(StructArray[]);

但:
myFunction(StructArray);

现在,我将尝试解释为什么我在以上句子中使用了 主要是这个词:

我将给出一些关于数组和指针之间区别的提示,为什么不应该混淆它们(即使我不会说它们无关,相反),以及上述 MyStruct PassedStruct[]参数传递语法的问题。

这不是针对初学者的,C++标准专家也应该避免阅读此内容(因为我不想进入ISO未定义行为区域(也称为禁区),因此不愿参加ISO Standard_ war。

让我们从数组开始:

想象一个简单的结构:
struct MyStruct{
int a;
int b;
char c;
};
MyStruct a1[3];是一个数组的声明,其项属于上述结构类型。定义数组时,编译器最重要的事情就是为其分配空间。在我们的示例中,它为3个结构保留了空间。此保留空间可以在堆栈上,也可以来自全局内存资源,具体取决于声明语句的位置。

您也可以在声明结构时对其进行初始化,如下所示:
struct MyStruct a1[3] = {{1, 2}, {3, 4}, {5, 6}};

请注意,在此示例中,我没有初始化 c字段,而是初始化了 ab。这是允许的。如果我的编译器支持以下指示符,则也可以使用指示符语法:
struct MyStruct a1[3] = {{a:1, b:2}, {a:3, b:4}, {a:5, b:6}};

现在,还有另一种语法可以使用空的方形backets定义数组,例如:
struct MyStruct a2[] = {{1, 2}, {3, 4}, {5, 6}};

这里的重点是 a2就像 a1一样,是一个完全正常的数组。数组的大小不是隐式的,它是通过初始化程序指定的:我有三个初始化程序,因此我得到了三个结构的数组。

我可以使用这种语法定义一个未初始化的已知大小的数组。
对于大小为3的未初始化数组,我将有:
struct MyStruct a2[] = {{},{},{}};

完全按照以前的语法分配空间,此处不涉及任何指针。

让我们介绍一个指针:
MyStruct * p1;

这是指向MyStruct类型的结构的简单指针。我可以通过通常的指针语法 p1->a(*p1).a访问字段。还有一种数组修饰的语法可以执行与上述 p1[0].a相同的操作。仍然与上面相同。您只需要记住p1 [0]是 (*(p1+0))的简写。

还要记住指针算法的规则:在指针上加1意味着将指向对象的 sizeof添加到基础内存地址(使用%p printf格式参数时得到的结果)。指针算术允许访问连续的相同结构。这意味着您可以使用 p1[0]p1[2]等按索引访问结构。

不检查边界。内存中指出的是程序员的责任。是的,我知道ISO的说法有所不同,但这就是我尝试过的所有编译器所做的事情,因此,如果您知道没有,请告诉我。

要对p1做任何有用的事情,您必须使其指向某种类型 MyStruct的结构。如果您有像 a1这样的可用结构数组,则可以执行 p1=a1,而p1将指向数组的开头。换句话说,您也可以完成 p1=&a1[0]。可以使用简单的语法是很自然的,因为这正是指针算法的设计目的:访问相似对象的数组。

该约定的优点在于它允许完全统一指针和数组访问语法。区别仅由编译器看到:
  • 看到p1[0]时,便知道必须获取名称为p1的变量的内容,并且该变量将包含某个内存结构的地址。
  • 看到a1[0]时,便知道a1是一些应理解为地址的常量(不是要在内存中获取的常量)。

  • 但是一旦 p1a1中的地址可用,处理方法便是相同的。

    一个常见的错误是编写 p1 = &a1。如果这样做,编译器会给您一些四个字母的单词。好的, &a1也是一个指针,但是获取 a1的地址时得到的是指向整个数组的指针。这意味着,如果将1加到这种类型的指针上,则实际地址将一次移动3个结构。

    此类指针的实际类型(我们称其为 p2)将为 MyStruct (*p2)[3];。现在您可以编写 p2 = &a1了。如果要访问 MyStruct指向的存储块开头的第一个struct p2,则必须编写类似 p2[0][0].a(*p2)[0].a(*(*p2)).a(*p2)->ap2[0]->a的内容。

    多亏类型系统和指针算法,所有这些都做的完全一样:提取p2中包含的地址,如上所述,将该地址用作数组(已知的常量地址)。

    现在您可以理解为什么指针和数组是完全不同的类型,不应像某些人所说的那样混淆。简而言之,指针是包含地址的变量,数组是常量地址。请不要向我开枪C++ Gurus,是的,我知道这不是全部,并且编译器会保留许多其他信息以及地址,尖(寻址的)对象的大小。

    现在您可能想知道为什么在参数传递上下文中可以使用空方括号,而这实际上意味着指针。 ?不知道。可能有人认为它看起来不错。

    顺便说一句,至少对于gcc,您还可以在方括号之间放置一些值,而不是将其保留为空。仍然会有一个指针,而不是数组,并且边界或类型检查都没有完成,这不会有什么不同。我没有检查是否应该执行ISO标准,以及该标准是否要求它执行或是否属于特定行为。

    如果要对边界进行类型检查,只需使用引用即可。这可能令人惊讶,但是如果您使用引用,则在该区域中,参数的实际类型会从指针更改为数组(而不是预期的从指针更改为指针的引用)。
    MyStruct StructArray[10]; 
  • header :void myFunction(struct MyStruct * PassedStruct)
  • call 者:myFunction(StructArray)
  • 状态:可用,您可以在PassedStruct
  • 中使用指针


  • header :void myFunction(struct MyStruct PassedStruct[])
  • call 者:myFunction(StructArray)
  • 状态:可用,您可以在PassedStruct
  • 中使用指针


  • header :void myFunction(struct MyStruct (& PassedStruct)[10])
  • call 者:myFunction(StructArray)
  • 状态:有效,您可以使用对大小为10的数组的引用


  • header :void myFunction(struct MyStruct (& PassedStruct)[11])
  • call 者:myFunction(StructArray)
  • 状态:无法编译,原型(prototype)和实际参数
  • 之间的数组类型不匹配


  • header :void myFunction(struct MyStruct PassedStruct[10])
  • call 者:myFunction(StructArray)
  • 状态:有效,PassedStruct是一个指针,提供的大小被忽略


  • header :void myFunction(struct MyStruct PassedStruct[11])
  • call 者:myFunction(StructArray)
  • 状态:正常运行,PassedStruct是一个指针,提供的大小被忽略
  • 关于c++ - 将结构数组传递给函数C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3613302/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com