【问题标题】:How to pass an array variable of a struct to another function?如何将结构的数组变量传递给另一个函数?
【发布时间】:2019-02-25 08:19:40
【问题描述】:

我对使用 typedef struct 很陌生,所以我希望你能给出非常基本的解释,以便我能更好地理解。

我已经为我的 typedef 结构声明了一个名为 ExpNum[3] 的数组变量。我希望能够将ExpNum[0].ValueofParamOne[0] 等等传递给另一个名为myfunction() 的函数。但是,我做不到

pstInputs->ExpNum[0].ValueofParamOne[0]

当我运行如下所示的代码时,这里初始化的值甚至没有被传递。我想出来了,因为我在主函数中 printf ExpNum[0].ValueofParamOne[0]myfunction() 并且值不同。 main 函数中的一个是正确的,而myfunction() 中的一个打印随机长数字,一个错误。我知道为什么会出现错误。我的问题是我应该如何传递这个数组?一开始有可能吗?

我知道一个更简单的方法是传递结构而不声明ExpNum[3]。然而这很关键,因为我的实际程序处理更多的实验,我需要ExpNum[3] 来帮助用户确保他们不会混淆ValueofParamOneValueofParamTwo 和它对应的ExperimentResults

或者我应该完全改变我的方法?我的主要重点是确保用户准确地分配他们的值。

myfunction() 具有高度的技术性和数学性。其目的是计算优化的参数值。当然,在我的实际函数中,实验数据不止3个。

typedef struct
{
unsigned int     NumofParam;
double     ExperimentResults[3];
double     ValueofParamOne[3];
double     ValueofParamTwo[3];
}EXP_CONDITION;

int main()
{
EXP_CONDITION stInputs;
EXP_CONDITION* pstInputs;
pstInputs = &stInputs;

pstInputs->NumofParam = 2U;
EXP_CONDITION ExpNum[3];

/*assign values to Experiment 1*/
ExpNum[0].ValueofParamOne[0]=200;
ExpNum[0].ValueofParamTwo[0]=400;
ExpNum[0].ExperimentResults[0]=1000;

/*assign values to Experiment 2*/
ExpNum[1].ValueofParamOne[1]=210;
ExpNum[1].ValueofParamTwo[1]=440;
ExpNum[1].ExperimentResults[1]=2000;

/*assign values to Experiment 3*/
ExpNum[2].ValueofParamOne[2]=220;
ExpNum[2].ValueofParamTwo[2]=480;
ExpNum[2].ExperimentResults[2]=3000;

myfunction(&stInputs);
return 0;
}

根据来自@MaxVollmer 和@aschepler 的 cmets 进行编辑 :)

【问题讨论】:

  • 有趣的事实:C++ 不需要typedef structstruct EXP_CONDITION { ... }; 包含编译器使用EXP_CONDITION 标识符所需的所有信息。听起来好像有人在教你 C,而不是 C++。
  • 困惑。您似乎并没有试图在任何地方传递数组。您可能过于简化了示例。
  • “当我运行如下所示的代码时,这里初始化的值甚至没有被传递。” 那是因为你没有传递它们。 stInputsExpNum 不相关,您将 stInputs 传递给 ExpNum,而不是 ExpNum
  • 我们至少需要查看myfunction 的声明,最好是一个简单的定义,以猜测发生了什么。理想情况下,您将创建一个具有相似功能、预期和实际输出的minimal reproducible example,这正是您得出结论“值未通过”的原因,因此我们无需猜测。
  • C 和 C++ 是不同的语言。在 C++ 中不要 typedef struct。而不是typedef struct{} Gah;,写struct Gah{}

标签: c arrays function struct typedef


【解决方案1】:

很明显,您对如何将这些值放在一个结构中以同时使用所有值有点困惑。

在您的代码中。您为 stInputs.NumofParam 分配了一个值——但没有分配其他值。

然后您在ExpNum 中声明了一个 3-struct 数组,但随后莫名其妙地在每个 struct 中分配了一行值?

从您的问题的要点来看,您似乎正在尝试用所有值填充一个结构,因此您可以将该结构传递给myfunction(我们假设它会执行类似输出结构中的所有值的操作)

在查看修复之前,让我们先看看一些一般性的编码问题。

