Как передать переменную массива структуры в другую функцию? - PullRequest
0 голосов
/ 21 сентября 2018

Я довольно новичок в использовании typedef struct, поэтому я надеюсь, что вы сможете дать довольно простое объяснение, чтобы я мог лучше понять.

Я объявил переменную массива с именем ExpNum[3] для моей структуры typedef.Я хочу иметь возможность передавать ExpNum[0].ValueofParamOne[0] и так далее и тому подобное в другую функцию с именем myfunction().Однако я не могу сделать

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

Когда я запускаю свои коды каккак показано ниже, значения, инициализированные здесь, даже не передаются.Я понял это, потому что я printf ExpNum[0].ValueofParamOne[0] в основной функции и myfunction() и значения разные.Значение в основной функции правильное, а в myfunction() напечатаны случайные длинные числа, ошибка.Я знаю, почему возникает ошибка.Мой вопрос, как я должен передать этот массив?Возможно ли это вообще?

Я знаю, что более простой способ - передать структуру без объявления ExpNum[3].Однако это очень важно, потому что моя настоящая программа имеет дело с большим количеством экспериментов, и мне нужно ExpNum[3], чтобы помочь пользователям убедиться, что они не смешивают ValueofParamOne, ValueofParamTwo, и это соответствует 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 голосов
/ 21 сентября 2018

В первой строке:

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 . . .
0 голосов
/ 21 сентября 2018

Совершенно очевидно, что вы немного озадачены тем, как объединить значения в единую структуру, чтобы использовать все значения сразу.

В вашем коде.Вы присваиваете значение stInputs.NumofParam - но другие значения не присваиваются.

Затем вы объявляете массив из 3 структур в ExpNum, но затем необъяснимым образом назначаете только одну строку значений в каждой структуре?

По сути вашего вопроса, похоже, что вы пытаетесь заполнить одну структуру всеми значениями, чтобы вы могли передать эту структуру в myfunction (что, как мы предполагаем, приводит к выводу всех значений вstruct)

Прежде чем смотреть на исправления, давайте рассмотрим некоторые общие проблемы кодирования.

Во-первых, не используйте магические числа в своем коде (кроме случаев, когда это абсолютно необходимо, напримерс модификатором scanf ширина поля ).Ваш 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избегает использования camelCase или MixedCase имен переменных в пользу всех строчных , сохраняя при этом прописных имен для использования с макросами и константами.Это вопрос стиля - так что это полностью ваше дело, но если вы не будете следовать ему, то в некоторых кругах вы можете получить неправильное первое впечатление.

Теперь перейдем к вашему коду.Во-первых (и особенно если вы будете циклически проходить по элементам в массиве) инициализирует ваши структуры со всеми нулями при объявлении.Это исключит возможность вызова неопределенного поведения при непреднамеренной попытке чтения из неинициализированного значения.Вы можете либо использовать именованный инициализатор для первого члена (все остальные будут установлены на ноль по умолчанию), либо вы можете использовать универсальный инициализатор (например, {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 }};

Теперь посмотрите на логику ваших заданий.Вы объявляете 3 элемента в массиве ExpNum.Каждая структура имеет 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

Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.Если я неверно истолковал ваш вопрос, просто оставьте комментарий или отредактируйте свой вопрос и дайте мне знать.

0 голосов
/ 21 сентября 2018

Если вы хотите передать массив 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];
    // ...
}
...