Reference to a vector element become invalid after n iterations - c++

Program stop occur in this line
guess = secret;
From that, I guess that reference is broken, because if I change reference to simple value
const string secret = word_list[idx_word];
the program finishes correctly. So, my question is why this happen. The word_list is not changed/resided in loop.
Erorr occur on 392 iteration.
#include <QCoreApplication>
#include <QFile>
#include <QDir>
#include <QVector>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <map>
#include <set>
#include <thread>
#include <mutex>
#include <iomanip>
#include <string>
using namespace std;
bool debug = true;
const int COUNT = 5;
string MASK_FULL_MATCH(COUNT, 'o');
const string getMask(const string& word, const string& answer) {
if (word.size() != COUNT || answer.size() != COUNT) {
cout << word.size() << " " << answer.size() << endl;
}
char mask[5];
bool visited[5];
for (int i = 0; i < COUNT; i++) {
mask[i] = 'x';
visited[i] = false;
}
// find correct letters
for(int i = 0; i < COUNT; i++){
if (word[i] == answer[i]){
mask[i] = 'o';
visited[i] = true;
}
}
// find present letters
for (int i = 0; i < COUNT; i++){
if (mask[i] != 'o'){
for (int j = 0; j < COUNT; j++) {
if (answer[j] == word[i] && !visited[j]) {
mask[i] = '-';
visited[j] = true;
break;
}
}
}
}
return string(mask, COUNT);
}
int main(int argc, char *argv[])
{
QString pathToFile = QString("C:/Users/Ivan/Desktop/w_assets/w") + QString::number(COUNT) + QString("_entropy.txt");
QFile file(pathToFile);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return -2;
QTextStream in(&file);
QVector<string> word_list;
while (!in.atEnd()) {
QString line = in.readLine();
word_list.append(line.split(QChar(' '))[0].toStdString());
}
file.close();
for (int idx_word = 0; idx_word < word_list.size(); idx_word++) {
const string &secret = word_list[idx_word];
cout << secret << '\t';
}
int total = 0;
for (int idx_word = 0; idx_word < word_list.size(); idx_word++) {
const string &secret = word_list[idx_word];
cout << "NEW SECRET " << secret << endl;
QVector<string> possible_answers = word_list;
for (int row = 0; row < 6; row++) {
string guess;
if (row == 0) {
guess = word_list[0];
}
else {
cout << "before broken secret\n";
guess = secret;
cout << "after broken secret\n";
cout << "row " << row << "; GUESS " << guess << endl;
}
debug = true;
string mask = getMask(guess, secret);
debug = false;
cout << "MASK: " << mask << endl;
if (mask == MASK_FULL_MATCH) {
break;
}
QVector<string> new_possible_answers;
for (const auto& pa : possible_answers) {
if (getMask(guess, pa) == mask) {
new_possible_answers.append(pa);
}
}
possible_answers = new_possible_answers;
cout << "NEW POSSIBLE WORDS SIZE " << possible_answers.size() << endl;
}
}
return 0;
}

word_list[0]; - this is a non-const operation in a QVector (see documentation, there is even a note about the possible detach) and since the reference count of your word_list is two due to the copy to possible_answers some lines above, the container has to do a detach and therefore your reference goes out of scope.
If you work with references on Qt containers you have to make sure to either have a reference count of 1 or only use const-access to the container (e.g. by creating a const ref to the container -> const auto &const_word_list = word_list; guess = const_word_list [0])

Related

pHash returning different hash lenght

