str::find() function for the const char* - c++

const char *attribute[] =
{"abc","efg","hij","lmn","opq","rst","uvw","Xyz"};
want to find Boolean and location of the "lmn" in the above array.

This example will show you how to get both a bool and an index back.
Demo here : https://onlinegdb.com/vHHJ9QG1M
#include <array>
#include <limits>
#include <algorithm>
#include <iostream>
#include <string_view>
// make a struct to be able to return two (readable) values from function
// I almost never use std::pair it results in hard to read code.
// where you have to check the semantics of first/second over and over again.
struct is_attribute_result_t
{
// conversion to bool so result can be directly used in "if's"
constexpr operator bool() const
{
return is_attribute;
}
bool is_attribute{false};
std::size_t index{std::numeric_limits<std::size_t>::max()};
};
// make a std::array that is usable at compile time
// use string_view because it implements operator== for the whole string (const char* doesn't)
constexpr std::array<std::string_view,8> attributes = {"abc","efg","hij","lmn","opq","rst","uvw","xyz"};
// make a function that can be evaluated at compile time
// so no std::find, just use availability of (constexpr) operator== on string_view
constexpr is_attribute_result_t test_attribute(const std::string_view& attribute)
{
is_attribute_result_t result;
for(std::size_t n = 0; n < attributes.size(); ++n)
{
if(attribute == attributes[n])
{
result.is_attribute = true;
result.index = n;
return result;
}
}
return result;
}
int main()
{
// nice thing is you can now also check at compile time.
static_assert(test_attribute("abc"));
static_assert(test_attribute("abc").index == 0ul);
static_assert(test_attribute("lmn"));
static_assert(test_attribute("lmn").index == 3ul);
static_assert(!test_attribute("123"));
// and ofcourse still use the function at runtime too
if ( auto result = test_attribute("lmn"))
{
std::cout << "lmn is an attribute, and is found at index = " << result.index << "\n";
}
return 0;
}

Related

My code is right but not accepted by Leetcode platoform. (ZigZag Conversion)

It is a leet code problem under the subcategory of string, medium problem.
Query: My program is returning right result for all the test cases at the run time and but when I submit, same test cases are not passing.
I also made a video, click here to watch.
My Code is:
string convert(string s, int numRows) {
int loc_rows = numRows-2;
int i=0;
int a=0,b=0;
int arr[1000][1000];
while(i<s.length())
{
if(a<numRows)
{
arr[a][b] = s[i];
a++;
i++;
}
else if(a>=numRows)
{
if(loc_rows>=1)
{
b++;
arr[loc_rows][b]=s[i];
i++;
loc_rows--;
}
else{
loc_rows=numRows-2;
b++;
a=0;
}
}
}
string result="";
for(int d=0;d<numRows;d++)
{
for(int y=0;y<b+1;y++)
{
char temp = (char)arr[d][y];
if((temp>='a' and temp<='z') or (temp>='A' and temp<='Z') )
result+=temp;
}
}
return result;
}
I believe the issue might be your un-initialised arrays / variables.
Try setting initialising your array: int arr[1000][1000] = {0};
live example failing: https://godbolt.org/z/dxf13P
live example passing: https://godbolt.org/z/8vYEv6
You can't rely on the data that is in these arrays so initialising the values is quite important.
Note: this is because you rely on the empty values in the array to be not a letter ([a-zA-Z]). So that you can re-construct your output with your final loop which attempts to print the characters only. This works the first time around because luckily arr contains 0's in the gaps between your values (or at least not letters). The second time around it contains some junk from the first time around (really - you don't know what this is going to be, but in practise it is probably just the values you left in there from last time). So even though you put in the correct values into arr each time - your final loop finds some of the old non-alpha values in the array - hence your program is incorrect...
Alternatively, we could also use unsigned int to make it just a bit more efficient:
// The following block might slightly improve the execution time;
// Can be removed;
static const auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(NULL);
std::cout.tie(NULL);
return 0;
}();
// Most of headers are already included;
// Can be removed;
#include <cstdint>
#include <vector>
#include <string>
static const struct Solution {
using ValueType = std::uint_fast16_t;
static const std::string convert(
const std::string s,
const int num_rows
) {
if (num_rows == 1) {
return s;
}
std::vector<std::string> res(num_rows);
ValueType row = 0;
ValueType direction = -1;
for (ValueType index = 0; index < std::size(s); ++index) {
if (!(index % (num_rows - 1))) {
direction *= -1;
}
res[row].push_back(s[index]);
row += direction;
}
std::string converted;
for (const auto& str : res) {
converted += str;
}
return converted;
}
};

