0

I'm trying to instantiate and easily access an array of names in C++ using basic types in contiguous memory. I'm astounded that this is extremely difficult or complicated to do in C++ WITH ONLY basic types.

For some background, I am programming a microcontroller with limited memory, modest processing power, and it is handling serial communication over a network to 36 other microcontrollers sending continuous sensor data which is uploaded to a webserver. The shorter the refresh rate of the data, the better, so I prefer basic program features.

Not that I'm saying the more complicated stuff I've looked in other forums for, like an array of strings, has worked.

In my desperation, I was able to get this to work.

char names_array[] = "Bob\0\0Carl";
printf("%s",names_array); //outputs Bob
printf("%s",names_array + 5); //outputs Carl

This is a horrible solution though. My indexing is dependent on the longest name in the array, so if I added "Megan" to my list of names, I'd have to add a bunch of null characters throughout the entire array.

What I want to do is something like this:

char names_array[2] = {"Bob","Carl"}; //does not compile
printf("%s",names_array[0]);
printf("%s",names_array[1]);
//Error: A value of type "const char *" cannot be used to
//initialize an entity of type "char" in "main.cpp"

but that didn't work.

I want to loop through the names in my list and do something with each name, so at this point, this is my best solution.

char name0[] = "Bob";
loop_code(name0);
char name1[] = "Carl";
loop_code(name1);
.
.
.

I expect there's a reasonable way to make an array of pointers, each to an array of char terminated by null(s). I must be doing something wrong. I refuse to believe that a language like C++ is incapable of such a basic memory allocation.

Mitchal
  • 3
  • 2
  • 1
    Are you sure that `char names_array[2] = {"Bob","Carl"};` ever compiled? Because it shouldn't. If it did, you should seriously consider switching to a more useful compiler… – Michael Kenzel Apr 30 '19 at 01:22
  • 3
    `char names_array[2]` => `const char* names_array[2]` – Paul Rooney Apr 30 '19 at 01:24
  • It's complicated to do because you're not using features of the language to make it easier. But since that's your restriction, that isn't to say it's impossible, but that's just to explain why it might be harder. – Tas Apr 30 '19 at 01:25
  • *but that didn't work* -- I think this question may be closed, because of a typo. [See here](http://coliru.stacked-crooked.com/a/42944494478bd53c), Except for the C++ ISO warning, the text is not garbled. – PaulMcKenzie Apr 30 '19 at 01:26
  • It seems you want to use c++ as a glorified c. That is perfectly fine. You can use zero terminated strings and initialize an array of pointers. But beware that there is no guarantee that they will be contagious. Or you can have one large string with a separator embedded within. If all you want to do is just iterate over the list that might do. – Dr Phil Apr 30 '19 at 01:35
  • Check this one. It seems that's easy you want https://stackoverflow.com/questions/1088622/how-do-i-create-an-array-of-strings-in-c – Dr Phil Apr 30 '19 at 01:38
  • @PaulRooney prefer `const char *names_array[2]` as `const char* a, b, c` certainly doesn't declare 3 `const` qualified pointers to `char`. Using `const char *a, b, c` makes that much more apparent. – David C. Rankin Apr 30 '19 at 01:52
  • @DavidC.Rankin this is purely a matter of style. People have been arguing over this for decades and will probably continue to do so for centuries to come…both styles are commonly used…I don't think this really is something relevant to discussion here… ;) – Michael Kenzel Apr 30 '19 at 02:05
  • Agree, it is a "Nit" as included below, but... one that can be corrected. It's not something intended to help those fluent in the language, but for those that are learning. – David C. Rankin Apr 30 '19 at 02:06
  • @DavidC.Rankin There is nothing to "correct" here. It's purely a matter of taste. Objectively, both versions do exactly the same thing…one might just as well debate whether if should be `if(a)` or `if (a)`…or whether one should use tabs or spaces for indentation…or whether one should use indentation at all…you may prefer one option over the other and you may have good reasons for doing so…that's totally fine and great…but that doesn't make it more correct… – Michael Kenzel Apr 30 '19 at 02:17
  • @Michael Kenzel Your first comment was correct. My mistake in writing the wrong comment. I confused it with other attempts that outputted garbled text. – Mitchal Apr 30 '19 at 19:57
  • @Paul Rooney How do you then assign `names_array[0]` and `names_array[1]` to "Bob" and "Carl" easily? I can make a char array for each name and then assign the pointer in `names_array[0]` and `names_array[1]`, but that's not elegant. – Mitchal Apr 30 '19 at 20:03
  • @PaulMcKenzie You're correct about the compilation. Michael Kenzel pointed that out as well. My mistake. I fixed it. – Mitchal Apr 30 '19 at 20:05
  • @Mitchal ok, thought so; that's good then, means your compiler is not completely broken… ;) – Michael Kenzel Apr 30 '19 at 20:07
  • @Dr Phil Yes. I'm programming an mbed. The language used is C++ but a lot of the built in stuff preferentially uses C stuff. Many functions will not take strings as input for instance, so there's quite a bit of conversion to C strings. I'm leaning right now towards your recommendation, a dynamic char array with a single null separating names, and an index array to keep track of where each. Then I could add names fairly easily. Still inelegant though. – Mitchal Apr 30 '19 at 20:29

