Двухмерный массив?

Лёха
Offline
Зарегистрирован: 22.02.2016
Привет.

Суть: я скажем храню номера телефонов в EPPROM ардуины.

Скажем каджый байт - 1 знак из номера телефона (12 знаков - 1 номер).

Сколько всего номеров - не известно, но останавливаюсь читать EPPROM когда следущий байт = 255.

У меня проблема с выводом массива:

Код с ошибкой:

/* Читаем телефоны с EPPROM */
String[] getPhoneNumbers() {
  
   String numbers[];

    /* 
        Чтение телефонов начинается с 49го адресса
        Один телефон занимает + 38 44 34 44 44 44 == 12 байт
    */
    int numI = 0;
    
    for (int addr = 49; addr < 1024; addr++) { 
      
        int n = EEPROM[addr];

        // Конец списка телефонов
        if(n == 255) { 
            break;
        }
        
        if(sizeof(numbers[numI]) == 12) {
           numI++; 
        }

        numbers[numI] += n;
    }
      
    return numbers;
  
}
 
И в переделке на char* он тоже не заносит.
Суть массива такая:
 
numbers[0] = "381038274937";
numbers[1] = "911638374237";
 
т.е. обьявить изначально кол-во элементов я не могу, так как не знаю сколько их. Как-то можно решить эту задачу?
 

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Можно. Написав нормальный код. Вы на голом С++ это хотите сделать? Это не так тривиально, как может показаться на первый взгляд, тем более - вы не знаете заранее, сколько так номеров телефонов. Вкратце - надо курить malloc/realloc/free - такие старые добротные хорошие сишные функции (new/delete, собственно, внутри себя их и юзают). Не зная заранее кол-ва элементов в массиве - только с ними и работать.

Навскидку без ошибок не напишу (даже вернее всего - будут ошибки), но как-то так:

/* Читаем телефоны с EPPROM */
char** getPhoneNumbers(int& array_size) 
{
  
  byte buff[13] = {0};
  char** result = NULL;
  array_size = 0;

    /* 
        Чтение телефонов начинается с 49го адресса
        Один телефон занимает + 38 44 34 44 44 44 == 12 байт
    */
    int readed = 0;
    
    for (int addr = 49; addr < 1024; addr++,readed++) 
    { 
      
        byte n = EEPROM[addr];
        if(n == 255) break;

       if(readed < 12)
       buff[readed] = n;
      else
      {
            buff[readed] = 0;
            readed = 0;

          // в buff лежит номер телефона, надо скопировать его в массив
          if(!array_size)
          {
             result = new char*[array_size+1];
             result[array_size] = new char[sizeof(buff)];
             strcpy(result[array_size],buff);
             array_size++;
          }
          else
          {
           char **copy = new char* [array_size+1]; 
             for(int j = 0;j < array_size; j++) 
              {
                  copy[j] = result [j];
               }  
 
              delete [] result; 
             result = copy;            
             result[array_size] = new char[sizeof(buff)];
             strcpy(result[array_size],buff);
             array_size++;
          }
      }

       
    }
      
    return result;
  
}

Собственно, принцип понятен, надеюсь. Только не забывайте освобождать память после использования. А ещё лучше - перейти на другой уровень абстракции - классы. Чтобы не париться с памятью, как в приведённом примере, а отдать это на откуп конкретной реализации класса.

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Кстати, а чего Вы ждёте от выражения sizeof(numbers[numI]) в строке 21? Текущей длины строки numbers[numI]? Таки нет - Вы получите размер объетка String в памяти - это фиксированная величина. Если нужна длина, то см. методы класса String.

Лёха
Offline
Зарегистрирован: 22.02.2016

DIYMan пишет:

Можно. Написав нормальный код. Вы на голом С++ это хотите сделать? Это не так тривиально, как может показаться на первый взгляд, тем более - вы не знаете заранее, сколько так номеров телефонов. Вкратце - надо курить malloc/realloc/free - такие старые добротные хорошие сишные функции (new/delete, собственно, внутри себя их и юзают). Не зная заранее кол-ва элементов в массиве - только с ними и работать.

