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; |
Следующая программа прекрасно компилируется в C с предупреждениями, но не компилируется в C ++. Зачем? Какова причина?
#include <stdio.h>
int main(void)
{
char a[5]="Hello";
a[0]='y';
puts(a);
for(int i=0;i<5;i++)
printf("%c",a[i]);
return 0;
}
Предупреждение:
Warning:[Error] initializer-string for array of chars is too long [-fpermissive] enabled by default
Но если программа скомпилирована как программа C ++, то компилятор C ++ выдает следующую ошибку:
[Error] initializer-string for array of chars is too long [-fpermissive]
Я использую компилятор GCC 4.8.1.
5
Решение
Краткий ответ: потому что C и C ++ — это разные языки с разными правилами.
Длинный ответ: в обоих случаях причина в том, что массив слишком мал для строкового литерала. Литерал состоит из пяти видимых символов с нулевым терминатором на конце, поэтому общий размер равен 6.
В C вы можете инициализировать массив слишком длинной строкой; лишние символы просто игнорируются:
C99 6.7.8 / 14: Массив символьного типа может быть инициализирован литералом символьной строки, необязательно заключенным в фигурные скобки. Последовательные символы литерала символьной строки (включая завершающий нулевой символ, если есть место или если массив имеет неизвестный размер) инициализируют элементы массива.
Компилятор предупреждает, что строка слишком велика, поскольку почти наверняка указывает на ошибку; но он не может отклонить код, если вы не скажете, чтобы он воспринимал предупреждения как ошибки.
В C ++ инициализатору не разрешено быть больше, чем массив:
C ++ 11 8.5.2 / 2: Инициализаторов не должно быть больше, чем элементов массива.
поэтому для этого языка компилятор должен выдать ошибку.
В обоих языках, когда вы хотите, чтобы символьный массив соответствовал размеру инициализатора строкового литерала, вы можете не указывать размер, и компилятор сделает все правильно.
char a[] = "hello"; // size deduced to be 6
22
Другие решения
Проблема в нижней строке
char a[5]="Hello";
Нет места для хранения завершающего нуля.
По умолчанию, gcc
не выдает никаких ошибок для этого случая с -fpermissive
опция включена. Так что компилирует нормально в C
,
Согласно требованию от языковых стандартов,
- За
C99
стандарт, глава 6.7.9, пункт 14,
Массив символьного типа может быть инициализирован символьным строковым литералом или строковым литералом UTF-8, необязательно заключенным в фигурные скобки. Последовательные байты строкового литерала (включая завершающий нулевой символ, если есть место или массив имеет неизвестный размер) инициализируют элементы массива.
- За
C++11
, глава 8.5.2, пункт 2
Инициализаторов не должно быть больше, чем элементов массива.
Итак, код компилируется (с предупреждениями) с gcc
, выдает ошибку с g++
,
10
Допустимая строка в C и C ++ должна иметь терминатор и в
char a[5]="Hello";
Там нет места для нулевого терминатора и не является допустимой строкой.
Так что это может не быть ошибкой в C, но вы обязательно столкнетесь с проблемами при использовании встроенных строковых функций, таких как strlen()
и семья.
5
Потому что «Привет» 6 char
с долго и г ++ без -fpermissive
не будет инициализировать 5 char
массив с ним, но GCC будет.
3
- 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.