Firstly I'm going to be the one to mention the obligatory "using namespace std; is bad".
If you want to be lazy and avoid having to use std:: everywhere, put using namespace std; as the first line of your function (i.e. main).
If you want to be somewhat lazy but also much safer then you can use using to only include the things you are using (and again, declare it within your function so it's local).
e.g.
int main()
{
using std::array;
using std::cout;
// The rest of your code
}
You stated the input would be in ASCII yet you have defined an array of 255 characters. ASCII only has 128 characters.
From Wikipedia:
Originally based on the English alphabet, ASCII encodes 128 specified
characters into seven-bit integers
Rather than using a C-style const char * it would be better to use a std::string.
You are using an array of char as if it were an array of bool.
This is C++, not C - if you want to represent a truth value use bool,true and false, not char,1 and 0.
Your variable names ought to be more representative of the object's function. arr tells me nothing about the purpose of the array, foundCharacters on the otherhand is perfectly self-documenting.
You are not using i outside of the while loop, so your while should be a for.
You really ought to be doing this is a separate function instead of squashing it all into main.
And you may or may not want to use exceptions.
Some people avoid them because of concerns about overhead or because they're using embedded systems.
Lastly There is a special case in which you can return early.
As you are assuming ASCII as the input encoding, you can return false on cases where the string is longer than the number of possibly valid unique ASCII characters (which is 128). This will also prevent the buffer overrun problem mentioned by @jvb.
Since you are using C style null-terminated const char * instead of C++ style std::string, you can also ignore the null character.
Edit:
As per a suggestion by @Tony Speight, it's possible to use a range-based for loop since the variable i is only being used to iterate the input string.
Applying these changes leaves us with:
#include <iostream>
#include <array>
#include <exception>
#include <string>
bool hasUniqueChars(const std::string & string)
{
using std::array;
using std::domain_error;
if (string.size() > 128)
{
return false;
}
// using @zett42's suggestion
array<bool, 128> foundCharacters{};
// using @Tony Speight's suggestion
for (const auto c: string)
{
// char may be signed or unsigned so check both possibilities
if (c < 0 || c > 127)
{
// Character is outside the ascii range
throw domain_error("string had a non-ascii character");
// return false; if you don't want to use exceptions
}
else
{
// at is just a precaution as we have already assured c >= 0 and c <= 127
if (foundCharacters.at(c))
{
return false;
}
else
{
foundCharacters.at(c) = true;
}
}
}
return true;
}
int main()
{
using std::string;
using std::cout;
using std::domain_error;
using std::out_of_range;
const string input = "ABCADEFGHIJKL";
try
{
cout << (hasUniqueChars(input) ? "Unique" : "Not Unique") << '\n';
}
catch (const domain_error & error)
{
cout << "Invalid input\n";
cout << error.what();
}
catch (const out_of_range & error)
{
cout << "Invalid input\n";
cout << error.what();
}
return 0;
}
Note that your 'indexing an array' solution is not viable for larger character sets, in which case @Jerry_Coffin and @Mercury Dime's suggestion of using std::set is a very good one.
Also to make better use of space, a std::bitset would have been better than a std::array.