Vector char array as string

Hello!
String handling is an important concept of C++. The Arduino library provides the String class. The String class is discouraged due to memory usage, and char arrays are suggested, along with string.h manipulations. What bothers me about char arrays is that you need to know the maximum string length at the delcaration, and the maximum string size cannot be stored in a variable! Dynamic memory allocation is difficult. So, I tried using vector char arrays, and a library I made with a class named “VectorString”. I installed the StandardCplusplus library.

VectorString.h:

#ifndef VectorString_h
#define VectorString_h
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <StandardCplusplus.h>
#include <vector>
using namespace std;
class VectorString{
public:
  VectorString(const char*);
  void concat(const char*);
  void concat(char*);
  void concat(char);
  void assign(const char*);
  void assign(char*);
  char charAt(word);
  word length();
  char* getString();
private:
  vector <char> vec;
};
#endif

VectorString.cpp:

#include "VectorString.h"
VectorString::VectorString(const char* sz){
  for(word i = 0; i < strlen(sz); i++){
    vec[i] = sz[i];
  }
}
void VectorString::assign(const char* sz){
  for(word i = 0; i < strlen(sz); i++){
    vec[i] = sz[i];
  }
}
void VectorString::assign(char* sz){
  for(word i = 0; i < strlen(sz); i++){
    vec[i] = sz[i];
  }
}
void VectorString::concat(const char* sz){
  word eoa = vec.size();
  for(word i = 0; i < strlen(sz); i++){
    vec[i+eoa] = sz[i];
  }
}
void VectorString::concat(char* sz){
  word eoa = vec.size();
  for(word i = 0; i < strlen(sz); i++){
    vec[i+eoa] = sz[i];
  }
}
void VectorString::concat(char c){
  word eoa = vec.size();
  vec[eoa] = c;
}
char VectorString::charAt(word n){
  return vec[n];
}
word VectorString::length(){
  return vec.size();
}
char* VectorString::getString(){
  const word vecSize = vec.size();
  char buf[vecSize] = "\0";
  for(word i = 0; i < vecSize; i++) buf[i] = vec[i];
  return buf;
}

I made a test code using the library:

#include <VectorString.h>
VectorString vec("This is the initial string.");
void setup(){
  Serial.begin(9600);
  Serial.println(vec.getString());
  vec.assign("This is the new string.");
  Serial.println(vec.getString());
  vec.concat(" This is the appended string.");
  Serial.println(vec.getString());
  Serial.print("Character at position 7: ");
  Serial.println(vec.charAt(7));
}
void loop(){
}

And got the following compiler error:

In file included from sketch_jul22a.cpp:1:
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/VectorString.h:23: error: ISO C++ forbids declaration of 'vector' with no type
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/VectorString.h:23: error: expected ';' before '<' token

I tried copying vector.cpp and vector from the StandardCplusplus library folder into the VectorString library folder, changed:

#include <StandardCplusplus.h.>
#include <vector>

into:

#include "vector"

and got the following errors:

In file included from C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/VectorString.h:10,
                 from sketch_jul22a.cpp:1:
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/vector:36: error: expected type-specifier before 'allocator'
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/vector:36: error: expected '>' before 'allocator'
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/vector:45: error: function definition does not declare parameters
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/vector:369: error: return type specification for destructor invalid
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/vector:369: error: invalid use of incomplete type 'struct std::vector<T, Allocator>'
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/vector:36: error: declaration of 'struct std::vector<T, Allocator>'
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/vector:377: error: two or more data types in declaration of 'reserve'
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/vector:377: error: 'size_type' was not declared in this scope
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/vector:393: error: two or more data types in declaration of 'resize'
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/vector:393: error: 'size_type' was not declared in this scope
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/vector:393: error: expected primary-expression before 'const'
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/vector:408: error: two or more data types in declaration of 'downsize'
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/vector:408: error: 'size_type' was not declared in this scope
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/vector:477: error: two or more data types in declaration of 'operator=='
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/vector:491: error: two or more data types in declaration of 'operator<'
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/vector:497: error: two or more data types in declaration of 'operator!='
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/vector:502: error: two or more data types in declaration of 'operator>'
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/vector:508: error: two or more data types in declaration of 'operator>='
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/vector:514: error: two or more data types in declaration of 'operator<='
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/vector:520: error: two or more data types in declaration of 'swap'
In file included from sketch_jul22a.cpp:1:
C:\Users\Ken Leung\Downloads\arduino-1.0.1\libraries\VectorString/VectorString.h:24: error: template argument 2 is invalid

What can I change in my library to make the functions work properly? Is my library any better than the String class?
Thanks!

You main .ino file needs to include all source files that get used, even the ones included in other files. In this case, vector needs to be included in your main .ino file.

This has to be done because the Arduino IDE only looks at the includes in the main .ino file to determine what to pass into the compiler for compilation.

