CStringArray

Introduction

This is a class to manage a double NUL-terminated list of strings, such as "one\0two\0three\0".

It’s similar in operation to Vector<String>, but more memory-efficient as all the data is stored in a single String object. (CStringArray is a subclass of String.)

You can see some examples in Sming/Core/DateTime.cpp and Sming/Core/Data/WebConstants.cpp.

Background

Each value in the sequence is terminated by a NUL character \0. For clarity, placing one string per line is suggested:

// ["one", "two", "three"]
CStringArray csa = F(
   "one\0"
   "two\0"
   "three\0"
);

Note use of the F() macro. Assignments require a length because of the NUL characters, so this won’t work as expected:

// ["one"]
CStringArray csa =
   "one\0"
   "two\0"
   "three\0";

When assigning sequences, the final NUL separator may be omitted (it will be added automatically):

// ["one", "two", "three"]
CStringArray csa = F(
   "one\0"
   "two\0"
   "three"
);

Sequences may contain empty values, so this example contains four values:

// ["one", "two", "three", ""]
CStringArray csa = F(
   "one\0"
   "two\0"
   "three\0"
   "\0"
);

Adding strings

Elements can be added using standard concatenation operators:

CStringArray arr;
arr += "string1";
arr += 12;
arr += 5.4;
arr += F("data");

Be mindful that each call may require a heap re-allocation, so consider estimating or calculating the required space and using String::reserve():

CStringArray arr;
arr.reserve(250);
// now add content

Use with FlashString

You can use a single FlashString containing these values and load them all at the same time into a CStringArray:

DEFINE_FSTR_LOCAL(fstr_list,
   "a\0"
   "b\0"
   "c\0"
   "d\0"
   "e\0"
);

CStringArray list(fstr_list);
for(unsigned i = 0; i < list.count(); ++i) {
   debug_i("list[%u] = '%s'", i, list[i]);
}

Note

The entire FlashString is loaded into RAM so better suited for occasional lookups or if instantiated outside of a loop.

You may find FSTR::Array, FSTR::Vector or FSTR::Map more appropriate. See FlashString for details.

Iterator support

Looping by index is slow because the array must be scanned from the start for each access. Iterators are simpler to use and much more efficient:

for(auto s: list) {
   debug_i("'%s'", s);
}

For more complex operations:

CStringArray::Iterator pos;
for(auto it = list.begin(); it != list.end(); ++it) {
   debug_i("list[%u] = '%s' @ %u", it.index(), *it, it.offset());
   // Can use direct comparison with const char* or String
   if(it == "c") {
      pos = it; // Note position
   }
}

if(pos) {
   debug_i("Item '%s' found at index %u, offset %u", pos.str(), pos.index(), pos.offset());
} else {
   debug_i("Item not found");
}

Comparison with Vector<String>

Advantages

More memory efficient Uses only a single heap allocation (assuming content is passed to constructor) Useful for simple lookups, e.g. mapping enumerated values to strings

Disadvantages

Slower. Items must be iterated using multiple strlen() calls Ordering and insertions / deletions not supported

API Documentation

class CStringArray : private String

Class to manage a double null-terminated list of strings, such as “one\0two\0three\0”.

Concatenation operators

template<typename T>
CStringArray &operator+=(T value)

Append numbers, etc. to the array.

Parameters
  • value: char, int, float, etc. as supported by String

Public Functions

bool add(const char *str, int length = -1)

Append a new string (or array of strings) to the end of the array.

Note

If str contains any NUL characters it will be handled as an array

Parameters
  • str:

  • length: Length of new string in array (default is length of str)

Return Value
  • bool: false on memory allocation error

bool add(const String &str)

Append a new string (or array of strings) to the end of the array.

Note

If str contains any NUL characters it will be handled as an array

Parameters
  • str:

Return Value
  • bool: false on memory allocation error

int indexOf(const char *str, bool ignoreCase = true) const

Find the given string and return its index.

Note

Comparison is not case-sensitive

Parameters
  • str: String to find

  • ignoreCase: Whether search is case-sensitive or not

Return Value
  • int: index of given string, -1 if not found

int indexOf(const String &str, bool ignoreCase = true) const

Find the given string and return its index.

Note

Comparison is not case-sensitive

Parameters
  • str: String to find

  • ignoreCase: Whether search is case-sensitive or not

Return Value
  • int: index of given string, -1 if not found

bool contains(const char *str, bool ignoreCase = true) const

Check if array contains a string.

Note

Search is not case-sensitive

Parameters
  • str: String to search for

  • ignoreCase: Whether search is case-sensitive or not

Return Value
  • bool: True if string exists in array

bool contains(const String &str, bool ignoreCase = true) const

Check if array contains a string.

Note

Search is not case-sensitive

Parameters
  • str: String to search for

  • ignoreCase: Whether search is case-sensitive or not

Return Value
  • bool: True if string exists in array

const char *getValue(unsigned index) const

Get string at the given position.

Parameters
  • index: 0-based index of string to obtain

Return Value
  • const: char* nullptr if index is not valid

const char *operator[](unsigned index) const

Get string at the given position.

Parameters
  • index: 0-based index of string to obtain

Return Value
  • const: char* nullptr if index is not valid

void clear()

Empty the array.

unsigned count() const

Get quantity of strings in array.

Return Value
  • unsigned: Quantity of strings