Short answer: Because C and C++ are different languages with different rules.
Long answer: In both cases the reason is that the array is too small for the string literal. The literal consists of the five visible characters, with a zero terminator on the end, so the total size is 6.
In C, you’re allowed to initialise an array with a string that’s too long; extra characters are simply ignored:
C99 6.7.8/14: An array of character type may be initialized by a character string literal, optionally enclosed in braces. Successive characters of the character string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.
The compiler helpfully warns that the string is too large, since it almost certainly indicates an error; but it can’t reject the code unless you tell it to treat warnings as errors.
In C++, the initialiser isn’t allowed to be larger than the array:
C++11 8.5.2/2: There shall not be more initializers than there are array elements.
so, for that language, the compiler should give an error.
In both languages, when you want a character array to be the right size for a string literal initialiser, you can leave the size out and the compiler will do the right thing.
char a[] = "hello"; // size deduced to be 6
Aside from the missing commas in your set of initializers, why not just skip making it a 2-dimensional array of char
? You’re only passing the array data to strstr()
, and all it wants are null terminated strings. Why not use the more flexible:
char* array[] = {
"Becky Warre, 555-1223",
"Joe Looney, 555-0097",
"Geri Palmer, 555-8787",
"Lynn Presnell, 555-1212",
"Holly Gaddis, 555-8878",
"Sam Wiggins, 555-0998",
"Bob Kain, 555-8712",
"Tim Haynes, 555-7676",
"Warren Gaddis, 555-9037",
"Jean James, 555-4939",
"Ron Palmer, 555-2893",
NULL
};
Now that the array is just a set of pointers (and it’s terminated with a NULL pointer), the loop can look something like:
char *ptr = NULL;
int i;
for (i = 0; array[i] != NULL; i++)
{
ptr = strstr(array[i], search);
if (ptr != NULL)
cout << array[i];
}
One advantage of this is that you can add new strings to the data without having to update any corresponding ‘size’ numbers. And you’ll never have to worry about the compiler complaining that the array is too small in one dimension or another — it’ll just make the array the size it needs to be.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <ctime> using namespace std; const int n = 5; typedef struct { int day; int month; int year; } DATE; typedef struct { char naimenuv[20]; int cina; DATE datavir; int termin; int kilkist; char virobnyk[20]; }shop; bool repair(shop *pShop) //проверка на просроченность { time_t seconds; struct tm currdate = { 0 }; seconds = time(NULL); //время в секундах с 1.1.1970 года //сформируем структуру currdate с датой изготовления товара. Остальные поля = 0 (0 год соответствует 1900, месяц - с 0) currdate.tm_year = pShop->datavir.year-1900; currdate.tm_mon = pShop->datavir.month-1; currdate.tm_mday = pShop->datavir.day; //проверим время (в секундах): разность текущей и даты товара со сроком годности return (seconds - mktime(&currdate) > pShop->termin * 24 * 60 * 60); //true - товар просрочен } int main () { setlocale(0, "rus"); shop tovar[n] = { "Сосиски", 50, {20,10,2020}, 15, 130, "Завод Петровский", "Хлеб", 14, {19,10,2020}, 5, 150, "Хлебозавод", "Вафли", 25, {19,10,2020}, 30, 98, "Вафлезавод", "Растишка", 40, {21,10,2020}, 45, 73, "Молокозавод", "Баунти", 35, {20,10,2020}, 35, 31, "Завод кондитерский" }; cout << "***** Список товаров, срок годности которых менее 20-ти дней:" << endl; for (int i = 0; i < n; ++i) { if (tovar[i].termin < 20) { cout << tovar[i].naimenuv << " " << tovar[i].termin << endl; } } cout << endl << "***** Просроченные товары:" << endl; int count = 0; for (int i = 0; i < n; ++i) { if (repair(&tovar[i])) { count++; cout << tovar[i].naimenuv << " " << tovar[i].datavir.day << "." << tovar[i].datavir.month << " " << tovar[i].termin << endl; } } cout << "Всего: " << count << endl; |
This sketch does not compile in the Arduino IDE
void setup() {
// put your setup code here, to run once:
}
struct test {
int i;
char variable[];
};
typedef struct test test;
test t = {
0, "hi"
};
void loop() {
// put your main code here, to run repeatedly:
}
Arduino throws
sketch_may09a:16: error: initializer-string for array of chars is too long [-fpermissive]
};
^
exit status 1
initializer-string for array of chars is too long [-fpermissive]
However compiling with g++ works just fine. How can I fix it? Or is there a principle reason why flexible array members are not supported?
Glorfindel
5741 gold badge7 silver badges18 bronze badges
asked May 9, 2019 at 19:31
4
Flexible array member is a C feature. It does not exist in C++. On top of that, the way you use it to declare and initialize a static struct of flexible size is non-standard even for C.
However, GNU-C language supports it as an extension. Also, newer versions of GCC (6 and higher) allow this in GNU-C++ code as an extension as well. But GCC 5.4.0 used by Arduino IDE doesn’t support this non-standard feature in C++ code.
If you flip through different GCC versions on Godbolt (https://godbolt.org/z/Iul7hD) you’ll see that support for this feature has always been present in C code, but for C++ code it first appeared in GCC 6.
This is why you were able to compile it with your standalone g++
compiler (which is apparently a much later version), but were unable to compile it in Arduino IDE.
It means that if you really want this non-standard code to compile in the current version of Arduino IDE, you have to place it into a .c
file. Or just specify the array size explicitly.
answered May 9, 2019 at 19:56
2
Maybe you’ve compiled it in g++ without any warnings enabled (or maybe it yeld warnings but was compiled). The arduino uses flags to consider all warnings as an error, so it won’t compile. It may wary for different platforms, I’ve got -fpermissive used (and I don’t like it at all).
That’s because size of struct must be known compile time and if you provide char variable[];
you’ll get zero sized array. Therefore anything biiger than nothing you’ll try to initialize for is too long.
Maybe you’re looking for something like this:
struct test {
int a;
const char * ptr;
};
test paramx {1, "some string"};
test paramy {2, "another string"};
test array[] = {{3,"three"}, {4, "four"}, {5,"five"}};
answered May 9, 2019 at 19:52
KIIVKIIV
4,4571 gold badge11 silver badges21 bronze badges
7
- Forum
- Beginners
- Initializer string is too long
Initializer string is too long
Whenever I attempt to compile this code I get the error «initializer-string for array of chars is too long». Any help is greatly appreciated.
|
|
Each string literal has additional character — terminating zero. So your array shall be declared as
char Map[10][11];
because it is initialized by string literal «##########» that has in total 11 characters (including the terminating zero).
Last edited on
"##########"
doesn’t contain 10 characters. It contains 11.
There’s a hidden
»
character added to the end, so it actually looks like this:
{'#', '#', '#', '#', '#', '#', '#', '#', '#', '#', ''}
»
is called the NUL character, and it’s used as a hint where the array ends.
Thank you for the help vlad and Catfish
Last edited on
Topic archived. No new replies allowed.