Передача строки в функцию
- Войдите на сайт для отправки комментариев
Ср, 25/12/2019 - 17:41
Люди добрые! Вы простите, что я к вас обращаюсь. Сами мы не местные, паспорт украли..... ну и т.д. :)
допустим, есть функция
void foo ( char * arg){
// чего-то там
}
когда я к ней обращаюсь foo("argument"); - все ок. Когда делаю так
char s[] = "argument"; foo(s);
программа крашится, проц уходит в ребут.В чем разница, подскажите плз.
нада объявить const
char*s ="argument";нада объявить const
char*s ="argument";void foo(char* t, char* tt){ for(uint8_t i = 0; i<9; i++){ Serial.printf("%d %x %x\n", i, *(t+i), *(tt+i)); } Serial.printf("strlen t = %d, strlen tt = %d\n", strlen(t), strlen(tt)); } void setup() { Serial.begin(115200); char s[] = "argument"; foo("argument", s); } void loop() {}В мониторе :
огласите весь нерабочий код. минимальную программу, которая крашыца.
Полный код. Всегда. Полный. Код.
Ну, мужики, держитесь! :)
типа main:
#define MY_CS 5 #define MAX_PLAYLIST 128 #define MAX_NAME_LEN 20 #include "header.h" File file; void setup() { Serial.begin(115200); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); Serial.print("Initializing SD card..."); if (!SD.begin(MY_CS)) { Serial.println("initialization failed!"); return; } Serial.println("initialization done."); uint64_t cardSize = SD.cardSize() / (1024 * 1024); Serial.printf("SD Card Size: %lluMB\n", cardSize); getURLcontent();// проверяем контент на FTP listDir(SD, "/", 0);// проверяем контент на SD checkSDcontent();//имена лишних файлов с на карте(которые не совпадают //с плейлистом на серваке) - заносим в в поле process // для последующего удаления // имена файлов которые есть на серваке но нет на карте // заносим в process для последующего скачивания for(uint8_t i = 0; i< filesDowmloadNumber; i++){ if(strlen(URLplayList[i].process) > 0) Serial.printf("Going to download %s \n", URLplayList[i].process); download_file(URLplayList[i].process, folderURL); // скачиваем недостающие memset(URLplayList[i].process, 0, sizeof(URLplayList[i].process)); } listDir(SD, "/", 0);// проверяем контент на SD } void loop() { }Файл header.h
#include <UDHttp.h> #include <FS.h> #include <SD.h> #include <SPI.h> #include <WiFiClient.h> #include "myClient.h" const char* ssid = "***"; const char* password = "***"; char ftp_server[] = "***"; char ftp_user[] = "***"; char ftp_pass[] = "***"; char folderURL[] = "***"; const char * urlFileName = "shortSample.mp3"; struct PlayList{//структура плейлиста uint16_t id; uint16_t order; char name [MAX_NAME_LEN]; char process [MAX_NAME_LEN]; uint8_t priority; uint32_t fileSize; }; int16_t urlFileNumber = 0;//количество файлов на серваке int16_t sdFileNumber = 0;//количество файлов на карте int16_t filesDowmloadNumber = 0;//количество файлов кот надо скачать PlayList SDplayList[MAX_PLAYLIST];//плейлист на карте PlayList URLplayList[MAX_PLAYLIST];//плейлист на сервакефайл с функциями functions.ino - самый треш :)
// не используется int responsef(uint8_t *buffer, int len) { Serial.printf("%s\n", buffer); return 0; } //write data callback int wdataf(uint8_t *buffer, int len) { //write downloaded data to file return file.write(buffer, len); } //отображение прогресса скачивания void progressf(int percent) { static int last = -1; if (last != percent)Serial.println(percent); last = percent; } //****************************************************** DOWNLOAD FILE VIA HTTP void download_file(char* file_name , char* folder_name) { UDHttp udh; uint8_t _a = strlen(folder_name); uint8_t _b = strlen(file_name); char url[_a + _b + 1]; memset(url, 0, sizeof(url)); memcpy(url, folder_name, _a);//strcpy тут не катит, как оказалось memcpy(url + _a, file_name, _b); Serial.printf("Start Doanloading %s\n", url);//проверяем правильность URL file = SD.open( file_name, FILE_WRITE);//открываем файл для записи if (!file) { Serial.println("can not open file!"); return; } Serial.print("Memory - "); Serial.println(uxTaskGetStackHighWaterMark(NULL)); udh.download(url, wdataf, progressf);//чтение в буфер, сбрасываем на карту, печать прогресса file.close(); Serial.printf("done downloading\n"); } //******************************************************** CD CARD DIRECTORY LIST void listDir(fs::FS &fs, const char * dirname, uint8_t levels) { uint8_t i = 0; File root = fs.open(dirname); if (!root) { Serial.println("Failed to open directory"); return; } if (!root.isDirectory()) { Serial.println("Not a directory"); return; } File file = root.openNextFile(); while (file) { if (file.isDirectory()) { if (levels) { listDir(fs, file.name(), levels - 1); } } else { memcpy(SDplayList[i].name, file.name(), sizeof(SDplayList[i].name)); SDplayList[i++].fileSize = file.size(); } file = root.openNextFile(); } sdFileNumber = i; printSDList(); } //**************************************** GET FTP CONTENT void getURLcontent() { uint8_t validFileCounter = 0; urlFileNumber = 0; myESP32_FTPClient ftp (ftp_server, ftp_user, ftp_pass); ftp.OpenConnection(); ftp.ChangeWorkDir("***"); String response = ""; String list[MAX_PLAYLIST]; ftp.InitFile("Type A"); ftp.ContentList("", list); ftp.CloseConnection(); for ( uint8_t i = 0; i < sizeof(list); i++) { uint8_t indexSize = 0; uint8_t indexMod = 0; if (list[i].length() > 0) { list[i].toLowerCase(); // нас интересуют только файлы mp3 if ( list[i].indexOf("file") > -1 and list[i].indexOf(".mp3") > -1) { URLplayList[validFileCounter].name[0] = '/'; strcpy(URLplayList[validFileCounter].name + 1, &list[i].substring(list[i].indexOf("; ") + 2)[0]); indexSize = list[i].indexOf("size") + 5; indexMod = list[i].indexOf("modify") - 1; URLplayList[validFileCounter].fileSize = list[i].substring(indexSize, indexMod).toInt(); validFileCounter++; } Serial.println(list[i]); } else break; } urlFileNumber = validFileCounter; printUrlList(); } void printUrlList() { for (uint8_t i = 0; i < urlFileNumber; i++) { Serial.print(i + 1); Serial.print(" "); Serial.print(URLplayList[i].name); Serial.print(" "); Serial.println(URLplayList[i].fileSize); } } void printSDList() { for (uint8_t i = 0; i < sdFileNumber; i++) { Serial.print(i + 1); Serial.print(" "); Serial.print(SDplayList[i].name); Serial.print(" "); Serial.println(SDplayList[i].fileSize); } } //*******************************CHECK MATCHING FILES ON SD AND FTP void checkSDcontent() { Serial.println("SD:"); bool res = false; String str = ""; for (uint8_t i = 0; i < sdFileNumber; i++) { res = true; for (uint8_t j = 0; j < urlFileNumber; j++) { str = String(URLplayList[j].name); if (compareStr(SDplayList[i].name, URLplayList[j].name, str.indexOf("mp3"))) { res = false; break; } } Serial.print(SDplayList[i].name); Serial.print("-"); Serial.println(!res ? "OK" : "DELETE"); res = false; } Serial.println("URL:"); Serial.print("urlFileNumber = "); Serial.println(urlFileNumber); Serial.print("sdFileNumber = "); Serial.println(sdFileNumber); str = ""; for (uint8_t i = 0; i < urlFileNumber; i++) { res = true; for (uint8_t j = 0; j < sdFileNumber; j++) { str = String(URLplayList[i].name); if (compareStr(URLplayList[i].name, SDplayList[j].name, str.indexOf("mp3"))) { res = false; break; } } if (res) { Serial.println("DOWNLOAD!"); Serial.print("i = "); Serial.println(i); Serial.print("file name = "); Serial.println(URLplayList[i].name); //download_file(URLplayList[i].name); memcpy(URLplayList[i].process, URLplayList[i].name, sizeof(URLplayList[i].name)); filesDowmloadNumber++; res = false; } } Serial.printf("filesDowmloadNumber - %d \n", filesDowmloadNumber); } //************************* COMPARE STRING // возвращает true если одинаковые // написал пока не выявил ф-цию источник краша bool compareStr(const char* str1, const char * str2, uint8_t str1len) { bool res = true; Serial.printf("Compare %s and %s len=%d \n", str1, str2, str1len); for (uint8_t i = 0; i < str1len; i++) { if (*(str1 + i) != *(str2 + i)) { res = false; break; } } Serial.println(res ? "OK" : "NOT"); return res; }Там еще два файла с библиотекой myESP32_FTPClient, но она не причина краша.
Вот в этом варианте программа добросовестно крашится при обращении к ф-ии void download_file(char* file_name , char* folder_name)
в файле functions.
В мониторе:
URLы запикал - не мой сервак, сорри.
Вот такая картина. Ссылка на библиотеку http клиента, где реализована ф-ия udh.download(url, wdataf, progressf);
Ну как минимум, навскидку, вижу. что в listlDir не закрывается дескриптор. open мы делаем, а close - нет. А надо бы. Далее, строка 80 - там ошибка:
Маркер конца итерации - неправильный, это НЕ количество элементов list, а просто его размер. Надо так:
Далее - чем strcmp не устроил, зачем самописные compareStr?
Короче, в коде ошибки есть, памяти оно жрёт, наскидку, не меньше 12 килобайт, жость :)
теперь строку 35 в файле functions я тупо меняю на:
udh.download("***/shortSample.mp3", wdataf, progressf);
И файл shortSample.mp3 три раза успешно скачиваются и сохраняется под разными именами на карте.
Ну как тут матом не заругацца!
Очень много сделано через зад и без знания языка. Склеивают строки так:
char url[80] = "";
strcat(url, folder_name);
strcat(url, file_name);
Ну и директория не может называться "***".
Очень много сделано через зад и без знания языка. Склеивают строки так:
char url[80] = "";
strcat(url, folder_name);
strcat(url, file_name);
Ну и директория не может называться "***".
", и пришлось написать так как написано. Эта проблема встречалась и у других, и в инете описана. Отнесем ее к багу. По началу многое было написано не так. Это вариант, который получился в следствии попыток избавиться от проблемы. Хотя да, я еще ток писака.
Директории запикал, сорри.
Ну то есть мы не будем править ошибки в коде, да и вообще код, чтобы не рушить стек, да? Вместо этого будем стрелять себе в ногу до тех пор, пока это кажется безопасным. Ведь если зажмуриться - то и не видно, правда?
Один тот факт, что было сообщение о краше стека - должен был навести на мысль, что стек - не резиновый, и надо бы переписать код, чтобы стек не рушился. Это не считая ошибок, о которых я писал выше.
Ну как минимум, навскидку, вижу. что в listlDir не закрывается дескриптор. open мы делаем, а close - нет.
Проц ESP32, памяти вроде достаточно.
Люди добрые! Вы простите, что я к вас обращаюсь. Сами мы не местные, паспорт украли..... ну и т.д. :)
допустим, есть функция
void foo ( char * arg){
// чего-то там
}
когда я к ней обращаюсь foo("argument"); - все ок. Когда делаю так
программа крашится, проц уходит в ребут.В чем разница, подскажите плз.
тут разница тока что во втором случае на стеке выделяется память для строки и она копируется туда а в первом просто ссылка на строку лежащую где в памяти с самого начала загрузки программы
со стеком у вас скорей всего намучено что то где то портится в другом месте
Правда разницы не увидел.
По прежнему в мониторе порта не видно разницы? Объясняю: sizeof одного экземпляра класса String - 6 байт, емнип. У вас в массиве таких экземпляров 20 штук. В ошибочном коде - вы пройдёте 120 (6*20) раз хрен знает по каким местам памяти, потому что, очевидно - вы вылазите за границы массива.
Во втором случае - получите размерность массива, потому что 120/6 = 20.
Рекомендую полистать книжку по С++, всё-таки.
Один тот факт, что было сообщение о краше стека - должен был навести на мысль, что стек - не резиновый, и надо бы переписать код, чтобы стек не рушился.
Во втором случае - получите размерность массива, потому что 120/6 = 20.
именно в мониторе и не увидел, а смысл понятен.
Рекомендую полистать книжку по С++, всё-таки.
Один тот факт, что было сообщение о краше стека - должен был навести на мысль, что стек - не резиновый, и надо бы переписать код, чтобы стек не рушился.
С++ - он такой. Опасная базука, которой можно себе бошку снести. То, что кажется, что ошибки нет - это только кажется.
Ещё раз: код - переписывать, ошибки - править, занятость стека - уменьшать, от самописных функций сравнения строк - избавляться, не гнать на strcpy и strcat - и постепенно всё получится.
Сейчас же ситуация следующая: вроде бы должно работать - но будет работать по фазам Луны. Надо проводить анализ кода на ошибки, плотный. А ошибки - есть, это точно.
тут разница тока что во втором случае на стеке выделяется память для строки и она копируется туда а в первом просто ссылка на строку лежащую где в памяти с самого начала загрузки программы
со стеком у вас скорей всего намучено что то где то портится в другом месте
сейчас проблема:
LoadProhibited, StoreProhibited
This CPU exception happens when application attempts to read from or write to an invalid memory location. The address which was written/read is found in
EXCVADDRregister in the register dump. If this address is zero, it usually means that application attempted to dereference a NULL pointer. If this address is close to zero, it usually means that application attempted to access member of a structure, but the pointer to the structure was NULL. If this address is something else (garbage value, not in0x3fxxxxxx-0x6xxxxxxxrange), it likely means that the pointer used to access the data was either not initialized or was corrupted.А именно вот эта: it usually means that application attempted to dereference a NULL pointer. еще бы понять чего это означает.... :/
я помню когда был молодой и зеленый писал большую программу на чистом Си, где вся работа со строками была на обычных сишных массивах и функциях навроде str***, короче программа стала крашится из за повреждения стека рандомно и ошибку я так и не нашел просидев в отладчике кучу времени))
сейчас проблема:
This CPU exception happens when application attempts to read from or write to an invalid memory location.
Что непонятно в описании проблемы? Я же говорю - код полон ошибок, портим память. Может, лучше начать с примеров попроще, а не браться сразу на Уильяма нашего Шекспира?
Что непонятно в описании проблемы? Я же говорю - код полон ошибок, портим память. Может, лучше начать с примеров попроще, а не браться сразу на Уильяма нашего Шекспира?
Что непонятно в описании проблемы? Я же говорю - код полон ошибок, портим память. Может, лучше начать с примеров попроще, а не браться сразу на Уильяма нашего Шекспира?
У вас с английским не очень, да? It usually means означает, что "Обычно, это означает...". Т.е. вам просто приводят пример, который может привести к такому поведению. Это - один из use-case, не более того. У вас проблема - в каше в коде, в которой (каше) очень сложно найти ошибки. Но они - есть. Парочку - я нашёл сходу, и то - ещё не факт, что вы правильно их исправили.
ТС у вас самый сложный БАГ рандомная порча памяти, программа у вас маленькая лучше перепишите все заново а то задолбаетесь искать
еще аццки неудобно писать программу без возможности запустить программу в отладчике и интерактивно пронаблюдать за изменением памяти после исполнения каждой строки, я вапще незнаю как под эти ардуины писать - нет даже примитивных средств отладки
Как много я пропустил-то пока с е-бумагой "любовью занимался" :-(
Как много я пропустил-то пока с е-бумагой "любовью занимался" :-(
У вас с английским не очень, да? It usually means означает, что "Обычно, это означает...". Т.е. вам просто приводят пример, который может привести к такому поведению. Это - один из use-case, не более того. У вас проблема - в каше в коде, в которой (каше) очень сложно найти ошибки. Но они - есть. Парочку - я нашёл сходу, и то - ещё не факт, что вы правильно их исправили.
...я вапще незнаю как под эти ардуины писать - нет даже примитивных средств отладки
А последовательный порт на что?
Как это нет?
А последовательный порт на что?
Это наше все! :)
А последовательный порт на что?
Это уже продвинутое. Примитивное - это светодиод на 13-м пине.