Навскидку без ошибок не напишу (даже вернее всего - будут ошибки), но как-то так:

/* Читаем телефоны с EPPROM */
char** getPhoneNumbers(int& array_size) 
{
  
  byte buff[13] = {0};
  char** result = NULL;
  array_size = 0;

    /* 
        Чтение телефонов начинается с 49го адресса
        Один телефон занимает + 38 44 34 44 44 44 == 12 байт
    */
    int readed = 0;
    
    for (int addr = 49; addr < 1024; addr++,readed++) 
    { 
      
        byte n = EEPROM[addr];
        if(n == 255) break;

       if(readed < 12)
       buff[readed] = n;
      else
      {
            buff[readed] = 0;
            readed = 0;

          // в buff лежит номер телефона, надо скопировать его в массив
          if(!array_size)
          {
             result = new char*[array_size+1];
             result[array_size] = new char[sizeof(buff)];
             strcpy(result[array_size],buff);
             array_size++;
          }
          else
          {
           char **copy = new char* [array_size+1]; 
             for(int j = 0;j < array_size; j++) 
              {
                  copy[j] = result [j];
               }  
 
              delete [] result; 
             result = copy;            
             result[array_size] = new char[sizeof(buff)];
             strcpy(result[array_size],buff);
             array_size++;
          }
      }

       
    }
      
    return result;
  
}

Собственно, принцип понятен, надеюсь. Только не забывайте освобождать память после использования. А ещё лучше - перейти на другой уровень абстракции - классы. Чтобы не париться с памятью, как в приведённом примере, а отдать это на откуп конкретной реализации класса.

 

Нет, делаю в Arduino Studio. 

Спасибо за пример, буду разбирать

Лёха
Offline
Зарегистрирован: 22.02.2016

Я не совсем понял как сделать двухмерный массив. А sizeof думал выдаст мне не общее кол-во массива, а кол-во ключей :)

Про String я знаю :)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Лёха пишет:

Я не совсем понял как сделать двухмерный массив. А sizeof думал выдаст мне не общее кол-во массива, а кол-во ключей :)

sizeof выдаёт размер объекта в памяти в момент компиляции и ничего больше

Лёха пишет:

Про String я знаю :)

Не знаете. Изучайте.

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

в условиях очень ограниченной "кучи" в МК не следует злоупотреблять malloc().

То есть не стоит часто отводить и высвобождать память не думая о последовательности дейстий.

В Вашем случае нужно один раз пробежать по EEPROM и узнать количество телефонов, а потом отвести под них память и вторым проходом туда прочитать. То есть отвести память один раз, потом, воспользовавшись телефонами, освободить память тоже один раз.

 

И еще вопрос: цифра номера это 4 бита, в байт одним макросом пакуется 2- цифры и столь же простым макросом - извлекаются.

Правда это имеет смысл только в том случае, если в проекте есть нехватка памяти, если на все хватает, то и не стоит огород городить.

Вот макросы для паковки и распаковки. М - массив unsigned char, i - индекс, a - цифра.

#define get_d(M,i) ((i&1)?((*(M+i/2)>>4)&0xf):(*(M+i/2)&0xf))
#define put_d(M,i,a) ((i&1)?(*(M+i/2)=*(M+i/2)&0xf|(a<<4)):(*(M+i/2)=*(M+i/2)&0xf0|a))

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

wdrakula пишет:

Вот макросы для паковки и распаковки. М - массив unsigned char, i - индекс, a - цифра.

#define get_d(M,i) ((i&1)?((*(M+i/2)>>4)&0xf):(*(M+i/2)&0xf))
#define put_d(M,i,a) ((i&1)?(*(M+i/2)=*(M+i/2)&0xf|(a<<4)):(*(M+i/2)=*(M+i/2)&0xf0|a))

Негодные макросы, небезопасные. Предлагаю подумать, как распакуется макрос, если я его вызову так:

put_d(arr,1+2,10+18);

;)

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

конечно нужно еще скобок поставить вокруг переменных, это же на коленке написано... ;) ну что Вы прямо!?