Go Down

Topic: Array of strings – compiling error [Solved] (Read 277 times) previous topic - next topic

guraknugen

Sep 12, 2017, 11:18 pm Last Edit: Sep 13, 2017, 08:59 pm by guraknugen
Hi. I try to declare an array of strings (2-dimensional array of characters), but I can't get rid of this error message:
Quote
declaration of 'X' as multidimensional array must have bounds for all dimensions except the first
I'm not sure what that means (my native language is not English, which makes it slightly harder), nor how to correct it.
My code is currently spread out on 11 files, so no way that anyone would bother to try to read it. Hopefully the below stuff is enough to address the problem.

A.h
Code: [Select]
class A {
    public:
        A(int);
        int GetA(int);
        ⁝
        ⁝
    private:
        static const char X[][];
        ⁝
        ⁝
};

A.cpp
Code: [Select]
#include "A.h"
const char A::X[][]={" N ","ENE"," NE","NNE",
                     " E ","ESE"," SE","SSE",
                     " S ","SSW"," SW","WSW",
                     " W ","WNW"," NW","NNW",
};
        ⁝
        ⁝

So how is this supposed to be done?
Kind regards

Johnny Rosenberg
ジョニー・ローゼンバーグ

AWOL

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.
I speak for myself, not Arduino.

johnwasser

I think you have to set aside room by specifying how long each of the sub-arrays is. If your longest string has three character and a null terminator you can use
Code: [Select]
X[][4]
 
Send Bitcoin tips to: 1G2qoGwMRXx8az71DVP1E81jShxtbSh5Hp

guraknugen

"ENE" Occupies four characters
Doesn't all of them occupy four characters each?
Kind regards

Johnny Rosenberg
ジョニー・ローゼンバーグ

AWOL

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.
I speak for myself, not Arduino.

guraknugen

I think you have to set aside room by specifying how long each of the sub-arrays is. If your longest string has three character and a null terminator you can use
Code: [Select]
X[][4]
 

Ah, that fixed it, thanks. Now I got another problem, though: How do I return such a string? I guess I have to return a pointer to the string, but I can't seem to get it right.
Code: [Select]
class A {
    public:
        A(int);
        char* GetX(int);
        ⁝
        ⁝
    private:
        static const char X[][];
        ⁝
        ⁝
};

Code: [Select]
char* A::GetX(int Something) {
        ⁝
        ⁝
    return X[SomeIndex];
}

Quote
invalid conversion from 'const char*' to 'char*' [-fpermissive]
     return X[SomeIndex];
Kind regards

Johnny Rosenberg
ジョニー・ローゼンバーグ

BulldogLowell

The hint lies in your error message

guraknugen

#7
Sep 13, 2017, 12:07 am Last Edit: Sep 13, 2017, 12:23 am by guraknugen
The hint lies in your error message
Yes, I realised that after trying a bit more. I thought that I tried that before and failed, but this time it worked, so obviously I didn't get it right the first time.
Code: [Select]
class A {
    public:
        A(int);
        const char * GetX(int);
        ⁝
        ⁝
    private:
        static const char X[][];
        ⁝
        ⁝
};

Code: [Select]
const char * A::GetX(int Something) {
        ⁝
        ⁝
    return X[SomeIndex];
}


Problem solved, thanks all!
Kind regards

Johnny Rosenberg
ジョニー・ローゼンバーグ

PaulMurrayCbr

Code: [Select]

const char A::X[][4]={" N ","ENE"," NE","NNE",
                     " E ","ESE"," SE","SSE",
                     " S ","SSW"," SW","WSW",
                     " W ","WNW"," NW","NNW",
};
http://paulmurraycbr.github.io/ArduinoTheOOWay.html

gfvalvo

Since your strings are constant, I'd use a single-dimension array of string pointers (char *).

It's a little odd that your array is a class variable (static), but the way you declare the GetX() method requires an instance of the class. But anyway:

A.h:

Code: [Select]
class A {
    public:
        const char *GetA(int);

    private:
        static const char *X[];
};


A.cpp:

Code: [Select]
#include "A.h"

const char * A::X[]={" N ","ENE"," NE","NNE",
                     " E ","ESE"," SE","SSE",
                     " S ","SSW"," SW","WSW",
                     " W ","WNW"," NW","NNW"
};

const char * A::GetA(int index) {
  return X[index];
}


.ino file:

Code: [Select]
#include "A.h"

A dog;
void setup() {
  uint8_t i;
  Serial.begin(115200);
  delay(1000);

  for (i=0; i<16; i++) {
    Serial.println(dog.GetA(i));
  }
}

void loop() {
}



guraknugen

It's a little odd that your array is a class variable (static), but the way you declare the GetX() method requires an instance of the class.
Why is it odd? Is odd bad? The array is used by that class' members only, shouldn't I place everything specific to that class within the class?

I'm only asking because I want to learn more about good and bad programming.
Kind regards

Johnny Rosenberg
ジョニー・ローゼンバーグ

gfvalvo

You made X[] private so only instances of the class can access it directly. That's good encapsulation.

You made X[] static so there is only one copy for the class rather than one per instances. Since it only contains constant strings, that's a good idea.

You created GetA() and made it public to provide access to X[] from the outside world. Again, good encapsulation.

But, you didn't make GetA() static. So that means there's one copy per instance rather than one for the whole class. Since it's accessing constant, static data, it would be more consistent to make GetA() static also as shown below.

A.h
Code: [Select]
class A {
    public:
        static const char *GetA(int);

    private:
        static const char *X[];
};


A.cpp
Code: [Select]
#include "A.h"

const char * A::X[]={" N ","ENE"," NE","NNE",
                     " E ","ESE"," SE","SSE",
                     " S ","SSW"," SW","WSW",
                     " W ","WNW"," NW","NNW"
};

const char * A::GetA(int index) {
  return X[index];
}


.ino file
Code: [Select]
#include "A.h"

void setup() {
  uint8_t i;
  Serial.begin(115200);
  delay(1000);

  for (i=0; i<16; i++) {
    Serial.println(A::GetA(i));
  }
}

void loop() {
}



The array is used by that class' members only
If that's the case, you don't need GetA() at all. Just access the elements of X[] directly from methods in the class instances.

guraknugen

If that's the case, you don't need GetA() at all. Just access the elements of X[] directly from methods in the class instances.
I simplified GetA to illustrate my problem. In my real project, there's some processing going on before returning a value based on that array and another one. My project is 11 files so far, I figured no one would bother to read them all, so I simplified as much as possible to focus on the problem only. The GetA method even has another (and longer) name… :)

Maybe I went too far with the simplifying this time.

Thank you for your input, I appreciate it very much!
Kind regards

Johnny Rosenberg
ジョニー・ローゼンバーグ

gfvalvo

#13
Sep 13, 2017, 02:34 pm Last Edit: Sep 13, 2017, 04:14 pm by gfvalvo
Makes sense. So, you have two decisions to make about GetA():

1. Does it always return the same value (for the same input arguments) regardless of which class instance calls it? If so, make it static. If not, keep it a member function.

2. Is it only called by class instances? If so, make it private. If not keep it public.

guraknugen

Makes sense. So, you have two decisions to make about GetA():

1. Does it always return the same value (for the same input arguments) regardless of which class instance calls it? If so, make it static. If not, keep it a member function.

2. Is it only called by class instances? If so, make it private. If not keep it public.

Thanks. I'm not sure I get the terminology though. If I make it static, isn't it still a member function?
Kind regards

Johnny Rosenberg
ジョニー・ローゼンバーグ

Go Up