Merge Intervals/Line 1034: Char 9: runtime error: reference binding to null pointer of type 'std::vector<int, std::allocator<int> >'

leetcode question-->I've to mearge the commom/overlaping intervals
can anyone help why this error is comming.
Question link-https://leetcode.com/problems/merge-intervals/
MY code is
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>>& intervals) {
vector<vector<int>>ans;
int n = intervals.size();
ans[0][0] = intervals[0][0];
ans[0][1] = intervals[0][1];
int i=0,j=1;
while(j<n ){
if(ans[i][1] > intervals[j][0]){
//ans[i][0] = intervals[i][0];
ans[i][1] = intervals[j][1];
j++;
}
else{
i=i+1;
ans[i][0] = intervals[j][0];
ans[i][1] = intervals[j][1];
j++;
}
}
return ans;
}
};
First of all, you need to choose a better title for your question. Secondly, I believe your algorithm does not meet the whole possible condition; if there's a set of intervals like {[2,3], [1,6]}, your algorithm merges these intervals to [2,6]. So, it is better to have some revise on your algorithm.
For solving this problem, we would want to sort the intervals first (order of N Log N).
This'll get through:
// The following block might slightly improve the execution time;
// Can be removed;
static const auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
}();
// Most of headers are already included;
// Can be removed;
#include <iostream>
#include <cstdint>
#include <vector>
#include <algorithm>
static const struct Solution {
static const std::vector<std::vector<int>> merge(
std::vector<std::vector<int>>& intervals
) {
std::sort(std::begin(intervals), std::end(intervals));
std::vector<std::vector<int>> merged;
if (std::size(intervals) >= 1) {
merged.emplace_back(intervals[0]);
}
for (std::size_t index = 0; index < std::size(intervals); ++index) {
const std::vector<int> interval = intervals[index];
const std::vector<int> tail = merged.back();
if (tail[1] >= interval[0]) {
merged.pop_back();
merged.emplace_back(std::vector<int> {
std::min(tail[0], interval[0]),
std::max(interval[1], tail[1])
});
} else {
merged.emplace_back(interval);
}
}
return merged;
}
};

Is it possible to get hash values as compile-time constants?

