Array initializer must be an initializer list error

I am completely new to C programming and the language I used to work on before C was Java. I am trying to get a method to return a char array and it is not working. Here is my syntax: char *

The rules of C says that you can’t initialize an array using a pointer. Instead define the array then copy to it:

char arr[strlen(val) + 1];  // Make sure there's enough space
strcpy(arr, val);

Then you can not define empty arrays. An array must have a size. And using the array newArr in the main function is wrong anyway since the function you call returns a pointer. So newArr must be a pointer as well.


Now with that out of the way, there are a couple of other things in your (current) code that are very wrong.

The first being the size of the array arr. An array of two characters can only hold space for one-character string. Remember that strings are null terminated, there must be space for the full string plus the terminator.

The second problem is that you return a pointer to a local variable. Once the function insertToArray returns, all its local variables cease to exist. Having a pointer to one of those variables will lead to undefined behavior when you use it.

The fix to the first problem is shown above. The fix to the second problem is a little harder, and involves either passing an extra argument to the function or allocating memory dynamically. I recommend the extra argument way:

char * insertToArray(const char * val, char * arr){
    strcpy(val, arr);

    // do some other staffs here to the value

    return arr;
}

Then call it like

char newArr[strlen(s1[i]) + 1];
insertToArray(s1[i], newArr);

First, when declaring a char array, you’ve to specify its size within the brackets like:

char arr[10];

except when you’re initializing it with a string literal.

And since we don’t know the number of characters the user will enter beforehand we may consider that GetString() takes care of that and returns a string (a char *). You may just declare a string and assign GetString() to it like that:

string s = GetString();

then access the contents of that string like you’d do with a char array. For example, if I wanna print out the first char in that string I may have something like this:

printf("%cn", s[0]);

Second, assuming you’re using a char array for any reason, you don’t have to cast the char you’re accessing to a char since it’s already a char! So considering this piece of code:

char arr[6] = {'h', 'e', 'l', 'l', 'o', ''};
printf("%cn", arr[0]); // no need to say (char) arr[0]

Lastly, you may print out the ciphered chars directly without storing them since we don’t need them after printing them out.

Edit: the error

array initializer must be an initializer list or string literal

means that when you declare an array, you have to initialize it using one of the following methods:

  1. char arr[6] = {'h', 'e', 'l', 'l', 'o', ''}; // initializer list
  2. char arr[6] = "hello"; // string literal

    char arr[] = "hello"; // also a string literal

A third way to initialize an array would be initializing its indices individually like that:

char arr[6];

arr[0] = 'h';
arr[1] = 'e';
arr[2] = 'l';
arr[3] = 'l';
arr[4] = 'o';
arr[5] = '';

Содержание

  1. Array Initializer Must Be an Initializer List or String Literal
  2. 3 Answers 3
  3. ошибка C3074: массив может быть инициализирован только списком инициализаторов
  4. Решение
  5. Другие решения
  6. Fixing std::initializer_list
  7. Problem 1): Uniform initialization
  8. Problem 2) A braced initializer has no type
  9. Problem 3): std::initializer_list access returns const T&
  10. Fixing the uniform initialization problem
  11. Fixing template deduction
  12. Allowing move semantics
  13. Allowing move semantics — take 2
  14. Conclusion

Array Initializer Must Be an Initializer List or String Literal

Given this array:

I get this error when compiling:

How to initialize this array properly?

3 Answers 3

First, when declaring a char array, you’ve to specify its size within the brackets like:

except when you’re initializing it with a string literal.

And since we don’t know the number of characters the user will enter beforehand we may consider that GetString() takes care of that and returns a string (a char * ). You may just declare a string and assign GetString() to it like that:

then access the contents of that string like you’d do with a char array. For example, if I wanna print out the first char in that string I may have something like this:

Second, assuming you’re using a char array for any reason, you don’t have to cast the char you’re accessing to a char since it’s already a char ! So considering this piece of code:

Lastly, you may print out the ciphered chars directly without storing them since we don’t need them after printing them out.

Edit: the error

array initializer must be an initializer list or string literal

means that when you declare an array, you have to initialize it using one of the following methods:

char arr[6] = «hello»; // string literal

char arr[] = «hello»; // also a string literal

