значения структуры изменяются при повторном обращении

#c

#c

Вопрос:

Я пытаюсь написать программу коллоидного моделирования на C, и я столкнулся с любопытной проблемой, которую я не знаю, как решить — я сократил код до минимума, где он показывает ошибку того же типа. (Заранее прошу прощения за длину кода …)

 /** main.c **/
#include <stdio.h>

/** typedefs **/
typedef struct { double x, y, z; } point;
typedef struct {
    double radius;
    point pos, potential, velocity;
} particle;
typedef struct {
    int num;                // size of particle array
    particle *particles;
} trough;
typedef struct { trough trough; } experiment;

void printPoint(point a) { printf("%f, %f, %fn", a.x, a.y, a.z); }

/** initializations **/
point initPoint(double x, double y, double z) {
    point new_point = { .x = x, .y = y, .z = z };
    return(new_point);
}
particle initParticle(double radius, point pos, point potential, point velocity) {
    particle new_particle = { .radius = radius, .pos = pos, .potential = potential, .velocity = velocity };
    return(new_particle);
}
trough initTrough(particle particles[]) {
    int num = sizeof(particles) / sizeof(int)   1;
    trough new_trough = { .num = num, .particles = particles };
    return(new_trough);
}
experiment initExperiment(trough in_trough) {
    experiment new_experiment = { .trough = in_trough };
    return(new_experiment);
}

/** probs **/
experiment newExperiment() {
    particle new_part1 = initParticle(1, initPoint(0, 4, 0), initPoint(0, 0, 0), initPoint(0, 0, 0));
    particle new_part2 = initParticle(1, initPoint(4, 4, 0), initPoint(0, 0, 0), initPoint(0, 0, 0));

    printPoint(new_part1.pos);
    printPoint(new_part2.pos);

    particle particles[2] = { new_part1, new_part2 };
    trough new_trough = initTrough(particles);

    printPoint(new_trough.particles[0].pos);
    printPoint(new_trough.particles[1].pos);

    return(initExperiment(new_trough));
}
int main(int argc, char *argv[]) {
    experiment experiment = newExperiment();

    printPoint(experiment.trough.particles[0].pos);
    printPoint(experiment.trough.particles[1].pos);

    return(0);
}
 

Я компилирую код: gcc -lm -std=c99 -Wall main.c и запускаю его: ./a.out и получаю следующий вывод:

 $ ./a.out
0.000000, 4.000000, 0.000000
4.000000, 4.000000, 0.000000
0.000000, 4.000000, 0.000000
4.000000, 4.000000, 0.000000
0.000000, 4.000000, 0.000000
0.000000, 4.000000, 0.000000
 

Проблема заключается в последней строке вывода, где я пытался найти значения x, y, z точки в массиве частиц — все, что я сделал в коде, это напечатал значения в разных точках, и поэтому значения не должны меняться, но они есть, иЯ совершенно не понимаю, почему это так. Связано ли это со ссылкой на массив по индексу? Любая помощь будет принята с благодарностью.

Комментарии:

1. Кроме того, sizeof(particles) не делает того, что вы думаете, потому что параметры функции никогда не имеют типа массива. Несмотря на то, что вы написали trough initTrough(particle particles[]) , тип particles is particle* . Объявление, вероятно, должно быть trough initTrough(int num, const particle* particles) .

Ответ №1:

Вы забыли выделить частицы в своей корыто-структуре. Есть несколько способов сделать это. В вашем примере исправление заключается в том, чтобы сделать particles массивом из двух элементов:

 typedef struct {
    int num;                // size of particle array
    particle particles[2];
};
 

вместо particals-pointer (который указывает «нигде» в вашем примере).

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

Ответ №2:

Тип trough не содержит массива particle s. Он содержит указатель, который может указывать на массив particle s. Вы инициализировали его, чтобы указать на локальный массив функции, объявленный в newExperiment() .

Но когда функция newExperiment завершается, время жизни массива заканчивается, и попытка снова использовать этот висячий указатель main вызывает неопределенное поведение.

Если количество частиц известно как максимальное во время компиляции, вы можете изменить элемент указателя на элемент массива, как показал @Patrick B. Если нет, вам нужно будет использовать malloc и free , чтобы убедиться, что элемент указателя указывает на память, которая будет оставаться действительной до тех пор, пока вам это нужно.