I have the following code:
fingerprint.cpp:
#include <iostream>
#include <filesystem>
#include "ImageHash.h"
#include "opencv2/core.hpp"
#include "opencv2/highgui.hpp"
#include <opencv2/imgcodecs.hpp>
using namespace std;
void usage (char** argv) noexcept {
cout << "Usage: " << argv[0] << " <image or dir>" << endl << "Example: " << argv[0] << " template.png" << endl;
}
int main(int argc, char** argv) {
if (argc != 2) {
usage(argv);
return 1;
}
auto imgHash = ImageHash();
if (std::filesystem::is_directory(argv[1])) {
for (const auto& dirEntry : std::filesystem::recursive_directory_iterator(argv[1])) {
auto filePath = dirEntry.path();
std::string fileName = dirEntry.path().filename().string();
cv::Mat img = cv::imread(filePath.string(), cv::IMREAD_GRAYSCALE);
img.resize(8*8);
/*cv::imshow("img", img);
cv::waitKey();*/
cout << fileName << "\t\t" << imgHash.getHashString(img) << endl;
}
}
else if (std::filesystem::is_regular_file(argv[1])){
cv::Mat img = cv::imread(argv[1], cv::IMREAD_GRAYSCALE);
cout << std::filesystem::path(argv[1]).filename().string() << "\t\t" << imgHash.getHashString(img) << endl;
}
else {
usage(argv);
}
return 0;
}
ImageHash.cpp:
#include "ImageHash.h"
#include <iomanip>
using namespace std;
ImageHash::ImageHash()
{
pHash = cv::img_hash::PHash::create();
}
std::string ImageHash::convertHashToString(vector<bool> hash) {
std::string ret = "";
double h = 0;
for (unsigned int i = 0; i < hash.size(); i++) {
if (hash[i]) {
h += pow(2, (i % 8));
}
if (i % 8 == 7) {
std::stringstream buffer;
buffer << std::hex << std::setfill('0') << std::setw(2) << h;
ret += buffer.str();
h = 0;
}
}
return ret;
}
std::vector<bool> ImageHash::hex_str_to_hash(std::string inputString) {
std::vector<bool> hash;
size_t size = inputString.size() / 2;
for (int i = 0; i < size; i++) {
std::string str2 = inputString.substr(i * 2, 2);
if (str2.empty()) {
continue;
}
unsigned int value = 0;
std::stringstream SS(str2);
SS >> std::hex >> value;
for (int j = 0; j < 8; j++) {
bool check = !!((value >> j) & 1);
hash.push_back(check);
}
}
return hash;
}
std::vector<bool> ImageHash::matHashToBoolArr(cv::Mat const inHash) {
const unsigned char* data = inHash.data;
std::vector<bool> v;
for (int i = 0; i < 8; i++) {
unsigned char c = data[i];
for (int j = 0; j < 8; j++) {
int shift = (8 - j) - 1;
bool val = ((c >> shift) & 1);
v.push_back(val);
}
}
return v;
}
std::vector<bool> ImageHash::computeHash(cv::Mat const input) {
cv::Mat inHash;
pHash->compute(input, inHash);
return matHashToBoolArr(inHash);
}
std::string ImageHash::getHashString(cv::Mat const input) {
return convertHashToString(computeHash(input));
}
//returns hamming distance
int ImageHash::getHashDistance(std::vector<bool>& hash1, std::vector<bool>& hash2) {
//assert(hash1.size() == hash2.size());
/* ToDo: I don't know why the size is not the same but if if is lets add padding to the smaller one
This does not seem to make it work*/
if (hash1.size() != hash2.size()) {
auto smaller = hash1.size() < hash2.size() ? &hash1 : &hash2;
auto larger = hash1.size() < hash2.size() ? hash2 : hash1;
smaller->resize(larger.size());
std::fill(begin(*smaller) + larger.size(), end(*smaller), 0);
}
int dist = 0;
for (unsigned int i = 0; i < hash1.size(); i++) {
dist += (hash1[i] != hash2[i]);
}
return dist;
}
For some reason the hashes returned have different size depending on the input image. I tried to add some padding at getHashDistance() but I don't think I should do that since now when I calculate the distance between two similar images I get a large distance as if they were not similar.
Do you know why that is? I'm resizing the images to 8*8 img.resize(8*8); which I though it would make the trick but it does not work.
Thanks
Thanks
auto imgHash = ImageHash();
Could it be that the auto keyword here is causing the runtime to draw different inferences of the returned type (and therefore the size of the returned type)?
Type Inference in C++ (auto and decltype)

How to get a substring by deleting minimum number of characters?

