I am building a small project for spelling correction, this is not homework.
Given two strings str1 and str2. One has to find out the number of characters matching between two strings.
For example if str1 = "assign" and str2 = "assingn", then the output should be 6.
In str2, characters, "a", "s", "s", "i", "g", "n" are there in str1, "assign". Thus output should be 6.
If str1 = "sisdirturn" and str2 = "disturb", then output should be 6.
In the str2, characters, "d", "i", "s", "t", "u", "r" are there in string str1, "sisdirturn". Thus output should be 6.
I've tried many attempts, however I am unable to get the answer. Kindly help to sort this out and if there is any idea to improve upon this, do tell.
Here is my attempt so far:
int char_match (string str1, string str2)
{
//Take two strings, split them into vector of characters and sort them.
int i, j, value = 0;
vector <char> size1, size2;
char* cstr1 = new char[str1.length() + 1];
strcpy(cstr1, str1.c_str());
char* cstr2 = new char[str2.length() + 1];
strcpy(cstr2, str2.c_str());
for(i = 0, j = 0 ; i < strlen(cstr1), j < strlen(cstr2); i++, j++)
{
size1.push_back( cstr1[i] );
size2.push_back( cstr2[j] );
}
sort (size1.begin(), size1.end() );
sort (size2.begin(), size2.end() );
//Start from beginning of two vectors. If characters are matched, pop them and reset the counters.
i = 0;
j = 0;
while ( !size1.empty() )
{
out :
while ( !size2.empty() )
{
if (size1[i] == size2[j])
{
value++;
pop_front(size1);
pop_front(size2);
i = 0;
j = 0;
goto out;
}
j++;
}
i++;
}
return value;
}
#include <iostream>
#include <algorithm> // sort, set_intersection
std::string::size_type matching_characters(std::string s1, std::string s2) {
sort(begin(s1), end(s1));
sort(begin(s2), end(s2));
std::string intersection;
std::set_intersection(begin(s1), end(s1), begin(s2), end(s2),
back_inserter(intersection));
return intersection.size();
}
int main() {
std::cout << matching_characters("assign", "assingn") << '\n'; // 6
std::cout << matching_characters("sisdirturn", "disturb") << '\n'; // 6
}
The above uses sort and so it has O(N*log N) performance, if that matters. If all your inputs are small then this may be faster than the second solution:
Sora's solution has better complexity, and can also be implemented concisely using standard <algorithm>s:
#include <iostream>
#include <algorithm> // for_each
#include <numeric> // inner_product
int matching_characters(std::string const &s1, std::string const &s2) {
int s1_char_frequencies[256] = {};
int s2_char_frequencies[256] = {};
for_each(begin(s1), end(s1),
[&](unsigned char c) { ++s1_char_frequencies[c]; });
for_each(begin(s2), end(s2),
[&](unsigned char c) { ++s2_char_frequencies[c]; });
return std::inner_product(std::begin(s1_char_frequencies),
std::end(s1_char_frequencies),
std::begin(s2_char_frequencies), 0, std::plus<>(),
[](auto l, auto r) { return std::min(l, r); });
}
int main() {
std::cout << matching_characters("assign", "assingn") << '\n'; // 6
std::cout << matching_characters("sisdirturn", "disturb") << '\n'; // 6
}
I'm using C++14 features, such as generic lambdas, for convenience. You may have to make some modifications if your compiler doesn't support C++14.
For me the solution using sort and set_intersection takes about 1/4th the time as the other solution for these inputs. That's because sorting and iterating over arrays of 6 or 7 elements can be faster than having to walk over arrays of 256 elements.
sort/set_intersection (3667ns) vs. for_each/inner_product (16,363ns)
Once the input is large enough the speed advantage will tip the other way. Furthermore, at the point where the input is too large to take advantage of the small-string optimization then the sort/set_intersection method will start doing expensive memory allocations.
Of course this performance result is highly implementation dependent, so if the performance of this routine matters you'll have to test it yourself on your target implementation with real input. If it doesn't matter then the O(N) solution is the better choice.
I am not 100% on what it is you are actually trying to achieve, but in the case of trying to see how many characters that match in the words, it would be a simple case of just running a loop through them and adding 1 every time you found a match, like this
int char_match (string str1, string str2)
{
//Take two strings, split them into vector of characters and sort them.
unsigned int matches = 0;
unsigned int stringLength = (str1.length > str2.length) ? str2.length : str1.length;
for(unsigned int i = 0; i < stringLength; ++i)
{
if(str1[i] == str2[i])
{
++matches;
}
}
return matches;
}
but from your code it looks like you want to find out exactly how many of the same characters they have that is to say ignoring the actual position of each character then it would be a rather different process. Something along the lines of this
int char_match (string str1, string str2)
{
unsigned int str1CharCount[256] = {0};
unsigned int str2CharCount[256] = {0};
unsigned int matches = 0;
for(unsigned int i = 0; i < str1.length; ++i)
{
++str1CharCount[static_cast<unsigned short>(str1[i])];
}
for(unsigned int i = 0; i < str2.length; ++i)
{
++str2CharCount[static_cast<unsigned short>(str1[i])];
}
for(unsigned int i = 0; i < 256; ++i)
{
matches += (str1CharCount[i] > str1CharCount[i]) ? str1CharCount[i] - (str1CharCount[i] - str2CharCount[i]) : str2CharCount[i] - (str2CharCount[i] - str1CharCount[i]);
}
return matches;
}
please note that for this second function there are probably a lot more efficient ways of doing it, but it should work all the same
EDIT:
This code should do what you wanted, main difference being it checks the ascii value to make sure it is a valid character
int char_match (string str1, string str2)
{
unsigned int str1CharCount[256] = {0};
unsigned int str2CharCount[256] = {0};
unsigned int matches = 0;
for(unsigned int i = 0; i < str1.length; ++i)
{
unsigned short aValue = static_cast<unsigned short>(str1[i]);
if(aValue >= static_cast<unsigned short>('a') && aValue <= static_cast<unsigned short>('z'))
{
++str1CharCount[static_cast<unsigned short>(str1[i]) - 32];
}
else if(aValue >= static_cast<unsigned short>('A') && aValue <= static_cast<unsigned short>('Z'))
{
++str1CharCount[static_cast<unsigned short>(str1[i])];
}
}
for(unsigned int i = 0; i < str2.length; ++i)
{
++str2CharCount[static_cast<unsigned short>(str1[i])];
}
for(unsigned int i = static_cast<unsigned short>('a'); i <= static_cast<unsigned short>('Z'); ++i)
{
matches += (str1CharCount[i] > str1CharCount[i]) ? str1CharCount[i] - (str1CharCount[i] - str2CharCount[i]) : str2CharCount[i] - (str2CharCount[i] - str1CharCount[i]);
}
return matches;
}
Related
I've written a code that removes all vowels from a string in c++ but for some reason it doesn't remove the vowel 'o' for one particular input which is: zjuotps.
Here's the code:
#include<iostream>
#include<string>
using namespace std;
int main(){
string s;
cin >> s;
string a = "aeiouyAEIOUY";
for (int i = 0; i < s.length(); i++){
for(int j = 0; j < a.length(); j++){
if(s[i] == a[j]){
s.erase(s.begin() + i);
}
}
}
cout << s;
return 0;
}
When I input: zjuotps
The Output I get is: zjotps
This is a cleaner approach using the C++ standard library:
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int main()
{
std::string input = "zjuotps";
std::string vowels = "aeiouyAEIOUY";
auto predicate = [&vowels](char c) { return vowels.find(c) != std::string::npos; };
auto iterator = std::remove_if(input.begin(), input.end(), predicate);
input.erase(iterator, input.end());
cout << input << endl;
}
Edit:
as #RemyLebeau pointed out, std::erase_if can be used which is introduced in c++20 and the answer becomes one line of code:
std::erase_if(input, [&vowels](char c) { return vowels.find(c) != std::string::npos; });
You can develop a solution by adding the matching characters to the new string object. The eliminate() method writes the character to the result object if the characters in the input object doesn't match the characters in the remove object.
#include <iostream>
/**
* #brief This method scans the characters in the "input" object and writes
* the characters not in the "remove" object to the "result" object.
* #param input This object contains the characters to be scanned.
* #param remove This object contains characters that will not match.
* #param result Non-match result data is writed to this object.
*/
void eliminate(std::string input, std::string remove, std::string &result);
int main()
{
std::string input = "zjuotpsUK", remove = "aeiouyAEIOUY", result;
eliminate(input, remove, result);
std::cout << result << std::endl;
return 0;
}
void eliminate(std::string input, std::string remove, std::string &result)
{
for (size_t i = 0, j = 0; i < input.length(); i++)
{
for(j = 0; j < remove.length(); j++)
if(input[i] == remove[j])
break;
if(j == remove.length())
result += input[i];
}
}
In your code here, I replaced s with input_str, and a with vowels, for readability:
for (int i = 0; i < input_str.length(); i++){
for(int j = 0; j < vowels.length(); j++){
if(input_str[i] == vowels[j]){
input_str.erase(input_str.begin() + i);
}
}
}
The problem with your current code above is that each time you erase a char in the input string, you should break out of the vowels j loop and start over again in the input string at the same i location, checking all vowels in the j loop again. This is because erasing a char left-shifts all chars which are located to the right, meaning that the same i location would now contain a new char to check since it just left-shifted into that position from one position to the right. Erroneously allowing i to increment means you skip that new char to check in that same i position, thereby leaving the 2nd vowel in the string if 2 vowels are in a row, for instance. Here is the fix to your immediate code from the question:
int i = 0;
while (i < s.length()){
bool char_is_a_vowel = false;
for(int j = 0; j < a.length(); j++){
if(s[i] == a[j]){
char_is_a_vowel = true;
break; // exit j loop
}
}
if (char_is_a_vowel){
s.erase(s.begin() + i);
continue; // Do NOT increment i below! Skip that.
}
i++;
}
However, there are many other, better ways to do this. I'll present some below. I personally find this most-upvoted code difficult to read, however. It requires extra study and looking up stuff to do something so simple. So, I'll show some alternative approaches to that answer.
Approach 1 of many: copy non-vowel chars to new string:
So, here is an alternative, simple, more-readable approach where you simply scan through all chars in the input string, check to see if the char is in the vowels string, and if it is not, you copy it to an output string since it is not a vowel:
Just the algorithm:
std::string output_str;
for (const char c : input_str) {
if (vowels.find(c) == std::string::npos) {
output_str.push_back(c);
}
}
Full, runnable example:
#include <iostream> // For `std::cin`, `std::cout`, `std::endl`, etc.
#include <string>
int main()
{
std::string input_str = "zjuotps";
std::string vowels = "aeiouyAEIOUY";
std::string output_str;
for (const char c : input_str)
{
if (vowels.find(c) == std::string::npos)
{
// char `c` is NOT in the `vowels` string, so append it to the
// output string
output_str.push_back(c);
}
}
std::cout << "input_str = " << input_str << std::endl;
std::cout << "output_str = " << output_str << std::endl;
}
Output:
input_str = zjuotps
output_str = zjtps
Approach 2 of many: remove vowel chars in input string:
Alternatively, you could remove the vowel chars in-place as you originally tried to do. But, you must NOT increment the index, i, for the input string if the char is erased since erasing the vowel char left-shifs the remaining chars in the string, meaning that we need to check the same index location again the next iteration in order to read the next char. See the note in the comments below.
Just the algorithm:
size_t i = 0;
while (i < input_str.length()) {
char c = input_str[i];
if (vowels.find(c) != std::string::npos) {
input_str.erase(input_str.begin() + i);
continue;
}
i++;
}
Full, runnable example:
#include <iostream> // For `std::cin`, `std::cout`, `std::endl`, etc.
#include <string>
int main()
{
std::string input_str = "zjuotps";
std::string vowels = "aeiouyAEIOUY";
std::cout << "BEFORE: input_str = " << input_str << std::endl;
size_t i = 0;
while (i < input_str.length())
{
char c = input_str[i];
if (vowels.find(c) != std::string::npos)
{
// char `c` IS in the `vowels` string, so remove it from the
// `input_str`
input_str.erase(input_str.begin() + i);
// do NOT increment `i` here since erasing the vowel char above just
// left-shifted the remaining chars in the string, meaning that we
// need to check the *same* index location again the next
// iteration!
continue;
}
i++;
}
std::cout << "AFTER: input_str = " << input_str << std::endl;
}
Output:
BEFORE: input_str = zjuotps
AFTER: input_str = zjtps
Approach 3 of many: high-speed C-style arrays: modify input string in-place
I borrowed this approach from "Approach 1" of my previous answer here: Removing elements from array in C
If you are ever in a situation where you need high-speed, I'd bet this is probably one of the fastest approaches. It uses C-style strings (char arrays). It scans through the input string, detecting any vowels. If it sees a char that is NOT a vowel, it copies it into the far left of the input string, thereby modifying the string in-place, filtering out all vowels. When done, it null-terminates the input string in the new location. In case you need a C++ std::string type in the end, I create one from the C-string when done.
Just the algorithm:
size_t i_write = 0;
for (size_t i_read = 0; i_read < ARRAY_LEN(input_str); i_read++) {
bool char_is_a_vowel = false;
for (size_t j = 0; j < ARRAY_LEN(input_str); j++) {
if (input_str[i_read] == vowels[j]) {
char_is_a_vowel = true;
break;
}
}
if (!char_is_a_vowel) {
input_str[i_write] = input_str[i_read];
i_write++;
}
}
input_str[i_write] = '\n';
Full, runnable example:
#include <iostream> // For `std::cin`, `std::cout`, `std::endl`, etc.
#include <string>
/// Get the number of elements in an array
#define ARRAY_LEN(array) (sizeof(array)/sizeof(array[0]))
int main()
{
char input_str[] = "zjuotps";
char vowels[] = "aeiouyAEIOUY";
std::cout << "BEFORE: input_str = " << input_str << std::endl;
// Iterate over all chars in the input string
size_t i_write = 0;
for (size_t i_read = 0; i_read < ARRAY_LEN(input_str); i_read++)
{
// Iterate over all chars in the vowels string. Only retain in the input
// string (copying chars into the left side of the input string) all
// chars which are NOT vowels!
bool char_is_a_vowel = false;
for (size_t j = 0; j < ARRAY_LEN(input_str); j++)
{
if (input_str[i_read] == vowels[j])
{
char_is_a_vowel = true;
break;
}
}
if (!char_is_a_vowel)
{
input_str[i_write] = input_str[i_read];
i_write++;
}
}
// null-terminate the input string at its new end location; the number of
// chars in it (its new length) is now equal to `i_write`!
input_str[i_write] = '\n';
std::cout << "AFTER: input_str = " << input_str << std::endl;
// Just in case you need it back in this form now:
std::string str(input_str);
std::cout << " C++ str = " << str << std::endl;
}
Output:
BEFORE: input_str = zjuotps
AFTER: input_str = zjtps
C++ str = zjtps
See also:
[a similar answer of mine in C] Removing elements from array in C
I would like something that can window a std::string object into partitions of length N - for example (using a function update):
int main() {
std::string s = "abcdefg";
update<2>(s);
return 0;
}
Calling the above should result in:
ab
bc
cd
ef
fg
I have the following version of the update function:
template<std::size_t size>
void update(std::string s) {
std::string result(size, '\0');
std::stringstream ss{s};
int iterations = s.length() - size;
for (int i = 0; i<iterations; i++) {
ss.read(&result[0], result.size());
std::cout << result << std::endl;
}
return;
}
but this skips out combinations where the initial character lies at an odd index (the number of combinations is correct in my case, even though there is a repeat)
ab
cd
ef
gf
gf
A side note is that if there are any trailing characters then these should be omitted from the printed values (although I think this would be covered by the parameters of the for loop)
A final note is that I would like this to be as optimised as possible since I would typically be using strings of a very large length (>5M characters long) - my current solution may not be best for this so I am open to suggestions of alternative strategies.
With C++17 you can do it like this, which is way more readable:
void update(std::string_view s, int size) {
const int iterations = s.size() - size;
for (int i = 0; i <= iterations; i++) {
std::cout << s.substr(i, size) << "\n";
}
}
string_view is made exactly for this purpose, for fast read access to a string. string_view::substr is const complexity while string::substr is linear.
As a side note, besides what Nick mentioned, your code has few other small problems:
std::endl fflushes the stream, it heavily impacts performance. Here you could just use '\n' to make a newline.
the return at the end is absolutely redundant, void functions do not require returns
what is the purpose of templating this? This will easily bloat your code without any measurable performance increase. Just pass the N as a parameter.
also your main is declared as void and should be int (even more so as you do return a value at the end)
With range-v3, you might use sliding view:
std::string s = "abcdefg";
for (auto r : s | ranges::views::sliding(2)) {
std::cout << r << std::endl;
}
Demo
Your call to ss.read will always read two characters, and then advance the ptr in the string stream 2 characters. So you never read/repeat the previous character at the start of each line.
If you want to do it "your way" then you have to keep track of the last character seperately.
#include <iostream>
#include <sstream>
template<std::size_t size>
void update(std::string s) {
std::string result(size, '\0');
char lastChar;
std::stringstream ss{s};
int iterations = s.length() - size;
int read = 0;
if (ss.readsome(&result[0], 1)) {
lastChar = result[0];
}
for (int i = 0; i < iterations; i++) {
if (read = ss.readsome(&result[0], size - 1)) {
std::cout << lastChar << result << std::endl;
lastChar = result[read - 1];
}
}
}
That being said, the above is definitely not the best approach performance wise. You should be able to do all of this without any string streams or read function, just iterating the string. Something like this
#include <iostream>
void update(std::string s, size_t size) {
int len = s.length();
for (int i = 1; i < len; i+=size-1) {
fwrite(&s[i-1], size, 1, stdout);
putchar('\n');
}
}
As part of my homework assignment, I have to split a char[] by its indices. So for example, the main function looks like:
int main()
{
char str[] = "A string to be split into given number of parts";
int split_size;
cout << "Enter the size of the part: ";
cin >> split_size;
int size = sizeof(str) / sizeof(str[0]);
SplitString(str, split_size, size);
int wait;
cin >> wait;
return 0;
}
Then using the function SplitString, the first x elements are printed, new line, then the next.
My first idea, was to use two for loops. One loops through the splits (i.e. if there are 4 splits, the range on this loop is 0 to 3), then the second loops through the split itself, iterating over the array elements.
My SplitString() function looks like this:
void SplitString(char str[], int split_size, int size) {
int parts = size / split_size;
for (int i = 0; i < parts; i++) {
for (int j = 0; j < split_size; j++) {
j = split_size * i;
cout << str[j];
}
cout << endl;
}
}
Is there an easier way to do this? I know in Python, you can use the arr[1:] to grab a range of elements from the array. Is there anything similar in C++? Is there some flaw in my logic? Is there something wrong with my code?
cout comes with a write function that takes a pointer and a size argument.
for (int i = 0; i < parts; i++) {
cout.write (str+i*split_size, split_size)
cout << endl;
}
Note that the code above does not check if the string is actually long enough. If the total size is not equal the split_size times a whole number, you will have to add an additional check.
Also, note that this:
int size = sizeof(str) / sizeof(str[0]);
can be written as:
int size = sizeof(str);
instead because the size of a char is always 1.
You can use std::string for this. Alternatively, if your compiler supports C++17, you can use std::string_view as the first argument of SplitString to avoid unnecessary copying.
#include <algorithm>
#include <iostream>
#include <string>
void SplitString(std::string s, std::size_t split_size)
{
while(!s.empty())
{
auto size = std::min(split_size, s.size());
std::cout << s.substr(0, size) << '\n';
s = s.substr(size, std::string::npos);
}
}
int main()
{
char str[] = "A string to be split into given number of parts";
int split_size = 5;
SplitString(str, split_size);
return 0;
}
Live example.
very basic C++ question. Looks I m really rusted there...
All I want to do is to read an array of X strings from a file and create an array of X vertical strings of the horizontal strings.
IE :
file contains:
azert
qsdfg
wxcvb
poiuy
mlkjh
I want to create a string array containing:
aqwpm
zsxol
edcol
rfvuj
tgbyh
Here is what I tried so far:
[bad code]
const int SIZE = 37;
std::string table_h[SIZE];
std::string table_v[SIZE];
int i = 0;
while (source >> table_h[i]) //,sizeof table_h[i]
{
for (int j = 0; j< SIZE; j++)
{
table_v[j][i] = table_h[i][j];
}
i++;
}
-> works fine for the first line, breaks when i=1. I don't understand what.
I noticed that although table_v[0][0] = 'f'; works fine.
Both table_v[0][36] = 'f'; and table_h[0].at(36); break.
With char * (which was my first idea),
char * table_h[SIZE];
char * table_v[SIZE];
something like
table_v[0][0] = 'f';
immediately breaks.
I suppose I need to allocate memory or initialize something first??
Thx in advance.
You should set the size of strings before using operator [] to access them. Resize of table_h is optional, but you definitely have to resize table_v.
const int SIZE = 37;
std::string table_h[SIZE];
std::string table_v[SIZE];
for (size_t i = 0; i < SIZE; ++i)
{
table_h[i].resize(SIZE);
table_v[i].resize(SIZE);
}
int i = 0;
while (source >> table_h[i])
{
for (int j = 0; j < SIZE; j++)
{
table_v[j][i] = table_h[i][j];
}
i++;
}
See the working example.
In my opinion, if you know the size of a strings, resizing is better than appending. It can save some memory re-allocations, and IMHO it is simply nicer solution.
Indeed the table_v[j] is an empty string.
The string needs to allocate space for the characters. This is not done by the index operators, i.e.
table_v[j][9] = 'a';
assumes enough space is allocated for table_v[j].
You can do append to your string to add to the initially empty string. Append does not take chars though, so instead of using index of table_h[i][j] you can use substr.
std::string to_append = table_j[i].substr(j, 1)
table[j].append(to_append);
This also relieves you of the i counter.
Here is a demonstrative program that shows how it can be done
#include <iostream>
#include <vector>
#include <string>
#include <numeric>
int main()
{
std::vector<std::string> v1 =
{
"azert", "qsdfg", "wxcvb", "poiuy", "mlkjh"
};
for ( const std::string &s : v1 ) std::cout << s << ' ';
std::cout << std::endl;
auto max_size = std::accumulate( v1.begin(), v1.end(),
size_t( 0 ),
[]( size_t acc, const std::string &s )
{
return acc < s.size() ? s.size() : acc;
} );
std::vector<std::string> v2( max_size );
for ( const std::string &s : v1 )
{
for ( std::string::size_type i = 0; i < s.size(); i++ )
{
v2[i].push_back( s[i] );
}
}
for ( const std::string &s : v2 ) std::cout << s << ' ';
std::cout << std::endl;
return 0;
}
The program output is
azert qsdfg wxcvb poiuy mlkjh
aqwpm zsxol edcik rfvuj tgbyh
As for your code than these statements
std::string table_h[SIZE];
std::string table_v[SIZE];
defined two arrays of empty strings. So you may not apply the subscript opertaor to an empty string. You could use for example member function push_back
for (int j = 0; j< SIZE; j++)
{
table_v[j].push_back( table_h[i][j] );
}
Hey I'm writing a function that takes two std::vector<std::string> and returns a third std::vector<std::string>.
The function is going to encode the two vectors together and create the 3rd vector.
I'm currently debugging this to find out why it's not working, and I keep getting: vector subscript out of range. As far as I can tell it's crashing at this line:
if (file2[i].size() < file1[i].size())
Can I use size() to get the size of the element at i?
std::vector<std::string> Encode(std::vector<std::string> &file1,
std::vector<std::string> &file2)
{
std::vector<std::string> file3;
std::string temp;
for (unsigned int i = 0; i < file1.size(); i++) {
for (unsigned int x = 0; x < file1[i].size(); x++) {
if (file2[i].size() < file1[i].size()) {
for (unsigned int t = 0; t < file2[i].size(); t++) {
file3[i][x] = (int)file1[i][x] + (int)file2[i][t];
}
} else if (file2[i].size() > file1[i].size()) {
file3[i][x] = (int)file1[i][x] + (int)file2[i][x];
}
if (file3[i][x] > 126) {
file3[i][x] = file3[i][x] % 127;
} else {
file3[i][x] = file3[i][x] + 32;
}
}
}
return file3;
}
Any idea what's going on here?
I'd be very much inclined to simplify by factoring. At the lowest layer is a combine function to combine two chars into one:
char combine(char a, char b)
{
char result = a+b;
if (result > 126)
return result % 127;
return result+32;
}
The next level up would be to iterate through each of the letters in two strings of possibly different sizes. The algorithm works for differing length strings by "recycling" through the shorter string.
std::string mix(const std::string &first, const std::string &second)
{
unsigned len1 = first.length();
unsigned len2 = second.length();
if (len1 < len2)
return mix(second, first);
std::string result;
// if the strings are of different lengths, first is now the longer
unsigned j=0;
for (unsigned i=0; i < len1; ++i, ++j) {
if (j >= len2)
j = 0;
result.push_back(combine(first[i], second[j]));
}
return result;
}
Finally, the combination of the vector of string is much simpler:
std::vector<std::string> Encode(const std::vector<std::string> &file1,
const std::vector<std::string> &file2)
{
std::vector<std::string> file3;
assert(file1.size() == file2.size());
for (unsigned int i = 0; i < file1.size(); i++) {
file3.push_back(mix(file1[i], file2[i]));
}
return file3;
}
Note that the code currently uses an assert to assure that the two vectors are the same length, but this is probably an artificial constraint. Real code should either assure that they are the same length or do something else to handle that case. Since it's not clear what your function is intended to do, I've left it to you to decide how to handle it, but with the assert as a placeholder to remind you that it does need to be addressed.
Finally, some driver code using C++11:
int main()
{
std::vector<std::string> english{"one", "two", "three", "four"};
std::vector<std::string> spanish{"uno", "dos", "tres", "cuatro"};
auto result = Encode(english, spanish);
std::copy(result.begin(), result.end(),
std::ostream_iterator<std::string>(std::cout, " "));
}
Note, too that I've used push_back to append to the end of the strings and const declarations for the passed strings.
Try these three sets of inputs:
1. file1 is bigger than file2
2. file2 is bigger than file1
3. file1 is equal to file2 in size.
Let us know the cases when the error was reproduced and when it was not.
I think by this stage you will solve the problem by yourself.
If not,
write contents of the (smallest possible) file1 and file2 that reproduced the error.
Some problems enumerated:
-You are assuming that file1 and file2 have the same size or at least that file1 has size <= file2 (in the other case would cause invalid memory access in line if (file2[i].size() < file1[i].size()) {) and are not checking in the function for that. At least add an assert statement or a checking.
-You are initializing file3 empty, and are indexing later in the function.
-The other problem is what happen when file1[i] and file2[i] have the same length, this option is not cover in the if-else, the cover options are < and > but not ==.
-You are accessing invalid memory with statements like file3[i][x], because the strings in file3[i] are initialized empty, for that, don't contain any character.
This is the more close that i can get without known the exact steps of the encode algorithm
#include <iostream>
#include <vector>
#include <boost/lexical_cast.hpp>
using namespace std;
std::vector<std::string> Encode(std::vector<std::string> &file1,
std::vector<std::string> &file2) {
assert(file1.size() <= file2.size());
std::vector<std::string> file3(file1.size());
std::string temp;
for (unsigned int i = 0; i < file1.size(); i++) {
for (unsigned int x = 0; x < file1[i].size(); x++) {
int enc = 0;
if (file2[i].size() <= file1[i].size()) {
for (unsigned int t = 0; t < file2[i].size(); t++) {
enc = (int)file1[i][x] + (int)file2[i][t];
}
}
else if (file2[i].size() > file1[i].size()) {
enc = (int)file1[i][x] + (int)file2[i][x];
}
if (enc > 126) {
file3[i] += (enc % 127);
}
else {
file3[i] += (enc + 32);
}
}
}
return file3;
}
int main(int argc, char *argv[]) {
std::vector<std::string> a{ "1", "2", "3" };
std::vector<std::string> b{ "6", "7", "8" };
for (const auto& s : a)
std::cout << s << std::endl;
for (const auto& s : b)
std::cout << s << std::endl;
auto c = Encode(a, b);
for (const auto& s : c)
std::cout << s << std::endl;
return 0;
}