A third way to initialize an array would be initializing its indices individually like that:

Источник

ошибка C3074: массив может быть инициализирован только списком инициализаторов

Я работаю над мелким (симпатичным) принтером для POD, STL и составных типов, таких как массивы. При этом я также возился со списками инициализации и наткнулся на следующее объявление

Кажется, что и VC2013, и G ++ 4.8 не совсем счастливы и выдают непротиворечивое сообщение об ошибке, которое в любом случае не очень полезно для меня

Для VC ++: error C3074: an array can only be initialized with an initialize-list

Для G ++ 4.8: error: array must be initialized with a brace-enclosed initialize

Так что или здесь нельзя использовать списки инициализации, или мой синтаксис совершенно неверный?

Похожий синтаксис следующий синтаксис

Какова возможная проблема с моим списком инициализации?

  • Заметка Я понимаю, что я должен использовать std::array вместо массивов типа С, но я просто экспериментирую.
  • Заметка Если вы не хотите поиграть с этим, вот IDEONE версия
  • Заметка Кроме того, было бы весьма полезно, если бы вы могли вернуть меня обратно к стандарту.

Решение

T
является
EmplaceConstructible
в
Икс
от
арг
для нуля или более аргументов
арг
, означает, что
следующее выражение правильно сформировано:
allocator_traits :: construct (m, p, args)

Так std::vector v< <1,2,3>, <4,5,6>>; действует, если double[3] является EmplaceConstructible от <1,2,3>как элемент списка инициализатора, передаваемого std::vector ,

Есть также пункт о прямых итераторах, но это не проблема (так как std::initialzier_list итераторы являются прямыми итераторами).

std::vector занимает std::initializer_list параметр.

Так std::initializer_list список кандидатов.

Первый, std::initializer_list x = <<1.0, 2.0, 3.0>>; не может скомпилировать в gcc. Но предположим, что это ошибка в gcc.

Во-вторых, ::new (nullptr) double[3](std::initializer_list <1.0, 2.0, 3.0>); размещение нового, которое EmplaceConstructable сводится к отсутствию подходящего construct переопределить, не компилируется.

Так double[3] не является EmplaceConstruble из std::initalizer_list ни из double[3] и ничего другого (поскольку ошибка возникает из-за того, что я использовал скобки, а не из-за того, что было в скобках, в месте размещения новых), если только распределитель не делает магию, о которой я не знаю, чтобы избежать размещения новых.

Таким образом, ваш код нарушает текущий черновой стандарт, и, вероятно, C ++ 11 и, конечно, C ++ 03 (который предъявляет более строгие требования к контейнерам).

Другие решения

Это ошибка в gcc и MSVC; Clang компилирует ваш код правильно.

Последние версии gcc на самом деле аварийно завершают работу («ice») компилятора:

внутренняя ошибка компилятора: проверка дерева: ожидаемый класс «type», имеет «исключительный» (error_mark) в useless_type_conversion_p, в tree-ssa.c: 1189

Стандарт достаточно ясен; от [Dcl.init.list]:

5 — объект типа std::initializer_list построен из списка инициализатора, как если бы реализация выделяла массив N элементы типа E , где N это количество элементов в списке инициализатора. Каждый элемент этого массива инициализируется копией с соответствующим элементом списка инициализатора, и std::initializer_list Объект создан для обращения к этому массиву. […]

Адаптируем пример из этого абзаца:

Это немного обманывает, хотя; более близкий перевод напишет E __a[2] = , E<20, 21, 22>>; , который не действителен. Но это конечно является можно копировать-инициализировать массив double[3] из списка фигурных скобок: E __a0 = <10, 11, 12>;

Источник

Fixing std::initializer_list

C++11 introduced std::initializer_list . This is a small class used if you want to initialize some container type with a pre-defined set of elements. It allows very convenient syntax just like plain old C arrays have.

Yet it has a couple of problems. This post will talk about them and how they can be fixed.

Throughout this post we’ll use the following class as an example:

I’m deliberately limiting the second interface to pointers, as there would be an ambiguity with the first constructor if we made it a template, so I’d needed some SFINAE there and explain that as well. But as I write this explanation I realize that the SFINAE explanation would have been shorter…