首先,不要在代码中使用幻数(除非绝对需要,例如使用scanf field-width 修饰符)。您的3 是一个幻数。相反,如果您需要一个常量 #define 一个(或多个),或者使用全局 enum 来做同样的事情。这样,您可以在代码顶部有一个位置来根据需要进行更改,并且您不必通过声明或循环限制来进行更改,例如

#include <stdio.h>

#define MAXV 3  /* if you need a constant, #define one (or more) */

typedef struct {
    unsigned int     NumofParam;
    double     ExperimentResults[MAXV];
    double     ValueofParamOne[MAXV];
    double     ValueofParamTwo[MAXV];
} EXP_CONDITION;

接下来,C 避免使用camelCaseMixedCase 变量名,而支持所有小写,同时保留大写 名以用于宏和常数。这是一个风格问题——所以这完全取决于你,但不遵循它可能会在某些圈子中导致错误的第一印象。

现在开始您的代码。首先(特别是如果您将循环遍历数组中的元素)在声明时将您的结构初始化为全零。这将消除通过无意中尝试读取未初始化值来调用 Undefined Behavior 的机会。您可以为第一个成员使用命名初始化器(默认情况下,所有其他成员都将设置为零),或者您可以使用通用初始化器(例如{0})完成同样的事情。示例:

int main (void)
{
    /* initialize your struct to all zero using a named initializer
     * or the universal intializer {0}
     */
    EXP_CONDITION stInputs = { .NumofParam = 0 };
    EXP_CONDITION* pstInputs;
    pstInputs = &stInputs;
    ...
    EXP_CONDITION ExpNum[MAXV] = {{ .NumofParam = 0 }};

现在看看你的作业逻辑。您在数组ExpNum 中声明了 3 个结构。每个结构都有 3 个数组,每个数组有 3 个值,例如

    double     ExperimentResults[MAXV];
    double     ValueofParamOne[MAXV];
    double     ValueofParamTwo[MAXV];

当您尝试填充 ExpNum[0] ExpNum[1]ExpNum[2] 中的每一个时,您只会填充一个元素,例如

    /*assign values to Experiment 1*/
    ExpNum[0].ValueofParamOne[0]=200;
    ExpNum[0].ValueofParamTwo[0]=400;
    ExpNum[0].ExperimentResults[0]=1000;

    /*assign values to Experiment 2*/
    ExpNum[1].ValueofParamOne[1]=210;
    ExpNum[1].ValueofParamTwo[1]=440;
    ExpNum[1].ExperimentResults[1]=2000;
    ...

要完全填充您需要的单个结构

    /*assign values to Experiment 1*/
    ExpNum[0].ValueofParamOne[0]=200;
    ExpNum[0].ValueofParamTwo[0]=400;
    ExpNum[0].ExperimentResults[0]=1000;

    ExpNum[0].ValueofParamOne[1]=210;
    ExpNum[0].ValueofParamTwo[1]=440;
    ExpNum[0].ExperimentResults[1]=2000;

    ExpNum[0].ValueofParamOne[2]=220;
    ExpNum[0].ValueofParamTwo[2]=480;
    ExpNum[0].ExperimentResults[2]=3000;

现在让我们看看myfunction,我们假设它只是输出存储在每个结构中的值(这只是示例):

void myfunction (EXP_CONDITION *exp)
{
    printf ("\nNumofParam: %u\n", exp->NumofParam);

    for (int i = 0; i < MAXV; i++)
        printf (" %7.1lf    %7.1lf    %7.1lf\n", exp->ExperimentResults[i],
                exp->ValueofParamOne[i], exp->ValueofParamTwo[i]);

    putchar ('\n');     /* tidy up with newline */
}

想想如果我们调用myfunction (pstInputs) 会打印什么?如果我们调用myfunction (&amp;ExpNum[0]) 会打印什么?或myfunction (&amp;ExpNum[1])

提示:

Initial stInputs struct

NumofParam: 2
     0.0        0.0        0.0
     0.0        0.0        0.0
     0.0        0.0        0.0

Content of each of ExpNum structs

NumofParam: 0
  1000.0      200.0      400.0
     0.0        0.0        0.0
     0.0        0.0        0.0


NumofParam: 0
     0.0        0.0        0.0
  2000.0      210.0      440.0
     0.0        0.0        0.0


NumofParam: 0
     0.0        0.0        0.0
     0.0        0.0        0.0
  3000.0      220.0      480.0

我可能是错的,但从逻辑上讲,您似乎打算在您的 stInputs 结构中进行所有实验,而不是在您的 ExpNum 数组中每个都撒上一行。编码和结构的美妙之处在于,您可以轻松地将数据混在一起,现在将其放在一个位置,以便您可以正确管理数据。简单循环 ExpNum 数组并将所有数据复制到 stInputs 结构的适当位置,例如

    /* now put all values in your stInputs struct like it appears
     * you intended to do?
     */
    for (int i = 0; i < MAXV; i++) {
        pstInputs->ExperimentResults[i] = ExpNum[i].ExperimentResults[i];
        pstInputs->ValueofParamOne[i] = ExpNum[i].ValueofParamOne[i];
        pstInputs->ValueofParamTwo[i] = ExpNum[i].ValueofParamTwo[i];
    }

现在,当您致电 myfunction (pstInputs) 时,您将获得所有数据,例如

Output of the completely filled stInputs struct

NumofParam: 2
  1000.0      200.0      400.0
  2000.0      210.0      440.0
  3000.0      220.0      480.0

将所有部分放在一起,您的最终示例可能如下所示:

#include <stdio.h>

#define MAXV 3  /* if you need a constant, #define one (or more) */

typedef struct {
    unsigned int     NumofParam;
    double     ExperimentResults[MAXV];
    double     ValueofParamOne[MAXV];
    double     ValueofParamTwo[MAXV];
} EXP_CONDITION;

void myfunction (EXP_CONDITION *exp)
{
    printf ("\nNumofParam: %u\n", exp->NumofParam);

    for (int i = 0; i < MAXV; i++)
        printf (" %7.1lf    %7.1lf    %7.1lf\n", exp->ExperimentResults[i],
                exp->ValueofParamOne[i], exp->ValueofParamTwo[i]);

    putchar ('\n');     /* tidy up with newline */
}

int main (void)
{
    /* initialize your struct to all zero using a named initializer
     * or the universal intializer {0}
     */
    EXP_CONDITION stInputs = { .NumofParam = 0 };
    EXP_CONDITION* pstInputs;
    pstInputs = &stInputs;

    pstInputs->NumofParam = 2U;
    EXP_CONDITION ExpNum[MAXV] = {{ .NumofParam = 0 }};

    /*assign values to Experiment 1*/
    ExpNum[0].ValueofParamOne[0]=200;
    ExpNum[0].ValueofParamTwo[0]=400;
    ExpNum[0].ExperimentResults[0]=1000;

    /*assign values to Experiment 2*/
    ExpNum[1].ValueofParamOne[1]=210;
    ExpNum[1].ValueofParamTwo[1]=440;
    ExpNum[1].ExperimentResults[1]=2000;

    /*assign values to Experiment 3*/
    ExpNum[2].ValueofParamOne[2]=220;
    ExpNum[2].ValueofParamTwo[2]=480;
    ExpNum[2].ExperimentResults[2]=3000;

    /* output your first stInputs struct */
    puts ("Initial stInputs struct");
    myfunction (&stInputs);

    /* output values in each of your ExpNum array of struct
     * (but note, you only assign one-row in each struct)
     */
    puts ("Content of each of ExpNum structs");
    for (int i = 0; i < MAXV; i++)
        myfunction (&ExpNum[i]);

    /* now put all values in your stInputs struct like it appears
     * you intended to do?
     */
    for (int i = 0; i < MAXV; i++) {
        pstInputs->ExperimentResults[i] = ExpNum[i].ExperimentResults[i];
        pstInputs->ValueofParamOne[i] = ExpNum[i].ValueofParamOne[i];
        pstInputs->ValueofParamTwo[i] = ExpNum[i].ValueofParamTwo[i];
    }

    /* output the completely filled stInputs struct */
    puts ("Output of the completely filled stInputs struct");
    myfunction (pstInputs);

    return 0;
}

使用/输出的完整示例

$ ./bin/expstruct
Initial stInputs struct

NumofParam: 2
     0.0        0.0        0.0
     0.0        0.0        0.0
     0.0        0.0        0.0

Content of each of ExpNum structs

NumofParam: 0
  1000.0      200.0      400.0
     0.0        0.0        0.0
     0.0        0.0        0.0


NumofParam: 0
     0.0        0.0        0.0
  2000.0      210.0      440.0
     0.0        0.0        0.0


NumofParam: 0
     0.0        0.0        0.0
     0.0        0.0        0.0
  3000.0      220.0      480.0

Output of the completely filled stInputs struct

NumofParam: 2
  1000.0      200.0      400.0
  2000.0      210.0      440.0
  3000.0      220.0      480.0

查看一下,如果您还有其他问题,请告诉我。如果我误解了您的问题,请发表评论或编辑您的问题并告诉我。

【讨论】:

    【解决方案2】:

    在你的第一行:

    EXP_CONDITION stInputs;
    

    您已经构建了EXP_CONDITION 结构的对象。它的所有成员都未初始化(即“随机”)。 然后创建指向该结构的指针并设置NumofParam 成员的值。所有其他成员保持未初始化:

    pstInputs = &stInputs;
    
    pstInputs->NumofParam = 2U;
    

    现在,我想这就是你被绊倒的地方。您创建了一个包含另外 3 个 EXP_CONDITION 结构的数组。他们坐在记忆中的其他地方。修改这些结构不会修改您在上面声明的原始 stInputs 对象。

    EXP_CONDITION ExpNum[3];

    您最终将指向原始stInputs 对象的指针传递给您的函数。它仍然未初始化。

    现在,当您分配结果时,您有 2 个级别的数组,不清楚原因。例如:

    /*assign values to Experiment 2*/
    ExpNum[1].ValueofParamOne[1]=210;
    ExpNum[1].ValueofParamTwo[1]=440;
    ExpNum[1].ExperimentResults[1]=2000;
    

    将值分配给第二个ExpNum(这看起来不错),但随后将其分配给结构内数组中的第二个索引(例如,ExpNum[1].ValueofParamTwo[0] 未初始化)。

    所以,我猜你想要什么:从一个可以容纳所有实验的顶级结构开始,然后创建一个单独的结构来保存每个实验的结果。

    typedef struct 
    {
        double     ExperimentResults;
        double     ValueofParamOne;
        double     ValueofParamTwo;
    } ExperimentData;
    
    typedef struct 
    {
        unsigned int     NumofParam;
        ExperimentData     experiments[3];
    } EXP_CONDITION;
    

    您可以像这样分配值:

    EXP_CONDITION stInputs;
    
    stInputs.NumofParam = 2U;
    
    stInputs.experiments[0].ValueofParamOne = 200;
    stInputs.experiments[0].ValueofParamTwo = 400;
    stInputs.experiments[0].ExperimentResults =  1000;
    
    stInputs.experiments[1].ValueofParamOne = 210;
    stInputs.experiments[1].ValueofParamTwo = 440;
    stInputs.experiments[1].ExperimentResults =  2000;
    
    // etc . . .
    

    【讨论】:

    • 您好,感谢您的回答。我可以肯定地说你明白我想用我的数据做什么。我试过这个方法。但是我在ExperimentData experiments[3] 遇到错误。它说:error C3646:'experiments':未知覆盖说明符error C2143:语法错误:在'['之前缺少','error C2143:语法错误:在';'之前缺少')' error C2238: ';' 前面的意外标记
    • 你好像有错字,你有一个开放的(括号吗?
    • 你是对的。感谢您详细解释我的 ValueofParamOne 的初始数组如何不合适。我按照你的方法。它给了我正在寻找的解决方案!从来没有想过添加另一个结构
    【解决方案3】:

    如果你想传递ExpNum 数组,只需传递它。真的没什么:

    myfunction(ExpNum);
    

    编译器实际上会传递一个指向数组中第一个元素的指针,但这并不重要。你知道它是 3 个元素(如果没有,你可以简单地在函数中添加第二个参数来提供元素的数量)。

    myfunction 中,您可以像这样访问数组中的元素:

    void myfunction(EXP_CONDITION* expNum)
    {
        double foo = expNum[0].ValueofParamOne[0];
        double bar = expNum[1].ValueofParamOne[0];
        double baz = expNum[2].ValueofParamOne[0];
        // ...
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-02
      • 2015-02-12
      • 1970-01-01
      • 1970-01-01
      • 2023-02-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多