I thought I'd try selecting different options as strings by hashing them, but this doesn't work:
#include <type_traits>
#include <string>
inline void selectMenuOptionString(const std::string& str)
{
switch (std::hash<std::string>()(str))
{
case std::hash<std::string>()(std::string("Selection one")) : break;
// Expression must have a constant value
}
}
inline void selectMenuOptionString2(const std::string& str)
{
size_t selectionOneHash = std::hash<std::string>()(std::string("Selection one"));
switch (std::hash<std::string>()(str))
{
case selectionOneHash: // Expression must have a constant value
// The variable of selectionOneHash cannot be used as a constant
}
constexpr size_t hash = std::hash<int>()(6); // Expression must have a constant value
}
It seems I can't get hash values at compile time. From what I've read each different input should yield the same unique output every time, with a very low chance of collision. Given these properties couldn't the hash value be calculated at compile time? I don't know much at all about hashing, I usually use an unordered_map, but I wanted to try something new for learning's sake.
std::hash::operator() isn't constexpr, so you can't just use it. Instead, you'd have to write your own constexpr hash function. For example, the following is the FNV-1a hash algorithm (untested):
template <typename Str>
constexpr size_t hashString(const Str& toHash)
{
// For this example, I'm requiring size_t to be 64-bit, but you could
// easily change the offset and prime used to the appropriate ones
// based on sizeof(size_t).
static_assert(sizeof(size_t) == 8);
// FNV-1a 64 bit algorithm
size_t result = 0xcbf29ce484222325; // FNV offset basis
for (char c : toHash) {
result ^= c;
result *= 1099511628211; // FNV prime
}
return result;
}
And then you can use it:
int selectMenuOptionString(const std::string& str)
{
switch (hashString(str))
{
case hashString(std::string_view("Selection one")): return 42;
default: return 0;
}
}
Note that if you wrote hashString("Selection one"), it would actually hash the null terminator as well, so you might want to have an overload to catch string literals, such as:
template <size_t N>
constexpr size_t hashString(char const (&toHash)[N])
{
return hashString(std::string_view(toHash));
}
Demo
You'll need to implement your own hash function, because there's no suitable instantiation of std::hash that's constexpr. Here's a cheap-and-dirty...
EDIT: In order not to be humiliated too badly by Justin's answer, I added a 32 bit branch.
constexpr size_t hash(const char *str) {
static_assert(sizeof(size_t) == 8 || sizeof(size_t) == 4);
size_t h = 0;
if constexpr(sizeof(size_t) == 8) {
h = 1125899906842597L; // prime
} else {
h = 4294967291L;
}
int i = 0;
while (str[i] != 0) {
h = 31 * h + str[i++];
}
return h;
}
I just wanted to add this because I think it's cool. The constexpr strlen I got from a question here: constexpr strlen
#include <iostream>
#include <string>
int constexpr strlength(const char* str)
{
return *str ? 1 + strlength(str + 1) : 0;
}
size_t constexpr Hash(const char *first)
{ // FNV-1a hash function
const size_t FNVoffsetBasis = 14695981039346656037ULL;
const size_t FNVprime = 1099511628211ULL;
const size_t count = strlength(first);
size_t val = FNVoffsetBasis;
for (size_t next = 0; next < count; ++next)
{
val ^= (size_t)first[next];
val *= FNVprime;
}
return val;
}
inline void selectMenuOptionString(const std::string& str)
{
switch (Hash(str.c_str()))
{
case Hash("Selection one"): /*Do something*/ break;
case Hash("Selection two"): /*Do something*/ break;
}
}
int main()
{
static_assert(strlength("Hello") == 5, "String length not equal");
}
You can't get the hash of a runtime value at compile-time, no.
Even if you passed std::hash a constant expression, it is not defined to be able to do its hashing work at compile-time.
As far as I know (which isn't far), you'd have to come up with some monstrous template metahackery (or, worse, macros!) to do this. Personally, if your text input is known at build, I'd just pregenerate a hash outside of the code, perhaps in some Python-driven pre-build step.

Char array in a struct - not renewing?

I have a for-loop and i'm creating a new instance of a struct on the stack each time. This struct just contains 2 variables - 2 char arrays of 64 bytes.
The code is below:
for (std::map<std::string, std::string>::iterator iter = m_mDevices.begin(); iter != m_mDevices.end(); ++iter)
{
Structs::SDeviceDetails sRecord;
if (false == GenerateDeviceCacheRecord(iter->first, iter->second, sRecord)) // could just pass iter in?
{
// Failed to create cache record
return false;
}
}
The really strange thing i am seeing in the debugger, is everytime i loop round, i am seeing the same value in sRecord's buffers. i.e. sRecord.m_strUsername and sRecord.m_strPassword is getting "written over" as opposed to being a newly created struct.
If sRecord.m_strUsername was "abc" on the first loop round, then after the GenerateDeviceCacheRecord function (which just modifies sRecord), sRecord.m_strUsername might be "HIc", where c is the character off the first loop! I'm obviously expecting "abc" and "HI", not "abc" and "HIc". Does anyone know what might be going on here?
Thanks
Extra code:
namespace Constants
{
static const int64 MAX_HOSTNAME_BUFFER = 64;
static const int64 MAX_ILA_BUFFER = 64;
};
struct SDeviceRecordDetails
{
char m_strHostname[Constants::MAX_HOSTNAME_BUFFER];
char m_strILA[Constants::MAX_ILA_BUFFER];
};
bool GenerateDeviceCacheRecord(std::string strHostname, std::string strILA, Structs::SDeviceRecordDetails& sRecord)
{
// Convert strings to char arrays to store in the authentication cache manager records
if (strHostname.length() > Constants::MAX_HOSTNAME_BUFFER)
return false;
if (strILA.length() > Constants::MAX_ILA_BUFFER)
return false;
std::copy(strHostname.begin(), strHostname.end(), sRecord.m_strHostname);
std::copy(strILA.begin(), strILA.end(), sRecord.m_strILA);
return true;
}
//! #brief Devices retrieved from XML file
std::map<std::string, std::string> m_mDevicesAuthenticated;
So. I appreciate that you tried to get closer to a better question. So I'm going to take some next steps with you.
What you posted wasn't really a mcve.
Here's a mcve for your problem:
#include <iostream>
#include <cstdint>
#include <map>
#include <string>
#include <algorithm>
namespace Constants
{
static const int64_t MAX_HOSTNAME_BUFFER = 64;
static const int64_t MAX_ILA_BUFFER = 64;
};
struct SDeviceRecordDetails
{
char m_strHostname[Constants::MAX_HOSTNAME_BUFFER];
char m_strILA[Constants::MAX_ILA_BUFFER];
};
bool GenerateDeviceCacheRecord(std::string strHostname, std::string strILA, SDeviceRecordDetails& sRecord)
{
// Convert strings to char arrays to store in the authentication cache manager records
if (strHostname.length() > Constants::MAX_HOSTNAME_BUFFER)
return false;
if (strILA.length() > Constants::MAX_ILA_BUFFER)
return false;
std::copy(strHostname.begin(), strHostname.end(), sRecord.m_strHostname);
std::copy(strILA.begin(), strILA.end(), sRecord.m_strILA);
return true;
}
std::map<std::string, std::string> m_mDevices;
int main() {
m_mDevices["hello"] = "foo";
m_mDevices["buzz"] = "bear";
for (std::map<std::string, std::string>::iterator iter = m_mDevices.begin(); iter != m_mDevices.end(); ++iter) {
SDeviceRecordDetails sRecord;
const bool result = GenerateDeviceCacheRecord(iter->first, iter->second, sRecord);
if (result == false)
std::cout << "Failed\n";
else
std::cout << sRecord.m_strHostname << " " << sRecord.m_strILA << "\n";
}
}
Things to note:
I can take this as is (instead of two code blocks in your question) and throw it at a compiler.
I included the proper #include lines.
There were namespaces in your type names that weren't represented in your code.
m_mDevicesAuthenticated != m_mDevices.
You didn't include anything that actually had any output.
What is actually in m_mDevices? This is really important to include!
Among other small corrections I had to apply to the code to get it to build.
What did this code do?
This code almost produces the correct output. It has an error, in that the strings that are written to sRecord are not null terminated.
Because of how compilers generate code, and that you don't explicitly clear sRecord each loop, it's likely that this is the root cause of your problem.
Let's fix that:
Instead of:
std::copy(strHostname.begin(), strHostname.end(), sRecord.m_strHostname);
std::copy(strILA.begin(), strILA.end(), sRecord.m_strILA);
Let'd do:
snprintf(sRecord.m_strHostname, Constants::MAX_HOSTNAME_BUFFER, "%s", strHostname.c_str());
snprintf(sRecord.m_strILA, Constants::MAX_ILA_BUFFER, "%s", strILA.c_str());
Or perhaps you are concerned about what sRecord starts each loop with:
In this case, sRecord is not initialized at the beginning of each loop. The compiler is free to have junk data in the struct for optimization purposes.
It happens that most compilers will place each iteration of the struct in that exact same spot in memory. This means that the junk data in the struct could be the data from the previous iteration. Or some other junk depending on how the compiler optimizations function.
You could fix this by initializing the struct to contain explicit data:
SDeviceRecordDetails sRecord = {};
What does all of this look like:
The finished code, with all the bug fixes looks like:
#include <iostream>
#include <cstdint>
#include <map>
#include <string>
#include <algorithm>
namespace Constants
{
static const int64_t MAX_HOSTNAME_BUFFER = 64;
static const int64_t MAX_ILA_BUFFER = 64;
};
struct SDeviceRecordDetails
{
char m_strHostname[Constants::MAX_HOSTNAME_BUFFER];
char m_strILA[Constants::MAX_ILA_BUFFER];
};
bool GenerateDeviceCacheRecord(std::string strHostname, std::string strILA, SDeviceRecordDetails& sRecord)
{
// Convert strings to char arrays to store in the authentication cache manager records
if (strHostname.length() > Constants::MAX_HOSTNAME_BUFFER)
return false;
if (strILA.length() > Constants::MAX_ILA_BUFFER)
return false;
snprintf(sRecord.m_strHostname, Constants::MAX_HOSTNAME_BUFFER, "%s", strHostname.c_str());
snprintf(sRecord.m_strILA, Constants::MAX_ILA_BUFFER, "%s", strILA.c_str());
return true;
}
std::map<std::string, std::string> m_mDevices;
int main() {
m_mDevices["hello"] = "foo";
m_mDevices["buzz"] = "bear";
m_mDevices["zed"] = "zoo";
for (std::map<std::string, std::string>::iterator iter = m_mDevices.begin(); iter != m_mDevices.end(); ++iter) {
SDeviceRecordDetails sRecord = {};
const bool result = GenerateDeviceCacheRecord(iter->first, iter->second, sRecord);
if (result == false)
std::cout << "Failed\n";
else
std::cout << sRecord.m_strHostname << " " << sRecord.m_strILA << "\n";
}
}
And outputs:
buzz bear
hello foo
zed zoo
Which looks correct to my eyes.
I don't see any initialisation here. You're seeing whatever happened to be at that place in memory before, which for you, today, happens to be the previous contents of those data members.

Iterating over list of structs

I'm creating a list of structs:
struct task{
int task_id;
bool is_done;
char* buffer;
int length;
} task;
list<task> taskList;
And trying to iterate over the tasks in order to check the is_done status:
for (std::list<task>::const_iterator iterator = taskList.begin(), end = taskList.end(); iterator != end; ++iterator) {
if(iterator->is_done) {
return 1;
} else {
return 2;
}
}
Where am I wrong?
I get: Missing template argument before '->' token
The iterator's operator-> does the dereferencing already. So instead of
if(*iterator->is_done==true)
you need
if(iterator->is_done==true)
is equivalent to
if((*iterator).is_done==true)
which as a sidenote is equivalent to the easier to read
if((*iterator).is_done)
or
if(iterator->is_done)
. Even better, you could also use std::any_of:
#include <algorithm>
....
if (any_of(begin(taskList), end(taskList),
[](task const &t) { return t.is_done; }))
{
return 1;
} else {
return 2;
}
Informal note: There is no need to qualify any_of, begin and end with std::, because taskList is of type std::list<?>, and the C++-compiler will look up those functions in the std-namespace for you already.
Like this
if (iterator->is_done==true){
no need for * and ->.
And not the question you asked but
if (iterator->is_done==true) {
is exactly the same as the easier to understand
if (iterator->is_done) {
Don't compare booleans to true and false, they already are true and false.
Use std::find_if instead:
#include <algorithm>
...
bool isDone(const task &task)
{
return task.is_done;
}
...
return std::find_if(taskList.begin(), taskList.end(), isDone) == taskList.end() ? 2 : 1;
Try this. Note change to task struct and referencing iterator. (I changed name of iterator - to be more concise - but not actually required). I just think looks less confusing.
#include <list>
using namespace std;
struct task{
int task_id;
bool is_done;
char* buffer;
int length;
};
int main() {
std::list<task> taskList;
task task1;
task1.buffer = "qwerty";
task1.is_done = true;
task1.length = 6;
task1.task_id = 1;
taskList.push_back(task1);
for (std::list<task>::const_iterator it = taskList.begin(), end = taskList.end();
it != end; ++it) {
if((*it).is_done==true)
return 1;
else
return 2;
}
return 0;
}