2 Answers2

1

You can, e.g., get an array of pointers to null-terminated strings:

const char* names_array[] = { "Bob", "Carl" };

and then

std::printf("%s", names_array[0]);
std::printf("%s", names_array[1]);

The problem with your attempt

char names_array[2] = {"Bob","Carl"};

is that you declare names_array to be an array of characters. This should never compile because what the = {"Bob","Carl"} essentially attempts to do is initialize each character in that array of characters with an entire array of characters of its own. A character is just a character, you cannot assign an entire array of characters to just an individual character. More precisely, initialization of a character array from a string literal is a special case of initialization [dcl.init.string] that allows a single string literal to be used to initialize an entire character array (because anything else doesn't make sense). What you actually want would be something more like an array of character arrays. However, the problem there is that you'd have to effectively pick a fixed maximum length for all strings in the array:

char names_array[][5] = { "Bob", "Carl" };  // each subarray is 5 characters in length

which would be potentially wasteful. You can flatten a series of multiple strings into one long array and then index into that, like you did with your first approach. The downside of that, as you've found out, is that you then need to know where each string starts in that array…

If you just want an array of string constants, a more modern C++ approach would be something like this:

#include <string_view>

using namespace std::literals;

constexpr std::string_view names[] = {
    "Bob"sv,
    "Carl"sv
};

The advantage of std::string_view is that it also has information about the length of the string. However, while std::string_view is compatible with most of the C++ standard library facilities that handle strings, it's not so simple to use it together with functions that expect C-style null-terminated strings. If you need null-terminated strings, I'd suggest to simply use an array of pointers to strings as shown at the very beginning of this answer…

Michael Kenzel
  • 15,508
  • 2
  • 30
  • 39
  • Nit `const char* names_array[]` better as `const char *names_array[]`. Not as likely to invoke confusion, e.g. `char* a, b, c` doesn't declare 3 pointers. `char *a, b, c` makes that clear. – David C. Rankin Apr 30 '19 at 01:58
0

char can has only one character.

If you want to use char, you can do it like

char name0[3] = "Bob";
char name1[4] = "Carl";
char *nameptr[2] = {&name0[0], &name1[0]};

Acutally, this pretty hard.

I suggest to you, use std::string.

std::string name[2] = {"Bob","Carl"};

this code is acceptable.

Retalia K
  • 64
  • 9
  • OP was very specific in saying they only wish to use basic types, so `std::string` is out. – Tas Apr 30 '19 at 02:00