Int массив, переданный через функцию, имеет неправильные значения только после нескольких проходов

У меня есть такой код:

for(int i = 0; i < its; i++) {
    x1 = random(0,4);
    y1 = random(0,4);
    multiLamp(new int[2] {3,1}, new int[2] {x1,x2}, new int[2] {y1,y2}, wait, 2);
    multiLamp(new int[2] {2,0}, new int[2] {x1,x2}, new int[2] {y1,y2}, wait, 2);
    x2 = random(0,4);
    y2 = random(0,4);
    multiLamp(new int[2] {1,3}, new int[2] {x1,x2}, new int[2] {y1,y2}, wait, 2);
    multiLamp(new int[2] {0,2}, new int[2] {x1,x2}, new int[2] {y1,y2}, wait, 2);
}

который вызывает функцию "multiLamp" и передает 3 int массива по 2 значения каждый. Вот эта функция:

void multiLamp(int epos[], int xpos[], int ypos[], int del, int len) {
  for(int it = 0; it < del; it++) {
    for(int i = 0; i < len; i++) {
      lamp(epos[i],xpos[i],ypos[i],2);
    }
  }
}

Предполагается, что эта функция вызывает некоторую функцию "лампа" с несколькими целыми числами из массивов. Вначале это работает нормально, но после более чем 50 вызовов функции "multiLamp" значения в массивах становятся {0,128,128} и {3,3,3} или чем-то подобным, хотя значения, переданные в нее из моего основного кода, одинаково действительны, как и раньше (они каким-то образом изменяются после передачи функции "multiLamp").

Кажется, я не могу найти здесь никакой проблемы. Любая помощь приветствуется!

ОБНОВЛЕНИЕ:

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

int e[] = {12,13,11,10};
int xy[] = {2,3,4,9,6,7,8,5,1,A0,A1,0,A3,A4,A5,A2};

void setup() {
  for(int a=0;a < 4;a++){
         pinMode(e[a], OUTPUT);
         digitalWrite(e[a], LOW);
  }
  for(int b=0;b < 16;b++){
         pinMode(xy[b], OUTPUT);
         digitalWrite(xy[b], HIGH);
  }
}

void loop() {
  bigCubes(100);
  rain(20, 30);
  miniCubes(15);
  every(80);
}

void lamp(int epos, int xpos, int ypos, int del) {
  int xypos = 4*xpos+ypos;
  digitalWrite(e[epos], HIGH);
  digitalWrite(xy[xypos], LOW);
  delay(del);
  digitalWrite(e[epos], LOW);
  digitalWrite(xy[xypos], HIGH);
}

void multiLamp(int epos[], int xpos[], int ypos[], int del, int len) {
  for(int it = 0; it < del; it++) {
    for(int i = 0; i < len; i++) {
      lamp(epos[i],xpos[i],ypos[i],1);
    }
  }
}

void every(int wait) {
  for(int i = 0; i < 4; i++) {
    for(int j = 0; j < 4; j++) {
      for(int k = 0; k < 4; k++) {
        lamp(i,j,k,wait);
      }
    }
  }
}

void miniCubes(int wait) {
  int cube[8][3] = {{0,0,0},{0,0,1},{0,1,1},{0,1,0},{1,1,0},{1,1,1},{1,0,1},{1,0,0}};
  for(int c = 0; c < 8; c++) {
    for(int it = 0; it < wait; it++) {
      for(int i = 0; i < 8; i++) {
        lamp(cube[i][0]+2*cube[c][0],cube[i][1]+2*cube[c][1],cube[i][2]+2*cube[c][2],2);
      }
    }
  }
}

void bigCubes(int wait) {
  multiLamp(new int[32] {0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3}, new int[32] {0,0,0,0,1,1,2,2,3,3,3,3,0,0,3,3,0,0,3,3,0,0,0,0,1,1,2,2,3,3,3,3}, new int[32] {0,1,2,3,0,3,0,3,0,1,2,3,0,3,0,3,0,3,0,3,0,1,2,3,0,3,0,3,0,1,2,3}, wait, 32);
}