Only the constructors are relevant here. This is a simplified version of std::vector . It provides two main constructors: one to initialize it with a given size and one to initialize it with a pointer range.

If we want to create a vector of given size we’ll use it like so:

If we want to have the contents of some array, we’ll use it like so:

The beautiful syntax in the parameter is a reference to an array of given length. It should have been const but I don’t know where to put the const there and I’m too lazy to look it up. That’s why you shouldn’t use C arrays for anything more advanced.

But what if we want a vector containing the elements 1 , 2 and 3 ? We have to use an array as temporary storage:

That’s not very nice, so that’s why std::initializer_list was created. Simply add a new constructor:

And we can use it like so:

This allows the same syntax as with array initialization, std::initializer_list just provides a range defined by two random access iterators, so the constructor can be implemented just like the two pointer constructor.

So what’s the problem with std::initializer_list ?

There are a few:

Problem 1): Uniform initialization

Let’s first address the elephant in the room:

C++11 also added another feature — uniform initialization. Uniform initialization on its own is also really cool. It allows a single syntax to initialize everything, prevents most vexing parse and narrowing conversions.

But there are cases in C++ where two unrelated features enhance each other, where the combination is greater than the sum of its parts, where the features enhance each other and open many possibilities. And then there are uniform initialization and std::initializer_list .

The problem is: the new uniform initialization syntax is the same as the one for std::initializer_list ! Both uses < and >in a constructor. In particular, this conflicts with two of the 4 initializer list syntaxes above, namely vec2 and vec3 .

Let’s change the snippet so that we only have two elements:

The syntax for vec3 is the same as calling a constructor with uniform initialization syntax — and it just so happens that there is a constructor taking two integers: the count + value one. So does it call this one and initializes the vector with one 2 or does it call the initializer list constructor and initializes the vector with 1 and 2 ?

But there is a similar ambiguity for vec2 . Do we call the initializer list constructor or do we use uniform initialization to create a temporary my_vector from the count + value constructor and copy that?

The answer is: if there is a std::initializer_list constructor and it uses the brace syntax with some elements that can somehow be converted to T , it will use the initializer list constructor. If the conversion from an element to T is narrowing, it will still use the initializer list constructor but fail to compile.

This behavior can be used to create the infamous uniform initialization gotcha:

So simply switching everything to uniform initialization changes behavior! This means that uniform initialization is not uniform anymore, if there is a std::initializer_list one has to use parenthesis instead.

But the problems don’t end here.

Problem 2) A braced initializer has no type

Even though the core language has been amended for std::initializer_list , the expression <1, 2, 3, 4, 5>does not have the type std::initializer_list . So if you have a template function:

And you want to call it with an initializer list:

You’ll get an error. This makes generic make function more complicated, because that won’t compile:

If you want to support that, you have to do more work, i.e. creating an additional overload:

There are many cases throughout the standard library where this has to be done like std::optional’s in-place constructor.

And don’t get me started on the rules for auto deduction of braced initializers!

Problem 3): std::initializer_list access returns const T&

If you have a std::initializier_list constructor it has to copy the elements, it can’t move it because you’ll only get const T& elements. This means that you can’t use std::initializer_list for moveable elements, and even if you pass temporaries, it is less efficient than possible.

Fixing the uniform initialization problem

Important Update: The solution presented here sadly has issues. The temporary array created by the initializer list only lives as long as the list itself. As such, you must be really careful storing them as members as done here.

All problems can be solved by adding an extra layer of indirection — so can this problem.

The main problem with std::initializer_list is probably the quirks regarding uniform initialization. But this can be solved easily: add an extra layer of indirection, i.e. define your own initializer_list :

This is just a wrapper over std::initializer_list . But if we change the my_vector initializer list constructor so that it uses this type, this fixes the problem:

a will call the count + value constructor as usual. But b will also call it! This is because there is no constructor taking std::initializer_list , so the regular rules apply. c is actually a compilation error because it could either mean c(initializer_list<5, 0>) or c(my_vector<5, 0>) . Only d will use the initializer_list constructor, because due to the extra braces the std::initializer_list preference kicks in resolving the ambiguity.

Now we have an initializer list that is not greedy regarding uniform initialization. If you say the syntax with the double braces is ugly, no problem, this is still legal:

And that’s the syntax I’d want to use when initializing a container with elements — it’s the same as the array one.