In this question, we take 2 strings as input say s1 and s2.
Now, first we need to check if s2 is a subsequence of s1. If not, print no.
But if it is, we need to print the minimum number of characters to be deleted from s1 to get s2.
Eg- thistext text
Here, text can be directly found without deleting any characters so the answer is 0.
Eg- cutefriendship crisp
In this case, the answer is 9.
What I've done so far,
#include <bits/stdc++.h>
using namespace std;
int checkIfSub(string s1, string s2, int m, int n)
{
int j = 0;
for(int i = 0; i < m && j < n; i++)
if(s1[i] == s2[j])
j++;
if(j == n)
return 0;
else
return 1;
}
int check(string s1, string s2)
{
int count = 0; string s3;
if(checkIfSub(s1, s2, s1.length(), s2.length()) == 1 || s2.length() > s1.length())
{
cout << "NO\n"; return 0;
}
int j = 0;
for(int i = 0; i < s1.length(); i++)
{
if(s1[i] == s2[j])
{
s3[j] = s1[j];
j++; continue;
}
count++;
}
cout << "YES " << count << "\n";
return 0;
}
int main() {
string s1, s2;
cin >> s1 >> s2;
check(s1, s2);
return 0;
}
My code works well for the second example, but fails the first case.
(This was a question asked in some interview I read online.)
Try something like this:
#include <iostream>
#include <string>
using namespace std;
bool check(const string &s1, const string &s2, int &minToDelete)
{
minToDelete = 0;
bool anySubSeqFound = false;
if (s2.empty())
return false;
string::size_type first = 0;
while ((first = s1.find(s2[0], first)) != string::npos)
{
int numDeleted = 0;
bool isSubSeq = true;
string::size_type next = first + 1;
for(string::size_type j = 1; j < s2.size(); ++j)
{
string::size_type found = s1.find(s2[j], next);
if (found == string::npos)
{
isSubSeq = false;
break;
}
numDeleted += (found - next);
next = found + 1;
}
if (isSubSeq)
{
if (anySubSeqFound)
{
if (numDeleted < minToDelete)
minToDelete = numDeleted;
}
else
{
anySubSeqFound = true;
minToDelete = numDeleted;
}
}
++first;
}
return anySubSeqFound;
}
int main()
{
int minToDelete;
if (check("thistext", "text", minToDelete))
cout << "yes, delete " << minToDelete << endl;
else
cout << "no" << endl;
if (check("cutefriendship", "crisp", minToDelete))
cout << "yes, delete " << minToDelete << endl;
else
cout << "no" << endl;
}
Live Demo

Passing a 2d dynamic array of strings by reference in C++

I have to use a dynamic array for this project but I can't pass it by reference, I am not sure what to do, I initialized the 2d dynamic array, but not sure how to pass it by reference.
#include <iostream>
#include <vector>
#include <string>
#include <iomanip>
using namespace std;
#define row 5
#define col 14
typedef string* StrArrPtr;
void set_up_array(string (&&layout_array)[row][col]);
int main()
{
StrArrPtr *layout_array = new StrArrPtr[col];
for(int i = 0; i < row; i++)
{
layout_array[i] = new string[col];
}
//string layout_array[row][col];
set_up_array(layout_array);
for(int i = 0; i < row; i++)
{
for(int j = 0; j < col; j++)
{
if(j == 1 && i > 0)
{
cout << right << setw(11);
}
cout << "| " << layout_array[i][j] << " ";
}
cout << "|" << endl;
}
return 0;
}
void set_up_array(string (&&layout_array)[row][col])
{
layout_array[0][0] = "Lab Number"; //First Column / first row
layout_array[1][0] = "1"; // second row
layout_array[2][0] = "2"; // third row
layout_array[3][0] = "3"; // fourth row
layout_array[4][0] = "4"; // fifth row
}
I am new to c++ so the solution might be very obvious but I just can't see it. Any help would be appreciated.
Given what you are doing with the array in set_up_array, you don't need to pass the actual string* by reference, because you're simply dereferencing it (telling your computer where to look for a string) and altering the value of string located at that index. When you pass an array in C/C++, you're just passing in an int, so don't worry about references unless you're modifying what the pointer is pointing to.
(It would be like string * &ref)
To pass a 2D array by reference, use:
void set_up_array(string (&layout_array)[row][col]);
In order to be able call that function, the variable needs to be of type string [row][col].
Change main to:
int main()
{
std::string layout_array[row][col];
set_up_array(layout_array);
...
}
Since you know the sizes of the arrays at compile time, it will be better to use std::array.
#include <iostream>
#include <vector>
#include <array>
#include <string>
#include <iomanip>
using namespace std;
const int row = 5;
const int col = 14;
void set_up_array(std::array<std::array<std::string, col>, row>& layout_array);
int main()
{
std::array<std::array<std::string, col>, row> layout_array;
set_up_array(layout_array);
for(int i = 0; i < row; i++)
{
for(int j = 0; j < col; j++)
{
if(j == 1 && i > 0)
{
cout << right << setw(11);
}
cout << "| " << layout_array[i][j] << " ";
}
cout << "|" << endl;
}
return 0;
}
void set_up_array(std::array<std::array<std::string, col>, row>& layout_array)
{
layout_array[0][0] = "Lab Number"; //First Column / first row
layout_array[1][0] = "1"; // second row
layout_array[2][0] = "2"; // third row
layout_array[3][0] = "3"; // fourth row
layout_array[4][0] = "4"; // fifth row
}
Arrays are always pass by reference.. your problem is how to pass a 2d array of string...
analyze how i did it:
#include <iostream>
#include <vector>
#include <string>
#include <iomanip>
using namespace std;
#define row 5
#define col 14
typedef string* StrArrPtr;
void set_up_array(string* layout_array[]);
int main()
{
StrArrPtr *layout_array = new StrArrPtr[row];
for(int i = 0; i < row; i++)
{
layout_array[i] = new string[col];
}
//string layout_array[row][col];
set_up_array(layout_array);
for(int i = 0; i < row; i++)
{
for(int j = 0; j < col; j++)
{
if(j == 1 && i > 0)
{
cout << right << setw(11);
}
cout << "| " << layout_array[i][j] << " ";
}
cout << "|" << endl;
}
return 0;
}
void set_up_array(string* layout_array[])
{
layout_array[0][0] = "Lab Number"; //First Column / first row
layout_array[1][0] = "1"; // second row
layout_array[2][0] = "2"; // third row
layout_array[3][0] = "3"; // fourth row
layout_array[4][0] = "4"; // fifth row
}

