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

时间:2018-09-21 00:22:56

标签: c arrays function struct typedef

我对使用typedef结构很陌生,所以希望您能给出一些基本的解释,以便我更好地理解。

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

  
    

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

  

当我如下所示运行代码时,此处初始化的值甚至都不会传递。我想出这是因为我在主函数中printf ExpNum[0].ValueofParamOne[0]myfunction()的值是不同的。主函数中的一个正确,而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的评论进行编辑:)

3 个答案:

答案 0 :(得分:3)

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

在您的代码中。您为stInputs.NumofParam分配了一个值-但未分配其他任何值。

然后您在ExpNum中声明一个由3个结构组成的数组,但是然后在每个结构中莫名其妙地只分配了一行值?

从问题的要点来看,您似乎正在尝试用所有值填充一个结构,以便可以将该结构传递给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变量名来支持所有小写用于宏和常量。这是一个风格问题-完全取决于您,但是如果不遵循它,可能会在某些圈子中导致错误的第一印象。

现在进入您的代码。首先(尤其是如果您要遍历数组中的元素)在声明时将结构初始化为全零。这样会由于无意间尝试从未初始化的值中进行读取而消除了调用未定义行为的机会。您可以为第一个成员使用命名初始化器(默认情况下,所有其他成员都将设置为零),也可以使用通用初始化器(例如{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;
}

使用/输出示例

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

仔细检查一下,如果还有其他问题,请告诉我。如果我对您的问题有误解,请发表评论或编辑您的问题,然后告诉我。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

第一行:

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(看起来不错),但是随后将其分配给struct内部数组中的第二个索引(例如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 . . .