You can’t use that syntax unfortunately.

Fixing template deduction

Our new initializer_list hasn’t changed the type of the expression <…>though, it still doesn’t work properly with generic functions. And there really isn’t something we can do about it as we cannot change the type of a literal.

Well, we can make a user-defined literal but there is no version for braced initializers. I recently saw discussion about it, basically allowing <…>_suffix , but it didn’t go much further.

Because we don’t have C++17’s class template argument deduction already, and initializer_list <12, 35, 53>is somewhat ugly we’re left with either a generic make function or extra work for the library implementer.

A make function could look like this:

The make_list() function itself just determines the value type for the list and returns it by using the std::initializer_list constructor of initializer_list .

The smart part here is determining the value type, I’ve leveraged that to std::initializer_list itself. The first detail::get_list_t overload when called with 0, deduces an argument for T and returns a T . If it is not possible to deduce a T (because of conflicting types), the second overload is selected — it has a less priority because it requires converting the int literal 0 to short , a common trick. Its second type is error , which can be created from any set of types, and it returns that.

Now we can just decltype() the return type of the selected function and static_assert() that it is not error.

Allowing move semantics

We still cannot use the initializer_list if we want to move things. While we could easily support a list where all the elements are rvalues, it is by design a homogeneous container and cannot store both lvalue references and rvalue references, so we would not be able to mix it.

We need a second layer of indirection to abstract that away.

So let’s make an initializer_list storing some wrapper over a T , which internally all store a pointer to T , but remembers whether it has been given an rvalue, so you can either call get() or get_rvalue() depending on that information in your code:

We would use it like so:

Then we change our initializer_list implementation so it stores a std::initializer_list > instead of T directly, and change the make_list() so that it wraps each argument in a wrapper.

This has no or even less overhead than using std::initializer_list directly and also allows move semantics.

Allowing move semantics — take 2

While the initializer_list using the wrapper works great, the compiler is not able to eliminate the conditional to check whether the current element is an lvalue or rvalue, even though that information is known at compile-time.

And even for std::initializer_list (and inlining) it can’t unroll the loop even though the number of elements is known at compile-time.

Luckily C++11 also added a feature to pass an arbitrary number of objects to a function: variadic templates. If you want a truly generic initializer list, use a variadic template and static_assert() or SFINAE that the type matches; you can even use the same syntax as for std::initializer_list thanks to uniform initialization.

Granted, the implementation is not a simple for loop but you might be able to do it with pack expansion. But the compiler is then able to fully optimize everything.

Conclusion

std::initializer_list does not work nicely with uniform initialization, template arguments or move semantics.

While we can fix all of those issues by simpling wrapping the std::initializer_list , wrapping each T and providing a generic make function, this is still not quite perfect.

However, writing a constructor accepting a variadic number of arguments allows the same syntax and completely bypasses these problems. So the next time you want a std::initializer_list constructor, consider writing one with a variadic number of arguments.

If you’ve liked this blog post, consider donating or otherwise supporting me.

This blog post was written for my old blog design and ported over. If there are any issues, please let me know.

Источник

ratatyq

3 / 3 / 1

Регистрация: 16.09.2015

Сообщений: 121

1

21.01.2016, 16:56. Показов 18653. Ответов 3

Метки нет (Все метки)


Вот собственно сама ошибка: «array must be initialized with a brace-enclosed initializer»
Сама программа должна выводить квадрат в консоль который нарисован в массиве
Код:
main.cpp

C++
1
2
3
4
5
6
7
8
9
10
#include <iostream>
#include "draw.h"
 
using namespace std;
 
int main() {
    Draw d;
    d.draw();
    return 0;
}

draw.cpp

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <cstring>
#include <iostream>
 
using namespace std;
 
class Draw {
private:
    string square[5][5][5][5] {
        {"*","*","*","*","*"},
        {"*"," "," "," ","*"},
        {"*"," "," "," ","*"},
        {"*","*","*","*","*"}
    };
public:
 
    void draw() {
        for(int x = 0; x < 5; x++)
            for(int x2 = 0; x2 < 5; x++)
                for(int x3 = 0; x3 < 5; x3++)
                    for(int x4 = 0; x4< 5; x++)
                        cout << square[x][x2][x3][x4];
    }
};

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь



0



Programming

Эксперт

94731 / 64177 / 26122

Регистрация: 12.04.2006

Сообщений: 116,782

21.01.2016, 16:56

3

Croessmah

Don’t worry, be happy

17781 / 10545 / 2036

Регистрация: 27.09.2012

Сообщений: 26,516

Записей в блоге: 1

21.01.2016, 17:12

2

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Draw {
private:
    string square[5][5] {
        {"*","*","*","*","*"},
        {"*","*","*","*","*"},
        {"*","*","*","*","*"},
        {"*","*","*","*","*"}
    };
public:
 
    void draw() {
        for(int x = 0; x < 5; x++){
            for(int x2 = 0; x2 < 5; x2++){
                cout << square[x][x2];
            }
            std::cout << std::endl ;
        }
    }
};



1



3 / 3 / 1

Регистрация: 16.09.2015

Сообщений: 121

21.01.2016, 17:56

 [ТС]

3

Croessmah, Спасибо помогло, вот только не пойму если мы сделали 4-ех значный массив то почему мы указали всего две скобки([][]) заместо четырех([][][][])?



0



0 / 0 / 0

Регистрация: 29.03.2019

Сообщений: 1

30.03.2019, 10:35

4

Массив двухзначный так-то был изначально



0



Я работаю над мелким (симпатичным) принтером для POD, STL и составных типов, таких как массивы. При этом я также возился со списками инициализации и наткнулся на следующее объявление

std::vector<double[3]> arr{ { 10, 11, 12 }, { 20, 21, 22 } };

Кажется, что и VC2013, и G ++ 4.8 не совсем счастливы и выдают непротиворечивое сообщение об ошибке, которое в любом случае не очень полезно для меня

Для VC ++: error C3074: an array can only be initialized with an initialize-list

Для G ++ 4.8: error: array must be initialized with a brace-enclosed initialize

Так что или здесь нельзя использовать списки инициализации, или мой синтаксис совершенно неверный?

Похожий синтаксис следующий синтаксис

std::vector<std::array<int, 3>>  arr{ { 10, 11, 12 }, { 20, 21, 22 } };

Какова возможная проблема с моим списком инициализации?

  • Заметка Я понимаю, что я должен использовать std::array вместо массивов типа С, но я просто экспериментирую.
  • Заметка Если вы не хотите поиграть с этим, вот IDEONE версия
  • Заметка Кроме того, было бы весьма полезно, если бы вы могли вернуть меня обратно к стандарту.

5

Решение

Чтение текущий проект стандарта C ++ 1y.

До таблицы 99:

T
является
EmplaceConstructible
в
Икс
от
арг
для нуля или более аргументов
арг
, означает, что
следующее выражение правильно сформировано:
allocator_traits :: construct (m, p, args)

Таблица 100:

X(il);              |  Equivalent to      | X(il.begin(), il.end());
--------------------+---------------------+--------------------------------
X(i, j);            |                     | Requires:
X a(i, j);          |                     | T shall be EmplaceConstructible
| into X from *i.

Так std::vector<double[3]> v{ {1,2,3}, {4,5,6} }; действует, если double[3] является EmplaceConstructible от {1,2,3} как элемент списка инициализатора, передаваемого std::vector<double[3]>,

Есть также пункт о прямых итераторах, но это не проблема (так как std::initialzier_list итераторы являются прямыми итераторами).

std::vector<T> занимает std::initializer_list<T> параметр.

Так std::initializer_list<double[3]> список кандидатов.

Первый, std::initializer_list<double[3]> x = {{1.0, 2.0, 3.0}}; не может скомпилировать в gcc. Но предположим, что это ошибка в gcc.

Во-вторых, ::new (nullptr) double[3](std::initializer_list<double>{1.0, 2.0, 3.0}); размещение нового, которое EmplaceConstructable сводится к отсутствию подходящего construct переопределить, не компилируется.

Так double[3] не является EmplaceConstruble из std::initalizer_list<double> ни из double[3] и ничего другого (поскольку ошибка возникает из-за того, что я использовал скобки, а не из-за того, что было в скобках, в месте размещения новых), если только распределитель не делает магию, о которой я не знаю, чтобы избежать размещения новых.