least number of digits without duplicates

I am a C++ noob. I have a list of numbers that I put into a Vector. All numbers are 9 digit integers and are unique. I want to know what is the least amount of digits (starting from the right) that can be used to uniquily identify each number in the set. right now there are only 6 numbers, but the list could potentially grow into the thousands. I have posted my code thus far (not working.)
EDIT output is the following...
digit is 1
digit is 1
digit is 1
RUN FINISHED; exit value 0; real time: 0ms; user: 0ms; system: 0ms
This is mostly a learning exercise. Please be generous and explicit with your comments and solutions.
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <cstdlib>
#include <algorithm>
using namespace std;
int main() {
//declare stream variable and load vector with values
ifstream myfile("mydata.txt");
vector<int> myVector;
int num;
while (myfile >> num) {
myVector.push_back(num);
}
//sort and squack if there is a duplicate.
std::sort(myVector.begin(), myVector.end());
for (int i = 0; i < (myVector.size() - 1); i++) {
if (myVector.at(i) == myVector.at(i + 1)) {
printf("There are duplicate student numbers in the file");
exit(EXIT_FAILURE);
}
}
//if it get here, then there are no duplicates of student numbers
vector<int> newv;
int k = 1;
bool numberFound = false;
bool myflag = false;
while (numberFound == false) {
//loop through original numbers list and add a digit to newv.
for (int j = 0; j < myVector.size(); ++j) {
newv.push_back(myVector.at(j) % (10^k));
}
sort(newv.begin(), newv.end());
for (int i = 0; i < (newv.size() - 1); i++) {
if (newv.at(i) == newv.at(i + 1)) {
//there is a duplicate for this digit. Set flag.
myflag = true;
}
if (myflag == false) {
numberFound = true;
cout << "digit is " << k << endl;
} else {
k++;
}
}
}
// for (int i = 0; i < myVector.size(); i++) {
// cout << "||" << myVector.at(i) << "||" << endl;
// }
//
// for (int i = 0; i < newv.size(); i++) {
// cout << "---" << newv.at(i) << "---" << endl;
// }
return 0;
}
Check the below code.
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <math.h>
using namespace std;
int main() {
//declare stream variable and load vector with values
ifstream myfile("mydata.txt");
vector<int> myVector;
int num;
while (myfile >> num) {
myVector.push_back(num);
}
//sort and squack if there is a duplicate.
std::sort(myVector.begin(), myVector.end());
for (int i = 0; i < (myVector.size() - 1); i++) {
if (myVector.at(i) == myVector.at(i + 1)) {
printf("There are duplicate student numbers in the file");
exit(EXIT_FAILURE);
}
}
//if it get here, then there are no duplicates of student numbers
vector<int> newv;
int k = 1;
bool numberFound = false;
bool myflag = false;
int p = 1;
while (numberFound == false) {
//loop through original numbers list and add a digit to newv.
newv.clear();
p = p * 10;
for (int j = 0; j < myVector.size(); ++j) {
newv.push_back(myVector[j] % p);
}
sort(newv.begin(), newv.end());
myflag = false;
for (int i = 0; i < (newv.size() - 1); i++) {
if ( newv[i] == newv[i+1]) {
//there is a duplicate for this digit. Set flag.
myflag = true;
break;
}
}
if (myflag == true){
k ++;
}else{
numberFound = true;
cout << "digit is " << k << endl;
break;
}
}
return 0;
}
Sample Input:
123451789
123456687
125456789
123456780
Output:
digit is 4