That being said, vector also uses dynamic memory allocation. You aren't really solving any issue here, simply burying the underlying issue under another layer of abstraction.

What bothers me about char arrays is that you need to know the maximum string length at the delcaration, and the maximum string size cannot be stored in a variable!

Yes, it can. If the variable is properly defined as const.

PaulS:
Yes, it can. If the variable is properly defined as const.

You are correct. I must have remembered wrong, because I did this:

const word vecSize = vec.size();
char buf[vecSize];

and I thought that I got an error saying that variable size array ‘buf’ may not be declared.

I changed the test code:

#include <StandardCplusplus.h>
#include <vector>
#include <VectorString.h>
using namespace std;
VectorString vec("This is the initial string.");
void setup(){
  Serial.begin(9600);
  Serial.println(vec.getString());
  vec.assign("This is the new string.");
  Serial.println(vec.getString());
  vec.concat(" This is the appended string.");
  Serial.println(vec.getString());
  Serial.print("Character at position 7: ");
  Serial.println(vec.charAt(7));
}
void loop(){
}

I also changed VectorString.cpp here:

//char* buf;
  char buf[vecSize+1];
  //buf = (char*)malloc(sizeof(char)*vecSize+1);

It compiles correctly, but sketches using StandardCplusplus.h take a lot of time compiling. I will report back later when I actually test it.

const word vecSize = vec.size();
char buf[vecSize];

Constants have to be declared before run-time. Is vec.size() determined when?

I'm not sure where you got your STL library, but I have no problems with this one:

http://www.gammon.com.au/forum/?id=11119

Direct link:

http://andybrown.me.uk/ws/2011/01/15/the-standard-template-library-stl-for-avr-with-c-streams/

Besides, the STL has a string class. Why not just make a vector of type string?

I got the STL from the Playground. The string class doesn’t have the memory problems? Dynamic string size, able to access each character, and can turn into a char array (I think). I guess that is more useful.

Yes, any string class on a microprocessor will have potential memory problems, particularly with fragmentation.

STL vectors use dynamic memory so you are just replacing one problem with another one.

Unfortunately, instead of displaying the strings, it displayed 3 newlines, and a single line of text.

Character at position 7: s

How can I get around this problem? Is the string class, or String class better?

How can I make the function properly return a char array?

Return a pointer to a char array, same way as many C string array commands.

GoForSmoke:
Return a pointer to a char array, same way as many C string array commands.

How would I change this function:

char* VectorString::getString(){
  const word vecSize = vec.size();
  char buf[vecSize] = "\0";
  for(word i = 0; i < vecSize; i++) buf[i] = vec[i];
  return buf;
}

Why would you want to? It returns a char pointer but is also Vector class that uses the allocation and deallocation that shotguns your sparse RAM space.

Vector, String and the like are okay for limited use on Arduino. The problems I see are 1) learning those and not char arrays so which do you use? The one you 'know'. 2) not 'knowing' what is behind them, what they do leading to cluelessness when the sketch crashes.

You can change "char arrays are suggested" to "char arrays are strongly suggested".

How would I change this function:

The function should take a reference to where to store the result. The caller then should allocate (dynamically or statically) the space where the string is to be extracted to. Of course, that means that the caller is responsible for making sure that the size is appropriate.

for(word i = 0; i < vecSize; i++) buf = vec*;[/quote]*
What the hell is a word? Use standard Arduino types, not some shit invented by those idiots in Redmond.

I do believe that the term word as used in computing originated before Gates was in business. Even ATMEL uses the term.

I knew machines (were they called computer in those days ?) with word sizes of 12 or 36 bit !

A byte being 8 bit is common sense, uint16_t is known by rather basic include files to "all" c compilers to get rid of that annoying uncertainly what an int is, when it matters.

But word = uint16_t and dword = uint32_t, might be something you do not need to follow, if you don't want to.

I do believe that the term word as used in computing originated before Gates was in business.

It's size is not obvious, though. int, long, byte, float, double, all have easily remembered sizes. word is some vague typedef'd mess that never should have been allowed. It's far too vague.

A word is not shit. In programming terms, it is a group of bytes. On my Windows Programmer’s Calculator, there is an option to choose the [signed] number size in bytes:

  1. Byte (8 bits)
  2. Word (16 bits)
  3. Dword (32 bits)
  4. Qword (64 bits)
    In Arduino, it is a short term for unsigned int. http://arduino.cc/en/Reference/Word.
    I like using words.

I'm a bit more hardware oriented. Word length means a different thing to me. It was DEC who had the 12-bit words, either 4 too many or 4 too few.

So, do you think that I should just give up on VectorString? Would it be better to have 3 String/string/VectorString objects, or 3 char arrays with 50 character space allocation each? I still want to know what is preventing my VectorString::getString() function from returning a string printable to the Serial Monitor.