0

When I want to give an input from user as string, then insert each char into a new list, I use the commands below:

#include <iostream>
#include <string>
#include <cstring>

using  namespace  std;

int main()
{
    string text;
    cout<<"Text: ";
    cin>>text;

    int len = text.length();
    char char_list[len + 1];

    strcpy(char_list, text.c_str());

    cout << char_list << endl;
    return 0;
}

In the code above why we use char char_list[len + 1];? If I don't use +1, I see the same results.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 4
    `char char_list[len + 1];` -- This is not valid C++ code. Arrays in C++ must have their sizes denoted by a compile-time expression, not a runtime value. Dynamic arrays in C++ are accomplished by using `std::vector`. – PaulMcKenzie May 02 '20 at 10:23
  • @PaulMcKenzie I apologize, I don't understand. Why is not valid? I got the result I needed. –  May 02 '20 at 10:32
  • @Thomas Sablik What is C strings? I am so newbe. –  May 02 '20 at 10:33
  • 1
    Variable-length arrays are not supported by C++. You are using a compiler extension. Your code won't compile on most compilers. AFAIK only GCC and Clang support it. E.g. MSVC doesn't support it. A C string is a [Null-terminated byte string](https://en.cppreference.com/w/cpp/string/byte) – Thomas Sablik May 02 '20 at 10:35
  • Try your code on Visual C++. Your code will not compile. So you have some good news -- there is no need to figure out that line of code, because it is fake C++. Change that line to `std::vector char_list(len + 1);`, and then you can start the thinking process over again. – PaulMcKenzie May 02 '20 at 10:36
  • @PaulMcKenzie Fake, what do you mean? I am using MinGW. –  May 02 '20 at 10:37
  • @Thomas Sablik How can I figure it out, if I am using a compiler extension or not in the future? –  May 02 '20 at 10:38
  • It is fake because that's what it is. It is not real C++. – PaulMcKenzie May 02 '20 at 10:39
  • This is not valid C++ code. Only GCC (mingw) and Clang understand your code. You can add the compiler flag `-pedantic` or `-pedantic-error`: https://wandbox.org/permlink/GQdQPVmu8BiLmWr3 – Thomas Sablik May 02 '20 at 10:39
  • @PaulMcKenzie What is real C++? Code::Blocks or something? –  May 02 '20 at 10:39
  • @Thomas Sablik What should I use, any suggestions? –  May 02 '20 at 10:40
  • Real C++ is what is described in the C++ ANSI/ISO standard. Variable Length Arrays are *not* part of C++. Instead you are using a compiler that allows such syntax. This is why I wished that g++ would turn **off** that syntax, and only allow it to exist using a special compiler option. Otherwise, g++ is creating more unwary programmers like yourself, believing that the syntax is actually C++ when it isn't. – PaulMcKenzie May 02 '20 at 10:42
  • You should add the compiler flags `-Wall`, `-Wextra` and `-pedantic` or `-pedantic-error` to all your GCC or Clang projects. See this example https://wandbox.org/permlink/GQdQPVmu8BiLmWr3 – Thomas Sablik May 02 '20 at 10:42
  • @PaulMcKenzie So what I understand is even I use a fake C++ command I can create sucessfully an `.exe` file and use it. Even my compiler allows me to do this and others' is not, the .exe file can do the same thing. –  May 02 '20 at 10:46
  • @SerhatÇelik `Why is not valid? I got the result I needed.` To get the expected result in c++ does not mean that the code is logically correct. It could just be undefined behavior. – t.niese May 02 '20 at 10:48
  • Use the flags that @ThomasSablik mentioned when compiling your code. And again, try your code on Visual Studio, where it will not compile. That's the point we're trying to get across to you. C++ has a set of rules, and those rules are described by ANSI/ISO. You are using a compiler that breaks those rules and allows you to use that syntax. – PaulMcKenzie May 02 '20 at 10:49
  • There is a difference between variable-length arrays in GCC/Clang and vectors in C++. The memory for variable-length arrays is allocated on the stack and the dynamic memory for vectors is allocated on the heap. The stack is much smaller than the heap. – Thomas Sablik May 02 '20 at 10:49
  • I see things more clear now :) Thank you, all of you. I understand the importance of this flags. In addition to that, is it possible a way to add these flags to IDEs like Code::Blocks like VisualStudio? –  May 02 '20 at 10:53
  • 1
    Yes, you can add these flags in all IDEs I've seen so far. You have to look in the project settings. Some IDEs have a checkbox to enable standard flags, other IDEs have input fields where you can enter flags as text. But VisualStudio uses MSVC instead of GCC. The flags are different and variable-length arrays can't be used. – Thomas Sablik May 02 '20 at 11:35

2 Answers2

2

C strings use arrays of characters with an additional special null character to indicate the end of the string. This is called the null terminator, and it goes after the other characters in the string. So in your code char_list is a C string. This is the only kind of string that the C language has.

The special null character in a C string is the reason you need to have len + 1. The +1 is to make enough room for the null character.

In C++ there is a std::string class to represent strings so text is a C++ string. But C++ can also work with C strings. In general in a C++ program you should prefer C++ strings.

It's a important fact in C++ programming is that just because your code works doesn't not mean it is correct. So even though it worked for you this time to leave out the +1 it may not work next time. The technical term for this is undefined behaviour, because you left out the +1 your program had undefined behaviour. Undefined behaviour means that anything can happen, even working counts as undefined behaviour, but so does crashing, or giving the wrong results.

john
  • 85,011
  • 4
  • 57
  • 81
1

For starters variable length arrays like char_list

int len = text.length();
char char_list[len + 1];

is not a standard C++ feature. The code will no compile if to use a C++ compiler that does not have its own language extension that allows to use variable length arrays.

In such a case you should dynamically allocate the array

int len = text.length();
char *char_list = new char[len + 1];

also it is a bad idea to use the signed type int to store an object of the unsigned integer type std::string::size_type that in general can be too large to be stored in an object of the type int

You could just write using the specifier auto

auto len = text.length();
char *char_list = new char[len + 1];

Nevertheless, the used C string function strcpy copies characters from source character array in destination character array until the terminating zero character '\0' will not be copied. That is the terminating zero character '\0' plays role of a sentinel value that is stored in a string along with other characters.

The same way behaves the overloaded operator << when its argument has the type char *.

Without reserving the additional byte for the terminating zero in the character array your program has undefined behavior though it provides for such a simple program the expected result.

You could copy the source object of the type std::string excluding the terminating zero the following way using another string function strncpy or memcpy

int len = text.length();
char char_list[len];

memcpy(char_list, text.c_str(), len );

But in this case you may not use the operator <<. Instead you may write

cout.write( char_list, len ) << endl;
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335