I recently had an assignment that asked us to restrict the amount of characters a user can enter for his or her name. My professor said this is useful in the event that your program is being "attacked." The simplest solution was to use C strings:

#include <iostream>

const int MAX_NAME_SIZE = 15;

int main () {
	char name[MAX_NAME_SIZE];
	std::cin.getline(name, MAX_NAME_SIZE);
	
	std::cout << name << std::endl;
	return 0;
}

However, I wanted to use C++ strings instead. Unfortunately this requires some unorthodox (to me at least) methods:

#include <iostream>
#include <string>

const int MAX_NAME_SIZE = 15;

int main () {
	std::string name(' ', MAX_NAME_SIZE);
	name.reserve(MAX_NAME_SIZE);
	std::cin.getline(const_cast<char *>(name.data()), MAX_NAME_SIZE);
	
        // optionally you could use the gcount function here to downsize the string

	std::cout << name << std::endl;
	return 0;
}

So my questions are:

  • Why was the functionality of the istream getline not included in the string getline ?
  • Is there another, preferably better, way of doing this with C++ strings?
  • Is there another, once again better, way of doing this at all?
  • Since the input buffer is pretty big, does it really slow the program down that much to prevent you from just using the resize() member function?

Any side comments are welcome.

Thanks,
Arkinder

std::cin.getline(const_cast<char *>(name.data()), MAX_NAME_SIZE); is undefined behavior because you are not allowed to modified the pointer-to-const-char returned by data.

You could easily just use the c-style approach and convert that into a string. Or you can do something like so.

string str(' ',MAX_SIZE);
cin.getline( &(str[0]) , str.size() );

> My professor said this is useful in the event that your program is being "attacked."

Useful, only if you are using C-style arrays of char.

Don't create a problem that did not exist in the first place, and then try to solve it; just use std::string instead. std::string is not vulnerable to buffer overflow exploits on user input; if you use the member function at() instead of [] for element access, it is safe even if there are programming errors. Unless you decide to use its buffer as a C-style array of modifiable chars, in which case you deserve to be subject to every bad thing that could possibly happen.

The second problem with restricting the number of characters that can be entered is that if the input is too long, crud is left in the stream buffer which has to be than read and discarded prior to the next input. Just reading in whatever is entered, and then truncating the string if it turns out to be too long is simpler.

Something like:

std::string name ;
    constexpr std::string::size_type MAX_CHARS = 20 ;

    if( std::cout << "name (max " << MAX_CHARS << " chars)? " && std::getline( std::cin, name  ) )
    {
        if( name.size() > MAX_CHARS )
        {
            std::cerr << name << " is too long; truncating it\n" ;
            name = name.substr( 0, MAX_CHARS ) ;
        }
        // use name
    }

    // else i/o error

std::cin.getline(const_cast<char *>(name.data()), MAX_NAME_SIZE); is undefined behavior because you are not allowed to modified the pointer-to-const-char returned by data.

You could easily just use the c-style approach and convert that into a string. Or you can do something like so.

string str(' ',MAX_SIZE);
cin.getline( &(str[0]) , str.size() );

I am aware that it is undefined behavior, that is why I said it was unorthodox. Regardless, this still is not a complete solution.

Thanks anyways,
Arkinder

> My professor said this is useful in the event that your program is being "attacked."

Useful, only if you are using C-style arrays of char.

Don't create a problem that did not exist in the first place, and then try to solve it; just use std::string instead. std::string is not vulnerable to buffer overflow exploits on user input; if you use the member function at() instead of [] for element access, it is safe even if there are programming errors. Unless you decide to use its buffer as a C-style array of modifiable chars, in which case you deserve to be subject to every bad thing that could possibly happen.

The second problem with restricting the number of characters that can be entered is that if the input is too long, crud is left in the stream buffer which has to be than read and discarded prior to the next input. Just reading in whatever is entered, and then truncating the string if it turns out to be too long is simpler.

Something like:

std::string name ;
    constexpr std::string::size_type MAX_CHARS = 20 ;

    if( std::cout << "name (max " << MAX_CHARS << " chars)? " && std::getline( std::cin, name  ) )
    {
        if( name.size() > MAX_CHARS )
        {
            std::cerr << name << " is too long; truncating it\n" ;
            name = name.substr( 0, MAX_CHARS ) ;
        }
        // use name
    }

    // else i/o error

This is interesting, and I never would have thought of doing it this way - thanks.

Regards,
Arkinder

This question has already been answered. Start a new discussion instead.