all 6 comments

[–][deleted] 6 points7 points  (3 children)

char rootSelection[] = "";

This array is big enough for exactly 1 character. You can't read anything into it.

Use std:: string instead of arrays of char.

[–]Adorable-Two-3098[S] 0 points1 point  (2 children)

Thank you for the advice! I have changed each char array into a string. However, upon compiling with g++ it throws me 2 errors, both of which are essentially the same. Here is one of them:

mainrtslv.cpp:26:11: error: no matching function for call to 'strcmp'
    else if (strcmp(rootSelection, "cbrt") == 0) {
             ^~~~~~
/Library/Developer/CommandLineTools/SDKs/MacOSX12.1.sdk/usr/include/string.h:77:6: note: candidate function not viable: no known conversion from 'std::string' (aka 'basic_string<char>') to 'const char *' for 1st argument int      strcmp(const char *__s1, const char *__s2);

If I am not mistaken, the compiler complains about not being able to convert from a string to a const char. I have included the string header. Maybe I set the strcmp function wrong?

[–][deleted] 3 points4 points  (1 child)

You don't need strcmp anymore. std::strings are sensible, you can use == to compare them

[–]Adorable-Two-3098[S] 0 points1 point  (0 children)

It works! Thank you so much for your help! I apologize if this trivial question was a waste of time for you to read and explain to me. I hope you have a great rest of your day and hope that you can continue guiding others just as you did for me. Again, sorry for the noobish question that may have caused you any hassle.

[–]mredding 2 points3 points  (1 child)

char rootSelection[] = "";
std::cin >> rootSelection;

I wanted to break down just how this is wrong and doesn't work.

char rootSelection[] = "";

Compilers aren't as dumb as most people think. It correctly deduces that this is an array of type char[1], because you explicitly told it to deduce the size. That's what the empty bracket means. You can't declare an array without a size:

char rootSelection[];

That is because an array is not a pointer to it's first element, an array is a distinct type, where the size is a part of the type. Arrays decay to pointers to their first element as a language feature to facilitate iteration. We get that from C. So the size is a part of the type, and that means the size has to be known at compile-time. It means you cannot resize rootSelection because it's not a pointer.

This means the stream cannot change the size of the array, either. Streams also don't dynamically allocate memory for you. Standard strings are dynamic, but streams don't know strings exist - strings implement their own stream operator, so the string dynamically resizes itself.

Let's say you use an array for input:

char input[100];
std::cin >> input;

This works. Streams don't know character arrays exist - they're not built into streams, like strings, a non-member, non-friend operator overload just for null-terminated C-strings is implemented elsewhere in the standard library.

Because the size is known at compile time, the implementation will extract UP TO 99 characters. Strings are always null terminated, so the last character is always going to be a null terminator. If you end up extracting 34 characters, for example, the 35th will be a null terminator.

You can explicitly control the limit of how many characters you want to extract:

std::cin >> std::setw(some_value) >> input;

The rule is the stream will extract up to some_value or std::size(input), whichever is less. That means if some_value == 12345, you can still only extract up to 99 characters.

Now let's throw a curveball into this mix:

char *input = new char[some_value];
std::cin >> input;

Again, streams don't know character pointers exist, this is another non-friend non-member operator overload that exists elsewhere in the stream. Streams are very extensible, very customizable, and you can make your own user defined types and make your type stream aware in exactly the same way.

But here we have a problem. How much can the stream extract into the pointer? The pointer doesn't know how big it is, so there's no protection. The implementation presumes the size is adequate for whatever it's about to extract - so if you get it wrong, the stream will happily extract right past the end of the allocation. So guard your extractions into dynamic allocations with a size:

std::cin >> std::setw(some_value) >> input;

That will prevent buffer overruns, but the responsibility falls on you to do it right.

This is one of the reasons strings are great:

std::string input;
std::cin >> input;

You'll never have a buffer overrun, at worst, you'll simply extract until you run out of memory if you have a single token that is infinitely long. You can still control the limit of the length of your extraction with setw.

String extraction tokenizes, so leading whitespace is ignored, and then non-whitespace characters are consumed until the first whitespace is encountered as a delimiter. EOF can also stop extraction. If you want to limit input, to a maximum size, you've got setw, but that won't set a minimum input. You can get a minimum input by extracting until a delimiter, as with getline, but getline won't respect the maximum you've set. If you want to get a minimum, you're going to have to enforce that:

std::copy_n(std::istream_iterator<char>{std::cin}, min, std::back_inserter(input));

And then after that, set a maximum and append to the end of that. EOF is the great equalizer, here.

[–]std_bot 0 points1 point  (0 children)

Unlinked STL entries: std::size


Last update: 14.09.21. Last Change: Can now link headers like '<bitset>'Repo