C++ Anagram Maker Error

I have been trying to make an anagram maker, using a textBox (encryption_text) for input, which the text is "Hello World", and the output textBox (encrypted_text) which receives the text:
"ellllloooo
WWWWWWooooooorrrrrrrrllllllllldddddddddd".
I also have a textBox called 'anag_used', which should record the used number/location in the string to encrypt.
Have I over complicated it, or is there an error?
Thanks :)
Here is my code:
void anagram()
{
string toanagram = marshal_as<string>(encryption_text->Text);
string out;
int k;
System::String^ rndstr;
System::String^ ktostr;
ostringstream kstr;
anag_used->Clear();
for (int i = 0; i < toanagram.size(); ++i)
{
anag_used->Text += "\n";
int rnd = 0 + rand() % toanagram.size();
ostringstream rndtostr;
rndtostr << rnd;
rndstr = gcnew System::String(rndtostr.str().c_str());
for (int l = 0; l < i; ++l)
{
if (anag_used->Lines[l] == rndstr)
{
k = rnd;
kstr << k;
ktostr = gcnew System::String(kstr.str().c_str());
for (System::String^ j = anag_used->Lines[l]; j == ktostr; k = 0 + rand() % toanagram.size())
{
kstr << k;
ktostr = gcnew System::String(kstr.str().c_str());
if (anag_used->Lines[l] == ktostr)
{
//Do someting if you want
}
else
{
out += toanagram[k];
anag_used->Lines[l] = ktostr;
}
}
}
else
{
out += toanagram[i];
anag_used->Lines[i] = rndstr;
}
}
}
encrypted_text->Text = marshal_as<System::String^>(out);
}
EDIT: FOUND A MUCH SIMPLER WORKING CODE
#include <algorithm>
.
string toanagram = marshal_as<string>(encryption_text->Text);
sort(toanagram.begin(), toanagram.end());
encrypted_text->Text = marshal_as<System::String^>(toanagram);
This works for console, but you could implement it in C++/CLI quite easily
#include <iostream>
#include <sstream>
#include <vector>
#include <ctime>
void str_vect(std::vector<const char>* v, std::string& s)
{
for (int i = 0; i < s.length(); ++i)
{
v->push_back(s[i]);
}
}
int main()
{
for (;;)
{
std::cout << "Please enter the word / phrase\n";
std::string word;
std::getline(std::cin, word);
std::vector<const char> word_split;
str_vect(&word_split, word);
int sz = word_split.size();
std::string anagram;
for (int i = 0; i < sz; ++i)
{
srand(time(NULL));
int r = (rand() % (word_split.size() - 0)) + 0;
anagram += word_split[r];
word_split.erase((word_split.begin()) + r);
}
system("cls");
std::cout << "Please guess the anagrammed phrase / word - '" << anagram << "'\n";
int max_tries = 3;
int tries = max_tries;
for (int i = 0; i <= max_tries; ++i)
{
std::string guess;
std::getline(std::cin, guess);
if (guess != word)
{
tries--;
if (tries == 0)
{
std::cout << "You have ran out of tries. The answer was: " << word << "\n";
break;
}
std::cout << tries << ((tries == 1) ? " try" : " tries") << " left\n";
}
else
{
std::cout << "Correct!\n";
break;
}
}
}
}
#include <algorithm>
.
string toanagram = marshal_as<string>(encryption_text->Text);
sort(toanagram.begin(), toanagram.end());
encrypted_text->Text = marshal_as<System::String^>(toanagram);