Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which of these new expressions with char arrays are well-formed?

For the following program:

int main() 
{
    new char[4] {"text"};  // #1
    new char[5] {"text"};  // #2
    new char[] {"text"};   // #3
}

clang gives an error for #1 which says:

error: initializer-string for char array is too long

and accepts #2 and #3.

gcc gives the following error for all statements:

error: invalid conversion from 'const char*' to 'char' [-fpermissive]

and in addition for #3 it gives the error:

error: expected primary-expression before ']' token

So what does the language say about whether this code is well-formed?

I want to know the current rules, but I'd also be interested to know if this has this changed in previous versions of the language.

like image 501
cigien Avatar asked Aug 23 '20 19:08

cigien


People also ask

What is the type of a char array?

A character array is a sequence of characters, just as a numeric array is a sequence of numbers. A typical use is to store a short piece of text as a row of characters in a character vector.

What is a char * array in C?

In C, an array of type char is used to represent a character string, the end of which is marked by a byte set to 0 (also known as a NUL character)

How do you initialize a new char array?

Initializing Char Array A char array can be initialized by conferring to it a default size. char [] JavaCharArray = new char [ 4 ]; This assigns to it an instance with size 4.

What is special about the array of char?

Char array or array of char is used to print or display the sequence of characters or numbers. With the help of a character array, we can store the variable in a memory to a correspondence memory address.

What is char ARY[] in C programming?

char ary []="Hello..!"; A) Character array, ary is a string. D) String can not contain special characters. It is a simple way of creating a C String. You can also define it like the below. \0 is mandatory in this version. char ary [] = {'h','e','l','l','o','\0'};

Which is essential to specify when initializing an array?

4. On the point of array initialization which is required to specify? Row is essential to specify when initializing an array. Example: 5. Which declaration is valid ? As a result, option (A) and option (C) are wrong as parentheses ( ) is used in place of square brackets [ ].

What is an array?

All of the above. Arrays are data structures that may consist of data items of different types. Arrays are data structures consisting of data items of the same type. Nice work! You just studied 25 terms! Now up your study game with Learn mode. Arrays may have __________ dimensions. All of the above.

When values are provided upon declaration of an array the new keyword?

When values are provided upon declaration of an array, the new keyword is not required. Values in an array can be totaled by using the ArrayTotal method. False. If the values of an array need to be totaled, a repetition statement may be used to traverse the array and add up each element.


2 Answers

OK, this is pretty simple to trace. The presence of {} means that list initialization is being performed, so we get to visit our favorite part of the spec: [dcl.init.list]/3.

The object being initialized in case 1 is a char[4]. The braced-init-list is not a designated initializer, so 3.1 is ignored. char[4] is not a class, so 3.2 is ignored. That brings us to 3.3:

Otherwise, if T is a character array and the initializer list has a single element that is an appropriately-typed string-literal ([dcl.init.string]), initialization is performed as described in that subclause.

Well, char[4] is definitely a character array, and the initializer list definitely contains a single element, and that element does in fact match the type of the character array. So off to [dcl.init.string] we go.

That tells us (after a fashion):

Successive characters of the value of the string-literal initialize the elements of the array.

But the next paragraph warns:

There shall not be more initializers than there are array elements.

Well, that makes #1 ill-formed.

So, we redo the process for char[5]. And that doesn't trigger, since 5 is sufficiently large.

Lastly, we come to char[]. Which is no different from using a number, as far as initialization is concerned. char[] is an array of characters, so it follows the above rules. C++17 would choke on using char[] in a new expression, but C++20 is fine with it.

If the type-id or new-type-id denotes an array type of unknown bound ([dcl.array]), the new-initializer shall not be omitted; the allocated object is an array with n elements, where n is determined from the number of initial elements supplied in the new-initializer ([dcl.init.aggr], [dcl.init.string]).

Which means that #2 and #3 are supposed to be legal. So GCC is wrong to make them ill-formed. And it makes #1 ill-formed for the wrong reason.

like image 144
Nicol Bolas Avatar answered Oct 23 '22 14:10

Nicol Bolas


Clang is correct in that #1 is ill-formed and #2 is okay.

As Ted Lyngmo noted in a comment, #3 was invalid by the C++ grammar rules, until paper P1009R2 made a change to allow it. A new-expression simply did not allow the possiblity of empty [] in the type, left over from when there was no syntax to initialize the array created by a new-expression, and therefore no way for a compiler to determine the actual size. The paper's changes are accepted in C++20 (but compiler writers will sometimes choose to support "fixes" retroactively in previous -std= modes).

For the difference between #1 and #2, the initialization of the array object is specified in [expr.new] to follow the direct-initialization rules of [dcl.init]. The general rules for initialization in [dcl.init] early on say if the initializer is a braced-init_list, it is list-initialization. The rules for this in [dcl.init.list] go like:

List-initialization of an object or reference of type T is defined as follows:

  • [C++20 only:] If the braced-init-list contains a designated-initializer-list, ...

  • If T is an aggregate class and...

  • Otherwise, if T is a character array and the initializer list has a single element that is an appropriately-typed string-literal ([dcl.init.string]), initialization is performed as described in that subclause.

  • ...

And so [dcl.init.string] (C++17, latest) gives the actual initialization rules which apply to this code:

An array of {C++17: narrow character type}{C++20: ordinary character type ([basic.fundamental])}, char8_­t array, char16_­t array, char32_­t array, or wchar_­t array can be initialized by {C++17: a narrow}{C++20: an ordinary} string literal, UTF-8 string literal, UTF-16 string literal, UTF-32 string literal, or wide string literal, respectively, or by an appropriately-typed string-literal enclosed in braces ([lex.string]). Successive characters of the value of the string-literal initialize the elements of the array.

There shall not be more initializers than there are array elements. [ Example:

char cv[4] = "asdf";            // error

is ill-formed since there is no space for the implied trailing '\0'. — end example ]

If there are fewer initializers than there are array elements, each element not explicitly initialized shall be zero-initialized ([dcl.init]).

Just like the plain variable definition, when the character array type of a new-expression has a specified bound, it must be large enough for all the characters of a string literal initializing it, including the trailing null character.

(This is an old difference between C and C++: C does allow char cv[4] = "asdf"; and ignores the null character.)

like image 27
aschepler Avatar answered Oct 23 '22 15:10

aschepler