Читаю файл с SD карты и записываю строки в массив. Но после записи, в массиве выводятся кракозябры. В C++ новичок, так что не судите строго. Файл config.txt Код (Text): 1000;1-100,2-200 2000;3-300,4-400,5-500 3000;90-500,0-20 Код (C++): #include <EncButton.h> EncButton<EB_TICK, 2> btn(INPUT_PULLUP); // кнопка управления пин 2 #include <SPI.h> #include <SD.h> const int sdPin = 4; // пин кардридера char *data[] = {}; // массив данных int data_count = 0; void setup() { Serial.begin(9600); } void loop() { btn.tick(); // опрашиваем кнопку if (btn.isClick()) { // нажали на кнопку // читаем данные с флэшки if (SD.begin(sdPin)) { File fileConfig; fileConfig = SD.open("config.txt"); // читаем файл настроек if (fileConfig) { int h = 0; while (fileConfig.available()) { String line = fileConfig.readStringUntil('\n'); char buf[line.length() + 1]; line.toCharArray(buf, line.length()); Serial.print("buf: "); Serial.println(buf); // данные выводятся правильно data[h] = buf; h++; } fileConfig.close(); } } Serial.println(data[0]); // кракозябры Serial.println(data[1]); // кракозябры Serial.println(data[2]); // кракозябры data_count = sizeof(data) / sizeof(data[0]); Serial.println(data_count); } } Итог: Код (Text): buf: 1000;1-100,2-200 buf: 2000;3-300,4-400,5-500 buf: 3000;90-500,0-20 ⸮⸮o⸮⸮⸮]⸮ݟ⸮⸮⸮f/J PUO 0
Это не массив для хранения строк. Это массив указателей. И так нельзя, СОВСЕМ НЕЛЬЗЯ ТАК: Нужно резервировать место под данные в массиве, копировать данные, а не указатель.
Так тут нужно все переписывать! Вам нужно почитать про массивы, указатели и строки на Си, чтобы хоть чуть-чуть понимать, о чем речь. Во-первых нужно определиться какой максимальной длины могут быть строки в файле. Во-вторых, нужно определиться с максимальным количеством строк в файле. Создать константы через #define. Прикинуть сколько это потребует памяти, влезет ли в ОЗУ. Создать двумерный массив, если не хотите заморачиваться динамическими массивами. Так: Код (C++): const char *names[] = { "Period", // 0 "Work", // 1 "Stop", // 2 }; можно делать только с инициализацией (объявлением строк), в массиве будут храниться указатели на эти строки в памяти. Без инициализации так делать нельзя (память под строки выделена не будет).
Самое простое, заменить это: Код (C++): char *data[] = {}; на это: Код (C++): String data[10]; А вообще, в стандартном GCC работает даже такая конструкция. Это Arduino IDE отличается от стандарта.
Вот этот код работает в gcc без артефактов. При этом не заданы явные размеры массива. Код (C++): #include <iostream> using namespace std; int main() { char *data[] = {}; data[0] = "abcde"; data[1] = "fghij"; cout << data[0] << endl; cout << data[1] << endl; return 0; }
Если задавать инициализацию указателей в массиве в явном виде, через индекс в виде константы, думаю компилятор сможет зарезервировать память за вас. Но если не проинициализировать массив указателей, и не указать его размерность, а в коде присвоить элементу массива с переменной в качестве индекса, адрес строки, как у ТС, то результат будет непредсказуемым. Вот пример, который работает корректно: Код (C++): void setup() { const char *data[]={"",""}; volatile int i; char buff[40]; Serial.begin(115200); // For debugging output Serial.println(""); Serial.println("--- Setup Start -----"); i=atoi("0"); data[i]="12345"; sprintf(buff,"1 data[%d] = %s\n",i,data[i]); Serial.print(buff); i=atoi("1"); data[i]="67890"; sprintf(buff,"1 data[%d] = %s\n",i,data[i]); Serial.print(buff); while(1); } void loop() { // put your main code here, to run repeatedly: } И этот пример тоже будет корректно отрабатывать: Код (C++): void setup() { const char *data[2]; volatile int i; char buff[40]; Serial.begin(115200); // For debugging output Serial.println(""); Serial.println("--- Setup Start -----"); i=atoi("0"); data[i]="12345"; sprintf(buff,"1 data[%d] = %s\n",i,data[i]); Serial.print(buff); i=atoi("1"); data[i]="67890"; sprintf(buff,"1 data[%d] = %s\n",i,data[i]); Serial.print(buff); while(1); } void loop() { // put your main code here, to run repeatedly: } Вывод будет одинаковым: Код (Text): --- Setup Start ----- 1 data[0] = 12345 1 data[1] = 67890 А это вариант, который мы обсуждали, как у ТС: Код (C++): void setup() { const char *data[] = {}; volatile int i; char buff[40]; Serial.begin(115200); // For debugging output Serial.println(""); Serial.println("--- Setup Start -----"); i=atoi("0"); data[i]="12345"; sprintf(buff,"1 data[%d] = %s\n",i,data[i]); Serial.print(buff); i=atoi("1"); data[i]="67890"; sprintf(buff,"1 data[%d] = %s\n",i,data[i]); Serial.print(buff); while(1); } void loop() { // put your main code here, to run repeatedly: } И вывод будет уже таким: Есть разница?
Проверил в gcc. Если делать "volatile int i", то программа вылетает из-за ошибки. А если делать "int i", то работает.
Так то, что вылетает - как раз и говорит, об ошибке в коде. Причем самой неприятной ошибке! Самые неприятные ошибки - испорченная память данных, стека, кучи (запись по неправильно инициированному указателю, или выходы за пределы размеров переменных). При этом поведение - то работает, то подвисает, то перезагружается. И хрен найдешь пытаясь отладить! Поэтому и нужно сразу правильно писать, а не надеяться, что умный компилятор сам догадается и все таки зарезервирует место для переменной.
User248 - этот код корректен с точки зрения синтаксиса, поэтому компилируется. Но по сути это тоже самое, как обьявить массив длиной пять элементов, а потом записать значение за границей массива: Код (C++): int array[5]; ..... ..... array[5] = 37; К чему приводит подобный код, я думаю вы догадываетесь. Ваш пример работает только потому, что локальные переменные data[0] = "abcde"; data[1] = "fghij"; не залезли ни в какую критичную область памяти Однако нет никакой гарантии. что при следующей перекомпиляции программа не развалится
Когда экспериментировал с этим вариантом: Код (C++): int main() { char *data[] = {}; data[0] = "abcde"; data[1] = "fghij"; //............................................ } показалось, что не смотря на отсутствие инициализации и явного указания размера массива указателей, компилятор, обнаружив явное указание элемента массива с индексом в виде константы, все таки резервирует место под этот указатель. Тогда мне не удалось добиться порчи данных этого массива указателей. Но, как выяснилось позже, резервирования не происходит, и при стечении обстоятельств, данные все равно могут быть испорчены. Объявляем массивы как выше: Код (C++): const char *data0[] = {"",""}; const char *data1[] = {}; const char *data2[2]; Инициализируем элементы массивов указателями на строки: Код (C++): data0[0]="0_12345"; data0[1]="0_67890"; data1[0]="1_12345"; data1[1]="1_67890"; data2[0]="2_12345"; data2[1]="2_67890"; Выводим информацию в монитор порта: Код (C++): Serial.print("dataX[0] ="); Serial.println(dataX[0]); Serial.print("dataX[1] ="); Serial.println(dataX[1]); Serial.print("sizof(dataX) = "); Serial.println(sizeof(dataX)); Получаем следующий результат: Массив нулевой длины, указатель указывает не туда - данные испорчены.
Спойлер: Пример демонстрирующий это: Код (C++): #pragma pack(1) char buff1[50]; const char *data0[] = {"",""}; const char *data1[] = {}; const char *data2[2]; char buff[50]; uint8_t i,j; uint8_t *ptr; uint8_t *ptr1; #pragma pack() void setup() { data0[0]="0_12345"; data0[1]="0_67890"; data1[0]="1_12345"; data1[1]="1_67890"; data2[0]="2_12345"; data2[1]="2_67890"; for (i=0;i<50;i++) { buff[i]='Q'; buff1[i]='Z'; } Serial.begin(115200); // For debugging output Serial.println("--- Setup Start -----"); // -------------------------------------------------------------- Serial.print("data0[0] ="); Serial.println(data0[0]); Serial.print("data0[1] ="); Serial.println(data0[1]); Serial.print("sizof(data0) = "); Serial.println(sizeof(data0)); sprintf(buff,"%p: %p,%p\n",&data0, data0[0],data0[1]); Serial.println(buff); Serial.println(""); // -------------------------------------------------------------- Serial.print("data1[0] ="); Serial.println(data1[0]); Serial.print("data1[1] ="); Serial.println(data1[1]); Serial.print("sizof(data1) = "); Serial.println(sizeof(data1)); sprintf(buff1,"%p: %p,%p\n",&data1, data1[0],data1[1]); Serial.println(buff1); Serial.println(""); // -------------------------------------------------------------- Serial.print("data2[0] ="); Serial.println(data2[0]); Serial.print("data2[1] ="); Serial.println(data2[1]); Serial.print("sizof(data2) = "); Serial.println(sizeof(data2)); sprintf(buff,"%p: %p,%p\n",&data2, data2[0],data2[1]); Serial.println(buff); // -------------------------------------------------------------- Serial.print(" "); for(i=0;i<16;i++) { if(i==8) Serial.print(" "); sprintf(buff,"0x%02x ", i ); Serial.print(buff); } Serial.print(" "); for(i=0;i<16;i++) { if(i==8) Serial.print(" "); sprintf(buff,"0x%02x ", i ); Serial.print(buff); } Serial.println(""); if (data0<data1) ptr = (uint8_t *)data0; else ptr = (uint8_t *)data1; if ((uint8_t *)data2 < ptr) ptr = (uint8_t *)data2; ptr = (uint8_t *) ((unsigned)ptr & 0xFF00); ptr1=ptr; for(j=0;j<32;j++) { sprintf(buff,"0x%04x: ",(unsigned)ptr); Serial.print(buff); for(i=0;i<16;i++) { if(i==8) Serial.print(" "); sprintf(buff,"0x%02x ", *(ptr++) ); Serial.print(buff); } Serial.print(" "); for(i=0;i<16;i++) { if(i==8) Serial.print(" "); if (*(ptr1)>=0x20 && *(ptr1) <= 0x7E) sprintf(buff," %c ",*(ptr1)); else sprintf(buff,"0x%02x ", *(ptr1)); Serial.print(buff); ptr1++; } Serial.println(""); } // -------------------------------------------------------------- Serial.println("--- Setup End -----"); while(1); } void loop() { // put your main code here, to run repeatedly: } Спойлер: Вывод: Код (Text): --- Setup Start ----- data0[0] =0_12345 data0[1] =0_67890 sizof(data0) = 4 0x200: 0x219,0x221 data1[0] =345 data1[1] =1_67890 sizof(data1) = 0 0x382: 0x230,0x231 data2[0] =2_12345 data2[1] =2_67890 sizof(data2) = 4 0x37e: 0x239,0x241 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f 0x0200: 0x19 0x02 0x21 0x02 0x00 0x00 0x00 0x00 0x39 0x01 0xa3 0x00 0xd1 0x00 0x85 0x01 0x19 0x02 ! 0x02 0x00 0x00 0x00 0x00 9 0x01 0xa3 0x00 0xd1 0x00 0x85 0x01 0x0210: 0x02 0x01 0xe0 0x00 0xf4 0x00 0x0d 0x0a 0x00 0x30 0x5f 0x31 0x32 0x33 0x34 0x35 0x02 0x01 0xe0 0x00 0xf4 0x00 0x0d 0x0a 0x00 0 _ 1 2 3 4 5 0x0220: 0x00 0x30 0x5f 0x36 0x37 0x38 0x39 0x30 0x00 0x31 0x5f 0x31 0x32 0x33 0x34 0x35 0x00 0 _ 6 7 8 9 0 0x00 1 _ 1 2 3 4 5 0x0230: 0x00 0x31 0x5f 0x36 0x37 0x38 0x39 0x30 0x00 0x32 0x5f 0x31 0x32 0x33 0x34 0x35 0x00 1 _ 6 7 8 9 0 0x00 2 _ 1 2 3 4 5 0x0240: 0x00 0x32 0x5f 0x36 0x37 0x38 0x39 0x30 0x00 0x2d 0x2d 0x2d 0x20 0x53 0x65 0x74 0x00 2 _ 6 7 8 9 0 0x00 - - - S e t 0x0250: 0x75 0x70 0x20 0x53 0x74 0x61 0x72 0x74 0x20 0x2d 0x2d 0x2d 0x2d 0x2d 0x00 0x64 u p S t a r t - - - - - 0x00 d 0x0260: 0x61 0x74 0x61 0x30 0x5b 0x30 0x5d 0x20 0x3d 0x00 0x64 0x61 0x74 0x61 0x30 0x5b a t a 0 [ 0 ] = 0x00 d a t a 0 [ 0x0270: 0x31 0x5d 0x20 0x3d 0x00 0x73 0x69 0x7a 0x6f 0x66 0x28 0x64 0x61 0x74 0x61 0x30 1 ] = 0x00 s i z o f ( d a t a 0 0x0280: 0x29 0x20 0x3d 0x20 0x00 0x25 0x70 0x3a 0x20 0x25 0x70 0x2c 0x25 0x70 0x0a 0x00 ) = 0x00 % p : % p , % p 0x0a 0x00 0x0290: 0x64 0x61 0x74 0x61 0x31 0x5b 0x30 0x5d 0x20 0x3d 0x00 0x64 0x61 0x74 0x61 0x31 d a t a 1 [ 0 ] = 0x00 d a t a 1 0x02a0: 0x5b 0x31 0x5d 0x20 0x3d 0x00 0x73 0x69 0x7a 0x6f 0x66 0x28 0x64 0x61 0x74 0x61 [ 1 ] = 0x00 s i z o f ( d a t a 0x02b0: 0x31 0x29 0x20 0x3d 0x20 0x00 0x64 0x61 0x74 0x61 0x32 0x5b 0x30 0x5d 0x20 0x3d 1 ) = 0x00 d a t a 2 [ 0 ] = 0x02c0: 0x00 0x64 0x61 0x74 0x61 0x32 0x5b 0x31 0x5d 0x20 0x3d 0x00 0x73 0x69 0x7a 0x6f 0x00 d a t a 2 [ 1 ] = 0x00 s i z o 0x02d0: 0x66 0x28 0x64 0x61 0x74 0x61 0x32 0x29 0x20 0x3d 0x20 0x00 0x20 0x20 0x20 0x20 f ( d a t a 2 ) = 0x00 0x02e0: 0x20 0x20 0x20 0x20 0x20 0x00 0x30 0x78 0x25 0x30 0x32 0x78 0x20 0x00 0x30 0x78 0x00 0 x % 0 2 x 0x00 0 x 0x02f0: 0x25 0x30 0x34 0x78 0x3a 0x20 0x20 0x00 0x20 0x20 0x25 0x63 0x20 0x20 0x00 0x2d % 0 4 x : 0x00 % c 0x00 - 0x0300: 0x2d 0x2d 0x20 0x53 0x65 0x74 0x75 0x70 0x20 0x45 0x6e 0x64 0x20 0x2d 0x2d 0x2d - - S e t u p E n d - - - 0x0310: 0x2d 0x2d 0x00 0x00 0x11 0x10 0x03 0x18 0x03 0x30 0x78 0x33 0x38 0x32 0x3a 0x20 - - 0x00 0x00 0x11 0x15 0x03 0x03 0 x 3 8 2 : 0x0320: 0x30 0x78 0x32 0x33 0x30 0x2c 0x30 0x78 0x32 0x33 0x31 0x0a 0x00 0x5a 0x5a 0x5a 0 x 2 3 0 , 0 x 2 3 1 0x0a 0x00 Z Z Z 0x0330: 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z Z 0x0340: 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x5a 0x30 0x78 0x37 0x37 0x20 Z Z Z Z Z Z Z Z Z Z Z 0x0350: 0x30 0x3a 0x20 0x20 0x00 0x33 0x39 0x2c 0x30 0x78 0x32 0x34 0x31 0x0a 0x00 0x51 0x00 : 0x00 3 9 , 0 x 2 4 1 0x0a 0x00 Q 0x0360: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51 Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q Q 0x0370: 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x51 0x0d 0x39 0x02 Q Q Q Q Q Q Q Q Q Q Q Q Q 0x0d 9 0x02 0x0380: 0x41 0x02 0xad 0x03 0x31 0x02 0x2d 0x8f 0x01 0x00 0x00 0x08 0x02 0x00 0x00 0xe8 A 0x02 0xb4 0x03 1 0x02 B 0x97 0x01 0x00 0x00 0x08 0x02 0x00 0x00 0xe8 0x0390: 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0xc5 0x00 0xc4 0x00 0xc0 0x00 0xc1 0x00 0xc2 0x03 0x00 0x00 0x00 0x00 0x00 0x00 0xc5 0x00 0xc4 0x00 0xc0 0x00 0xc1 0x00 0xc2 0x03a0: 0x00 0xc6 0x00 0x01 0x00 0x00 0x04 0x0a 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xc6 0x00 0x01 0x00 0x00 0x1a 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x03b0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x03c0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x03d0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x03e0: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x20 0x30 0x78 0x30 0x30 0x20 0x30 0x78 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 x 7 8 0x03f0: 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0x32 0x30 0x20 0x30 0x78 0x33 0x32 0 x 2 0 0 0 --- Setup End -----