void rain(int its, int wait) {
  int x2 = random(0,4);
  int y2 = random(0,4);
  int x1;
  int y1;
  for(int i = 0; i < its; i++) {
    x1 = random(0,4);
    y1 = random(0,4);
    multiLamp(new int[2] {3,1}, new int[2] {x1,x2}, new int[2] {y1,y2}, wait, 2);
    multiLamp(new int[2] {2,0}, new int[2] {x1,x2}, new int[2] {y1,y2}, wait, 2);
    x2 = random(0,4);
    y2 = random(0,4);
    multiLamp(new int[2] {1,3}, new int[2] {x1,x2}, new int[2] {y1,y2}, wait, 2);
    multiLamp(new int[2] {0,2}, new int[2] {x1,x2}, new int[2] {y1,y2}, wait, 2);
  }
}

, 👍1

Обсуждение

Мхх, я вижу, как вы создаете 3 новых массива при каждом вызове " multiLamp ()", но я никогда не видел, чтобы вы снова их освобождали. Помимо того факта, что динамическое распределение памяти плохо на плате AVR, такой как Uno, вам нужно снова освободить выделенную память, когда она вам больше не понадобится, или вы довольно быстро заполните оперативную память. Если памяти не осталось, поведение Arduino не определено (хотя в основном они просто сбрасываются). Это кажется лучшим кандидатом для решения проблемы. Не могли бы вы предоставить полный скомпилированный примерный скетч, который показывает вашу проблему? (не просто фрагмент), @chrisl

Та часть, которая на самом деле является проблемой, на самом деле является общей проблемой программирования., @timemage

@christl Я добавил полный код, хотя не знаю, пригодится ли он вам., @JaMoin

@christl Должен ли я освободить их вручную? Я думал, что массивы освободятся, если функция закончится?, @JaMoin


1 ответ


Лучший ответ:

0

Вы неправильно используете оператор new для своих массивов. Это позволит динамически распределять эти массивы. Они помещаются в кучу (а не в стек, как локальные переменные) и поэтому не освобождаются автоматически при выходе из функции. Это должно быть сделано вашим кодом с ключевым словом delete. Ваш код просто съедает всю доступную память. Это называется утечкой памяти.

То, что вам нужно освободить ваши динамически создаваемые переменные, - это не проблема Arduino; это правильно для всего кода C/C++. Но ограниченная память на ардуино на базе AVR, таких как Uno, делает его еще хуже.

Если вы сделаете математику, то одна итерация void loop() заблокирует 432 байта памяти (216 элементов массива, каждый из которых имеет тип int, таким образом, 2 байта). 2 КБ памяти (которая также необходима для локальных и глобальных переменных) съедаются довольно быстро.

Я не понимаю, зачем вам вообще понадобилось использовать динамически создаваемые массивы. Почему бы просто не использовать локально определенные массивы, как в функции miniCubes ()?


Тем не менее, это также в целом плохая идея использовать микроконтроллеры динамического выделения памяти, особенно с небольшой памятью. При создании и удалении объектов разного размера (что является основным преимуществом динамического выделения) вы оставляете в оперативной памяти небольшие отверстия, которые слишком малы для того, чтобы в них поместился один из ваших объектов. В какой-то момент ваша оперативная память полностью заполняется этими дырами, так что для сохранения ваших объектов больше не может быть выделено никакой памяти. Это называется фрагментацией памяти.

На вашем ПК это не проблема из-за 2 причин:

  • ПК имеет нагрузки ОЗУ доступные, и
  • ОС управляет оперативной памятью, дефрагментируя ее, если это необходимо.

Поскольку микроконтроллеры не имеют ОС, управляющей оперативной памятью, и часто очень ограниченной оперативной ПАМЯТЬЮ, вам нужно убедиться, что ваша оперативная память не слишком сильно фрагментируется во время выполнения вашего кода.

,

Большое спасибо! Я сделал это так, как вы мне сказали, и сделал это, как в функции miniCubes (). Это сработало великолепно., @JaMoin