2

The following piece of code gives me the error: "too many initializers for 'char []'" :

int main()
{
    int input;
    char numbers[] = {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};

    std::cin >> input;

    std::cout << ((input > 9) ? "Greater than 9" : numbers[input-1]) << std::endl;
}

What's needed for this to work is for numbers to be a pointer variable, i.e:

char * numbers[] = {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};

I'm new to c++ and I'm trying to understand why this array needs to be a pointer and what exactly is happening in memory which requires this to be a pointer?

In other languages such as Java you can do the following:

import java.util.Scanner;

public class Playground
{
    public static void main(String[] args)
    {
        Scanner scanner = new Scanner(System.in);
        int input = scanner.nextInt();

        String[] numbers = {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
        System.out.println((input > 9) ? "Greater than 9" : numbers[input-1]);
    }
}

No Pointers are required here, and from my understanding there's no need for them in this kind of scenario either.

solarflare
  • 880
  • 2
  • 8
  • 23
  • 4
    `char` is a single **char**acter, not a string. You are trying to initialize an array of characters with an array of strings, which does not make sense. I'm not sure where the confusion stems from. – Max Langhof Jun 21 '19 at 08:53
  • 2
    `char numbers[]` should be `const char* numbers[]`. Or `std::string numbers[]`. – Blaze Jun 21 '19 at 08:53
  • Note that Java also uses pointers, only they are not visible to you. – Michael Chourdakis Jun 21 '19 at 08:58

3 Answers3

3

As @Max Langhof said in the comment char is a single character. You are trying to initialize an array of characters with an array of strings

You mention using C++, so instead of using C style arrays [] use the std::array available in the array header file. Along with std::string

std::array<std::string,SIZE> = {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};

Declaring it as a pointer it essentially creates an array of char pointers which in plain english translates to an array of char arrays.

enter image description here

If you want to learn more about C style char arrays The Definitive C++ Book Guide and List

Take the following code
const char* a [] = {"sadas", "dasdas"}; std::cout << a[0][0]; // will output 's'

a[0] will return sadas

Having a pointer to a char array will make the value const (read-only) a[0][0] = 'b' // illegal

Rostin
  • 161
  • 6
  • How does initializing a pointer variable to an array of characters with an array of strings solve the issue though? – solarflare Jun 21 '19 at 09:18
  • Just to check this with you `char * numbers[]` creates something like `[char["one"], char["two"]...]`, and `char numbers[]` creates `["one", "two"..]` which is invalid since chars can only store single characters? – solarflare Jun 21 '19 at 09:46
  • Yes, `char numbers[] = {"sada","sda"}` is invalid while `char numbers[] = "dadsadas" is fine – Rostin Jun 21 '19 at 10:16
  • _"it essentially creates an array of char pointers which in plain english translates to an array of char arrays"_ no no no no no I get that you're trying to simplify it but pleeeeease don't propagate this myth! – Lightness Races in Orbit Jun 21 '19 at 11:06
  • `sizeof(p)==4` is outdated or at the very least doesn't point out that it's impl-defined – Lightness Races in Orbit Jun 21 '19 at 11:07
  • Also the code suggested on that site won't compile (`char*` cannot be assigned a string literal since almost a decade ago). Don't link to random "tutorials", but instead to [a good book](https://stackoverflow.com/q/388242/560648). – Lightness Races in Orbit Jun 21 '19 at 11:08
  • @LightnessRacesinOrbit I linked the book guide list instead of the outdated tutorial ^_^, I know the sizeof(p) is imp-defined but, the picture makes its point :D. As to the myth.... didn't know what other analogy to use :( – Rostin Jun 21 '19 at 12:05
  • @LightnessRacesinOrbit According to godbolt, "char* cannot be assigned a string literal since almost a decade ago " this statement is wrong. It still compiles with std=c++17. It does give a warning because char* is not const but it does compile – Rostin Jun 21 '19 at 12:33
  • @Rostin That conversion was deprecated before C++11 and _illegal_ since. Looks like GCC and Clang are both more lenient than I remember, by making it a warning not an error; but the code is still invalid (not to mention dangerous!). – Lightness Races in Orbit Jun 21 '19 at 13:28
3

Since the strings are literals, i.e. constants, you should declare the array like this:

const char* numbers[] = { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };

This is the C way of things with the array defined at compile time. So the memory required for the array is calculated by the compiler. Hence you have to declare it as an array of const char*, i.e. the contents can't be changed as it is defined at compile time.

You could declare the array like this:

char numbers[9][6] = { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };

What this does is declare a 2D array of 9 elements, each element containing 6 chars. So now you could change the value of each word at run time if you want to. The square brackets [] make all the difference. When you use char*[] the compiler treats elements as literals.

You would have to allocate them on the heap if you don't know the size of each word in the array beforehand.

The C++ way is to use std:string (allocated on the heap internally for you) and these can be changed at run time:

std::string numbers[] = { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
jignatius
  • 6,304
  • 2
  • 15
  • 30
  • He already knows that, his question is *why* this is happening in C++. – Michael Chourdakis Jun 21 '19 at 09:05
  • With the C way of doing things - what exactly is happening in memory which requires the char array to be a pointer? – solarflare Jun 21 '19 at 09:22
  • Each word is a char * - an array of chars. So an array of words in char* []. The size of the array is calculated for you at compile time, in this case 9. – jignatius Jun 21 '19 at 10:18
  • @solarflare _"which requires the char array to be a pointer?"_ You keep saying that, but it's not what's happening. The array is not a pointer. The array _contains_ pointers. It's an array of pointers. Each pointer points to an array of characters, i.e. a C-style string. – Lightness Races in Orbit Jun 21 '19 at 11:09
2

What's needed for this to work is for numbers to be a pointer variable.

Your confusion lies here (and possibly also in what char signifies).

numbers is not a pointer variable, with or without the *.
The * is about the elements, not the array.

This:

char numbers[] = {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};

is an array of chars. It doesn't compile because a char is a single character, and none of the expressions "one", "two" etc fit that description.

Instead, they are string literals. These are each implemented as arrays of char (ironically, the sort of array you just tried to create!). We typically access them via pointers, of type const char* (in the olden days you could use char*, but that's no longer true; perhaps you're using an ancient compiler).

So, to fix your array, it needs to be not an array of chars, but an array of const char*s.

And that's what you're doing here (const added by me for modern correctness):

const char* numbers[] = {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};

… it's an array of const char*s.

And, yes, since C declaration syntax is confusing, you're arguably better off using modern C++ tools as shown in other answers.


No Pointers are required here, and from my understanding there's no need for them in this kind of scenario either.

That's not really true either, but it looks like it is because Java is a completely different language with different syntax and abstractions.

Somewhere underneath the bonnet, String is a pointer (because Java has managed objects), and furthermore it'll have a pointer inside it that points to dynamically-allocated data (so, in fact, there's additional indirection in the Java example!).

The only difference is that it's done for you, transparently, rather than you having to spell it out as you do in C.

It's best not to directly compare two unrelated languages; there's usually very little value in doing so.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • 1
    Thank you very much for this - yes this answer makes things much clearer to me. I've been struggling to get to grips with c++ pointers so ways in which they're used confuses me quite often. Understanding that `char * numbers` is an *array* of pointers is really helpful, as obvious as that description may sound to others! I'd disagree with you on comparing c++ to Java though. I'd argue learning a language by comparing it to another is a massive help! – solarflare Jun 21 '19 at 12:37