如何将结构的数组变量传递给另一个函数?

How to pass an array variable of a struct to another function?

我对使用 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 的评论编辑:)

如果要传递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];
    // ...
}

在你的第一行:

EXP_CONDITION stInputs;

您已经构建了 EXP_CONDITION 结构的对象。它的所有成员都未初始化(即 "random")。 然后创建指向该结构的指针并设置 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 . . .

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

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

然后您在 ExpNum 中声明了一个 3-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 变量名,转而使用所有 lower-case,同时保留 upper -case 与宏和常量一起使用的名称。这是一个风格问题——因此完全取决于您,但不遵循它可能会导致在某些圈子中产生错误的第一印象。

现在开始你的代码。首先(特别是如果你将遍历数组中的元素)在声明时将你的结构初始化为全零。这将消除通过无意中尝试读取未初始化的值来调用 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 (&ExpNum[0]) 会打印什么?或者 myfunction (&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;
}

完整示例Use/Output

$ ./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

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