Таким образом, ваш код нарушает текущий черновой стандарт, и, вероятно, C ++ 11 и, конечно, C ++ 03 (который предъявляет более строгие требования к контейнерам).

5

Другие решения

Это ошибка в gcc и MSVC; Clang компилирует ваш код правильно.

Последние версии gcc на самом деле аварийно завершают работу («ice») компилятора:

внутренняя ошибка компилятора: проверка дерева: ожидаемый класс «type», имеет «исключительный» (error_mark) в useless_type_conversion_p, в tree-ssa.c: 1189

Стандарт достаточно ясен; от [Dcl.init.list]:

5 — объект типа std::initializer_list<E> построен из списка инициализатора, как если бы реализация выделяла массив N элементы типа E, где N это количество элементов в списке инициализатора. Каждый элемент этого массива инициализируется копией с соответствующим элементом списка инициализатора, и std::initializer_list<E> Объект создан для обращения к этому массиву. […]

Адаптируем пример из этого абзаца:

using E = double[3];
using X = std::vector<E>;
E __a[2] = {{10, 11, 12}, {20, 21, 22}};
X x(__a, __a+2);

Это немного обманывает, хотя; более близкий перевод напишет E __a[2] = {E{10, 11, 12}, E{20, 21, 22}};, который не действителен. Но это конечно является можно копировать-инициализировать массив double[3] из списка фигурных скобок: E __a0 = {10, 11, 12};

3

Я получаю следующую ошибку c++:

array must be initialized with a brace enclosed initializer 

из этой строки C++

int cipher[Array_size][Array_size];

в чем здесь проблема? Что означает ошибка? Ниже приведен полный код:

string decryption(string todecrypt)
{
    int cipher[Array_size][Array_size] = 0;
    string ciphercode = todecrypt.substr(0,3);
    todecrypt.erase(0,3);
    decodecipher(ciphercode,cipher);
    string decrypted = "";
    while(todecrypt.length()>0)
    {
        string unit_decrypt = todecrypt.substr(0,Array_size);
        todecrypt.erase(0,Array_size);
        int tomultiply[Array_size]=0;
        for(int i = 0; i < Array_size; i++)
        {
            tomultiply[i] = int(unit_encrypt.substr(0,1));
            unit_encrypt.erase(0,1);
        }
        for(int i = 0; i < Array_size; i++)
        {
            int resultchar = 0;
            for(int j = 0; j<Array_size; j++)
            {
                resultchar += tomultiply[j]*cipher[i][j]; 
            }
            decrypted += char((resultchar%229)-26);
        }
    }
    return decrypted;
}

3 ответов


синтаксис для статической инициализации массива использует фигурные скобки, например:

int array[10] = { 0 };

это приведет к нулевой инициализации массива.

для многомерных массивов вам нужны вложенные фигурные скобки, например:

int cipher[Array_size][Array_size]= { { 0 } };

отметим, что Array_size должна быть константой времени компиляции, чтобы это работало. Если Array_size не известно во время компиляции, необходимо использовать динамическую инициализацию. (Предпочтительно std::vector).


вы не можете инициализировать массив до «0», как это

int cipher[Array_size][Array_size]=0;

вы можете либо инициализировать все значения в массиве, как вы объявляете его следующим образом:

// When using different values
int a[3] = {10,20,30};

// When using the same value for all members
int a[3] = {0};

// When using same value for all members in a 2D array
int a[Array_size][Array_size] = { { 0 } };

или вам нужно инициализировать значения после объявления. Если вы хотите инициализировать все значения до 0, например, вы можете сделать что-то вроде:

for (int i = 0; i < Array_size; i++ ) {
    a[i] = 0;
}

вы не можете инициализировать массивы такой:

int cipher[Array_size][Array_size]=0;

синтаксис для 2D массивов:

int cipher[Array_size][Array_size]={{0}};

обратите внимание на фигурные скобки в правой части оператора инициализации.

для массивов 1D:

int tomultiply[Array_size]={0};

Понравилась статья? Поделить с друзьями:
  • Armoury crate asus ошибка установки
  • Armoury crate asus ошибка службы
  • Armory create ошибка установки 102
  • Armory create ошибка 2005
  • Armorstatushud как изменить расположение