Указатель на массив символов

array char

Я пытаюсь передать список файлов (расположенных в скетче) для чтения с помощью написанной мной библиотеки. Список может иметь разные имена файлов и различаться количеством файлов.

Как передать этот массив в мою библиотеку?

например:

char *parameterFiles[3] = {"/myIOT_param.json", "/myIOT2_topics.json", "/sketch_param.json"};

EDIT_1

Чтобы более четко объяснить, что мне нужно: Допустим, моя библиотека имеет имя класса myIOT2. Этот класс содержит массив, содержащий список всех имен файлов (здесь показан не весь класс). Эти имена отличаются от одного использования библиотеки к другому, и в ней могут быть не все 4 файла (может быть также сохранено 0 файлов).

Я хочу иметь возможность не задавать точное имя файла заранее, а передавать этот массив как часть моего скетча, как показано до EDIT_1.

class myIOT2
{
public:    
const char *parameter_filenames[4] = {nullptr, nullptr, nullptr, nullptr}; 


};

, 👍0

Обсуждение

Вы имеете в виду собственную библиотеку, которую вы сейчас пишете?, @Edgar Bonet

@EdgarBonet - Извините, да, @Guy . D

@EdgarBonet, пожалуйста, смотрите мой комментарий для ответа, @Guy . D

Я видел комментарий. Это не похоже на то, на что вы ожидаете ответа., @Edgar Bonet

@EdgarBonet, пожалуйста, объясните - добавление этих переменных имеет решающее значение для ответа. Надеюсь объяснили почему., @Guy . D

Объяснить, что? Если вам нужно добавить какие-то переменные, я не вижу в этом проблемы. Если у вас есть вопрос, сформулируйте его максимально четко, отредактировав вопрос здесь. Представьте, что вы разговариваете с кем-то совершенно тупым (я не очень хорошо умею экстраполировать правильный вопрос на основе очень частичной информации)., @Edgar Bonet

@EdgarBonet см. EDIT_1, @Guy . D


1 ответ


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

4

Вы должны передать как указатель на список, так и длину списка как дополнительный аргумент. Подпись функции может быть чем-то нравится:

void processFiles(const char *fileList[], int fileCount);

Обратите внимание, что const char *fileList[] — это просто причудливый способ записи const char **fileList. Я нахожу первое более читаемым, но это полностью субъективно.

Вот небольшой тестовый код, показывающий это в действии:

void processFiles(const char *fileList[], int fileCount)
{
    for (int i = 0; i < fileCount; ++i) {
        Serial.print("Processing file ");
        Serial.println(fileList[i]);
    }
}

const char *parameterFiles[3] = {
    "/myIOT_param.json",
    "/myIOT2_topics.json",
    "/sketch_param.json"
};

void setup() {
    Serial.begin(9600);
    processFiles(parameterFiles, 3);
}

void loop() {}

В качестве альтернативы вы можете поместить «страж» в конец списка: нулевой указатель, указывающий, что на этом список заканчивается:

void processFiles(const char *fileList[])
{
    for (const char **p = fileList; *p; ++p) {
        Serial.print("Processing file ");
        Serial.println(*p);
    }
}

const char *parameterFiles[] = {
    "/myIOT_param.json",
    "/myIOT2_topics.json",
    "/sketch_param.json",
    nullptr
};

void setup() {
    Serial.begin(9600);
    processFiles(parameterFiles);
}

void loop() {}

ОБНОВЛЕНИЕ: ответ на EDIT_1.

Класс [Моей библиотеки] содержит массив, содержащий список всех имена файлов

Во-первых, вам нужно решить, кто отвечает за хранение этих имена файлов: библиотека или ее клиент. Когда вы пишете:

const char *parameterFiles[3] = {
    "/myIOT_param.json", "/myIOT2_topics.json", "/sketch_param.json"
};

вы создаете 4 массива: массив из 3 указателей с именем parameterFiles и три массива символов, содержащих имена файлов. Обратите внимание, что эти 3 массива являются анонимными: они не являются массивами. переменные. Если клиентский код попытается передать этот parameterFiles в вашей библиотеки, идентификатор массива превратится в указатель, а ваш библиотека получит этот указатель. Что с этим делать?

  1. Библиотека может просто сохранить копию указателя. Затем клиент несет ответственность за то, чтобы он оставался действительным до тех пор, пока библиотека может понадобиться. На практике это означает, что parameterFiles должна быть глобальной переменной и не должна изменяться после передачи библиотека.

  2. Библиотека может сделать копию массива. Затем клиент освобождается от этой ответственности. Тем не менее, он по-прежнему несет ответственность за гарантируя, что указатели, которые были скопированы из массива, останутся действительны, т. е. имена файлов остаются в памяти на одном и том же месте.

  3. Библиотека может сама копировать имена файлов. Затем клиент не несет никакой ответственности за поддержание корректности указателей.

Если вы выберете вариант 2 или 3, в библиотеке должен будет храниться один или несколько массивы. Затем вам нужно будет выбрать, выделять ли вы их статически или динамически с помощью new. Динамическое размещение больше эффективен, когда массивы могут сильно различаться по длине, но это может увеличить проблемы с фрагментацией памяти на устройствах с ограниченным объемом оперативной памяти.

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

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

Вот игрушечная реализация класса myIOT2, где список имена файлов копируются конструктором в класс:

class myIOT2 : public Printable
{
public:
    static const int maxFileCount = 4;

    myIOT2(const char *fileList[], int count) {
        if (count > maxFileCount)
            count = maxFileCount;  // discard extra files
        fileCount = count;
        for (int i = 0; i < fileCount; i++)
            filenames[i] = fileList[i];
    }

    size_t printTo(Print& p) const {
        size_t count = p.print(F("myIOT2["));
        for (int i = 0; i < fileCount; i++) {
            count += p.print('"');
            count += p.print(filenames[i]);
            count += p.print('"');
            if (i < fileCount - 1)
                count += p.print(", ");
        }
        count += p.print(']');
        return count;
    }

private:
    const char *filenames[maxFileCount];
    int fileCount;
};

Обратите внимание, что массив имен файлов размещается статически, жесткий максимум на количество файлов, которые могут быть сохранены. я сделал class Printable только для удобства отладки.

А вот пример использования этого класса:

const int fileCount = 3;

const char *parameterFiles[fileCount] = {
    "/myIOT_param.json", "/myIOT2_topics.json", "/sketch_param.json"
};

myIOT2 iot(parameterFiles, fileCount);

void setup() {
    Serial.begin(9600);
    Serial.println(iot);
}

void loop() {}

Этот тестовый скетч печатается:

myIOT2["/myIOT_param.json", "/myIOT2_topics.json", "/sketch_param.json"]
,

отличная идея со "стражем". Никогда не сталкивался с использованием такого цикла for, @Guy . D

Чтобы завершить мой первоначальный вопрос - lib будет содержать fileList и fileCount, чтобы иметь указатель для последующего использования, а функция Эдгара может быть: void processFiles (const char *_fileList[], int _fileCount) { число_файлов=_счетчик_файлов; for (int i = 0; i <fileCount; ++i) { Serial.print("Обработка файла"); список_файлов[i]=_список_файлов[i]; Serial.println(список_файлов[i]); } }, @Guy . D