Problem is to return any one combination from given array that sums up to the target. I'm new to C++. How can I complete the function howSum() below? I can't return null here since the return type is vector. Also I'm having trouble passing the vectors.
JavaScript:
const howSum = (targetSum, numbers) => {
if (targetSum === 0) return [];
if (targetSum < 0) return null;
for (let num of numbers) {
const remainder = targetSum - num;
const remainderResult = howSum(remainder, numbers);
if (remainderResult !== null)
{
return [...remainderResult, num];
}
}
return null;
};
C++:
vector<int> howSum(int targetSum, vector<int> numbers)
{
if(targetSum == 0) return {};
if(targetSum < 0) return; //can't return null here in C++
for (int i = 0; i < numbers.size(); i++)
{
int remainder = targetSum - numbers[i];
vector<int> remainderResult = howSum(remainder, numbers);
if(pass)
{
pass
}
}
}
You can use C++17 std::optional and return std::nullopt when it does not contain value.
#include <optional>
#include <vector>
std::optional<std::vector<int>>
howSum(int targetSum, const std::vector<int>& numbers) {
if (targetSum == 0)
return std::vector<int>{};
if (targetSum < 0)
return std::nullopt;
for (auto numer : numbers) {
const auto remainder = targetSum - numer;
auto remainderResult = howSum(remainder, numbers);
if (remainderResult) {
remainderResult->push_back(targetSum);
return remainderResult;
}
}
return std::nullopt;
}
Let your function return a bool to indicate if the vector result (returned as an out param) is valid or not. It's likely going to be more efficient to pass the array (vector) as an out param reference than as a return value anyway. (Although modern compilers can do some amazing optimizations these days.)
bool howSum(int targetSum, const std::vector<int>& numbers, std::vector<int>& result)
{
result.clear();
if (targetSum == 0) {
return true;
}
if (targetSum < 0) {
return false;
}
for (int num : numbers) {
const int remainder = targetSum - num;
bool recursion_result = howSum(remainder, numbers, result);
if (recursion_result) {
result.push_back(num);
return true;
}
}
return false;
}
Related
The problem: I am trying to create a function capable of finding the largest number if the array is an integer, double, float, etc. If the array given is a string it returns the string in the string with the most letters. However, I don't know how to cast list [0] and list[i] as strings.
#include <isostream>
#include <algorithm>
using namespace std;
unsigned int strlength(string word) {
char *ch = &word[0];
unsigned int count = 0;
while (*ch != '\0') {
count++;
ch++;
}
return *count;
}
template<typename U>
U maxNumber(U list[], int size) {
unsigned int i;
if (typeid(list) == typeid(string*)) {
unsigned int i;
for (i = 0; i < size; i++) {
if (strlength(list[0]) < strlength(list[i])) {
list[0] = list[i];
}
else {
list[0] = list[0];
}
}
return list[0];
}
else {
for (i = 0; i < size; i++) {
if (list[0] < list[i]) {
list[0] = list[i];
}
else {
continue;
}
}
return list[0];
}
}
if (typeid(list) == typeid(string*)) is the wrong tool.
You need compile time branch,
either with if constexpr
template<typename U>
U maxNumber(U list[], int size) {
if constexpr (std::is_same_v<U, std::string>) {
auto less_by_size = [](const auto& lhs, const auto rhs){
return lhs.size() < rhs.size(); };
return *std::max_element(list, list + size, less_by_size);
} else {
return *std::max_element(list, list + size);
}
}
or via overload/tag dispatching
std::string maxNumber(std::string list[], int size) {
auto less_by_size = [](const auto& lhs, const auto rhs){
return lhs.size() < rhs.size(); };
return *std::max_element(list, list + size, less_by_size);
}
template<typename U>
U maxNumber(U list[], int size) {
return *std::max_element(list, list + size);
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I am running into a few errors, a memory error with the back function and failing to pass many of the tests that the program checks for.
I need to get this code working, which is in Vector.cpp:
#include <stdexcept>
#include "Vector.h"
using namespace std;
void Vector::grow()
{
const int GROWER = 1.6;
capacity = capacity * GROWER;
}
Vector::Vector()
{
capacity = CHUNK;
n_elems = 0;
data_ptr = new int[capacity];
for (size_t i = 0; i < capacity; i++)
{
data_ptr[i] = 0;
}
}
Vector::Vector(const Vector& v)
{
n_elems = 0;
capacity = v.capacity;
data_ptr = new int[capacity];
for (size_t i = 0; i < capacity; i++)
{
data_ptr[i] = v.data_ptr[i];
n_elems++;
}
}
Vector& Vector::operator=(const Vector& v)
{
capacity = v.capacity;
data_ptr = new int[capacity];
for (size_t i = 0; i < capacity; i++)
{
data_ptr[i] = v.data_ptr[i];
}
return *this;
}
Vector::~Vector()
{
delete[] data_ptr;
}
int Vector::front() const
{
if (n_elems != 0)
{
return data_ptr[0];
}
else
{
return -1;
throw range_error("Range Error");
}
}
int Vector::back() const
{
if (n_elems != 0)
{
return data_ptr[n_elems - 1];
}
else
{
throw range_error("Range Error");
}
}
int Vector::at(size_t pos) const
{
if (pos >= 0 && pos < capacity)
{
return data_ptr[pos];
}
else
{
throw range_error("Range Error");
}
}
size_t Vector::size() const
{
return n_elems;
}
bool Vector::empty() const
{
if (n_elems == 0)
{
return true;
}
else
{
return false;
}
}
int& Vector::operator[](size_t pos)
{
return data_ptr[pos];
}
void Vector::push_back(int item)
{
grow();
data_ptr[n_elems - 1] = item;
}
void Vector::pop_back()
{
if (n_elems >= 0)
{
--n_elems;
}
else
{
throw range_error("Range Error");
}
}
void Vector::erase(size_t pos)
{
if (pos >= 0 && pos < capacity)
{
for (size_t i = pos; i < capacity; i++)
{
data_ptr[i] = data_ptr[i + 1];
}
n_elems--;
}
else
{
throw range_error("Range Error");
}
}
void Vector::insert(size_t pos, int item)
{
int moveCount = n_elems - pos;
grow();
if (pos >= 0 && pos < capacity)
{
for (size_t i = n_elems; i >= 0; i--)
{
data_ptr[i] = data_ptr[i - 1];
}
data_ptr[pos] = item;
n_elems++;
}
else
{
throw range_error("Range Error");
}
}
void Vector::clear()
{
n_elems = 0;
}
int* Vector::begin()
{
if (n_elems == 0)
{
return nullptr;
}
else
{
return data_ptr;
}
}
int* Vector::end()
{
if (n_elems == 0)
{
return nullptr;
}
else
{
return (data_ptr + (n_elems - 1));
}
}
bool Vector::operator==(const Vector& v) const
{
bool flag = true;
for (size_t i = 0; i < capacity; i++)
{
if (data_ptr[i] == v.data_ptr[i])
{
flag = true;
}
else
{
flag = false;
break;
}
}
return flag;
}
bool Vector::operator!=(const Vector& v) const
{
bool flag = true;
for (size_t i = 0; i < capacity; i++)
{
if (data_ptr[i] != v.data_ptr[i])
{
flag = true;
}
else
{
flag = false;
break;
}
}
return flag;
}
To pass these tests, which are located in a file called testVector.cpp:
#include "Vector.h"
#include "test.h"
#include <stdexcept>
using namespace std;
int main() {
// Test exceptions
Vector v;
throw_(v.at(0), range_error);
throw_(v.pop_back(), range_error);
throw_(v.erase(0), range_error);
throw_(v.front(), range_error);
throw_(v.back(), range_error);
// Test adding an element
v.push_back(1);
test_(v.size() == 1);
test_(v.at(0) == 1);
test_(v[0] == 1);
test_(v.front() == 1);
test_(v.back() == 1);
test_(!v.empty());
// Add another
v.push_back(2);
test_(v.size() == 2);
test_(v.at(0) == 1);
test_(v.at(1) == 2);
test_(v[0] == 1);
test_(v[1] == 2);
test_(v.front() == 1);
test_(v.back() == 2);
test_(!v.empty());
// Test iterators
auto iter = v.begin();
test_(*iter == 1);
++iter;
test_(*iter == 2);
++iter;
test_(iter == v.end());
// Test copy and ==
Vector v2 = v;
test_(v2.size() == 2);
test_(v2.at(0) == 1);
test_(v2.at(1) == 2);
test_(v2[0] == 1);
test_(v2[1] == 2);
test_(v2.front() == 1);
test_(v2.back() == 2);
test_(!v2.empty());
test_(v == v2);
iter = v2.begin();
test_(*iter == 1);
++iter;
test_(*iter == 2);
++iter;
test_(iter == v2.end());
// Test assignment
Vector v3;
v3 = v;
test_(v3.size() == 2);
test_(v3.at(0) == 1);
test_(v3.at(1) == 2);
test_(v3[0] == 1);
test_(v3[1] == 2);
test_(v3.front() == 1);
test_(v3.back() == 2);
test_(!v3.empty());
//iter = v3.begin();
//test_(*iter == 1);
//++iter;
//test_(*iter == 2);
//++iter;
//test_(iter == v3.end());
// Test assignment
v[1] = -2;
test_(v.back() == -2);
test_(v.at(1) == -2);
test_(v[1] == -2);
// Test pop_back
v.pop_back();
test_(v.size() == 1);
test_(v.front() == 1);
test_(v.back() == 1);
test_(v.at(0) == 1);
test_(v[0] == 1);
// Test clear and !=
v.clear();
test_(v.size() == 0);
test_(v.empty());
throw_(v.at(0), range_error);
throw_(v.pop_back(), range_error);
throw_(v.erase(0), range_error);
throw_(v.front(), range_error);
throw_(v.back(), range_error);
test_(v != v2);
// Test erase
v3.erase(0);
test_(v3.size() == 1);
test_(v3.at(0) == 2);
test_(v3[0] == 2);
test_(v3.front() == 2);
test_(v3.back() == 2);
// Test insert
//v3.insert(0,1);
test_(v3.size() == 2);
test_(v3.at(0) == 1);
test_(v3[0] == 1);
test_(v3[1] == 2);
test_(v3.front() == 1);
test_(v3.back() == 2);
// Test grow
Vector v4;
for (int i = 1; i <= 10; ++i)
v4.push_back(i);
test_(v4.size() == 10);
test_(v4.front() == 1);
test_(v4.back() == 10);
v4.insert(10,11);
test_(v4.size() == 11);
test_(v4.front() == 1);
test_(v4.back() == 11);
report_();
}
push_back() and insert() both call grow(), which fails to increase the capacity because GROWER is an int, so 1.6 truncates to 1, and multiplying capacity * 1 doesn't change its value. But even if capacity were increased properly, the data_ptr array is not being re-allocated at all to fit the new capacity.
But even if grow() were working properly, there is no need to call grow() on every insertion of a new element, that defeats the purpose of separating n_elems from capacity to begin with. You should grow the array only when n_elems has reached capacity.
There are many other problems with your class, as well:
operator= is not testing for self-assignment, and is leaking the allocated memory of the old array. Consider using the copy-swap idiom instead.
front() does not reach the throw statement when the array is empty.
at() and erase() are performing bounds checking using capacity instead of n_elems.
push_back() is inserting the new value at the wrong index, and not incrementing n_elems.
pop_back() does not throw an error when the array is empty, causing n_elems to decrement below 0, which wraps around to the max positive value of size_t because size_t is unsigned.
erase() and operator== go out of bounds while iterating the array.
begin() and end() should not be returning nullptr for an empty array. And end() is returning a pointer to the last element in a non-empty array rather than returning a pointer to 1 past the last element.
operator== and operator!= do not perform any bounds checking to make sure the 2 vectors have the same same n_elems before iterating their arrays. And they are comparing element values beyond n_elems. Also, operator!= is returning the wrong result.
With that said, try something more like this:
#include <stdexcept>
#include <algorithm>
#include "Vector.h"
void Vector::grow()
{
static const float GROWER = 1.6f;
size_t new_capacity = capacity * GROWER;
if (new_capacity <= capacity)
throw std::overflow_error("cant grow capacity");
int *new_data_ptr = new int[new_capacity];
std::copy(data_ptr, data_ptr + n_elems, new_data_ptr);
delete[] data_ptr;
data_ptr = new_data_ptr;
capacity = new_capacity;
}
Vector::Vector()
{
capacity = CHUNK;
n_elems = 0;
data_ptr = new int[capacity];
}
Vector::Vector(const Vector& v)
{
capacity = v.capacity;
n_elems = v.n_elems;
data_ptr = new int[capacity];
std::copy(v.begin(), v.end(), data_ptr);
}
Vector& Vector::operator=(const Vector& v)
{
if (this != &v)
{
Vector temp(v);
std::swap(capacity, temp.capacity);
std::swap(n_elems, temp.n_elems);
std::swap(data_ptr, temp.data_ptr);
}
return *this;
}
Vector::~Vector()
{
delete[] data_ptr;
}
int Vector::front() const
{
if (n_elems == 0)
throw std::range_error("Range Error");
return data_ptr[0];
}
int Vector::back() const
{
if (n_elems == 0)
throw std::range_error("Range Error");
return data_ptr[n_elems - 1];
}
int Vector::at(size_t pos) const
{
if (pos >= n_elems)
throw std::range_error("Range Error");
return data_ptr[pos];
}
size_t Vector::size() const
{
return n_elems;
}
bool Vector::empty() const
{
return (n_elems == 0);
}
int& Vector::operator[](size_t pos)
{
return data_ptr[pos];
}
void Vector::push_back(int item)
{
if (n_elems == capacity)
grow();
data_ptr[n_elems] = item;
++n_elems;
}
void Vector::pop_back()
{
if (n_elems == 0)
throw std::range_error("Range Error");
--n_elems;
}
void Vector::erase(size_t pos)
{
if (pos >= n_elems)
throw std::range_error("Range Error");
std::copy(data_ptr + pos + 1, data_ptr + n_elems, data_ptr + pos);
--n_elems;
}
void Vector::insert(size_t pos, int item)
{
if (pos > n_elems) // insert at end() is OK...
throw range_error("Range Error");
if (n_elems == capacity)
grow();
std::copy_backward(data_ptr + pos, data_ptr + n_elems, data_ptr + n_elems + 1);
data_ptr[pos] = item;
++n_elems;
}
void Vector::clear()
{
n_elems = 0;
}
int* Vector::begin()
{
return data_ptr;
}
int* Vector::end()
{
return data_ptr + n_elems;
}
bool Vector::operator==(const Vector& v) const
{
return (n_elems == v.n_elems) && std::equal(v.begin(), v.end(), data_ptr);
}
bool Vector::operator!=(const Vector& v) const
{
return !(*this == v);
}
Your'e missing declaration of vector here, but I can surmize its structure. First mistake you doing here:
const int GROWER = 1.6;
capacity = capacity * GROWER; // it will never change
Reallocation doesn't happen, where it is? You just call upon dietis of Undefined Behaviour.
You either have to make GROWER float or increment size by fixed size. Also it's very unusual for a vector to grow geometrically. And very ineffective to grow on each push_back. Instead you have to have a CAPACITY and ALLOCATED SIZE. Latter may be greater and would grow if push_back would increase capacity outside of its limits. You apparently have a number of elements n_elems there, but you ignore it?
Many of those are doing too much extra work and don't do what they should.
Like this could actually be
data_ptr = new int[capacity] {}; // value initialization
//for (size_t i = 0; i < capacity; i++)
//{
// data_ptr[i] = 0;
//}
Use initialization lists, not side effects. Or you may lose them. Copy constructor also doesn't take in account n_elems of v and may copy garbage, converting it into new elements.
Comparisons simply wrong, because vectors can have different capacity. E.g.
bool Vector::operator==(const Vector& v) const
{
// check here if either of vectors is empty,
// if both are empty, they are equal?
// if their capacities are unequal, vectors are not equal. Those are shortcuts
// capacities are same
for (size_t i = 0; i < capacity; i++ )
if (data_ptr[i] != v.data_ptr[i])
return false;
return true;
}
I am writing a BigBinaryString class in C++ which abstractly holds the large binary string and can perform operations like xor, and, left shift and right shift.
I have stored the binary string internally as a vector of unsigned longs, so each element in vector consumes 64-bits from the bitstring.
I have decided to use have four types of constructors:
BigBinaryString(const string bitstring) //for directly converting the bitstring to internal repr.
BigBinaryString() //initialize the binary string to 0.
BigBinaryString(const size_t num) //hold the binary for corresponding unsigned long.
BigBinaryString(const vector<size_t> vec) //Directly pass the internal repr to the constructor for it to copy.
So far I have implemented and, xor, equality and left shift operators.
However, I feel the left shift operator has a very high time complexity in which the way I have implemented it.
So, I need a few suggestions on how to speed up the left shift operator so that I can implement the right shift efficiently as well.
The code so far is as follows:
#define SIZE_UNSIGNED_LONG (sizeof(size_t) * 8)
class BigBinaryString {
private:
vector<size_t> num;
void reduce() {
while (*num.rbegin() == 0) {
num.pop_back();
}
if (num.size() == 0) {
num.push_back(0);
}
}
public:
BigBinaryString() { num.push_back(0); }
BigBinaryString(const size_t n) { num.push_back(n); }
BigBinaryString(const vector<size_t> vec) {
const size_t length = vec.size();
for (size_t i = 0; i < length; i++) {
num.push_back(vec.at(i));
}
reduce();
}
BigBinaryString operator&(const BigBinaryString& op) {
vector<size_t> vec;
size_t maxlen = max(num.size(), op.num.size());
size_t minlen = min(num.size(), op.num.size());
const size_t zero = 0;
for (size_t i = 0; i < minlen; i++) {
vec.push_back(num.at(i) & op.num.at(i));
}
return BigBinaryString(vec);
}
BigBinaryString(const string bitstring) {
string temp = bitstring;
size_t dec = 0;
while (temp.length() != 0) {
if (temp.length() > SIZE_UNSIGNED_LONG) {
dec = stoul(temp.substr(temp.length() - SIZE_UNSIGNED_LONG,
SIZE_UNSIGNED_LONG),
nullptr, 2);
temp = temp.substr(0, temp.length() - SIZE_UNSIGNED_LONG);
} else {
dec = stoul(temp, nullptr, 2);
temp = "";
}
num.push_back(dec);
}
reduce();
}
BigBinaryString operator^(const BigBinaryString& op) {
vector<size_t> vec;
size_t maxlen = max(num.size(), op.num.size());
size_t minlen = min(num.size(), op.num.size());
for (size_t i = 0; i < maxlen; i++) {
if (i < minlen) {
vec.push_back(num.at(i) ^ op.num.at(i));
} else if (maxlen == num.size()) {
vec.push_back(num.at(i));
} else if (maxlen == op.num.size()) {
vec.push_back(op.num.at(i));
}
}
return BigBinaryString(vec);
}
bool operator==(const BigBinaryString& op) {
if (num.size() != op.num.size()) {
return false;
}
size_t length = num.size();
for (size_t i = 0; i < length; i++) {
if (num.at(i) != op.num.at(i)) {
return false;
}
}
return true;
}
bool operator==(const size_t n) {
BigBinaryString op(n);
if (num.size() != op.num.size()) {
return false;
}
size_t length = num.size();
for (size_t i = 0; i < length; i++) {
if (num.at(i) != op.num.at(i)) {
return false;
}
}
return true;
}
bool operator!=(const BigBinaryString& op) { return not(*this == op); }
bool operator!=(const size_t op) { return not(*this == op); }
BigBinaryString operator<<(size_t shift) {
string bitstring = this->to_string();
bitstring.append(shift, '0');
return BigBinaryString(bitstring);
}
string to_string() {
string suffix = "";
string retval = "";
string prefix = "";
size_t n = 0;
for (auto i = num.rbegin(); i != num.rend(); i++) {
n = *i;
prefix.clear();
suffix.clear();
while (n != 0) {
suffix = (n % 2 == 0 ? "0" : "1") + suffix;
n /= 2;
}
if (i != num.rbegin()) {
prefix.append(SIZE_UNSIGNED_LONG - suffix.size(), '0');
}
prefix = prefix + suffix;
if (prefix.size() == SIZE_UNSIGNED_LONG) {
retval += prefix;
} else if (i == num.rbegin()) {
retval += prefix;
} else if (i != num.rbegin()) {
throw invalid_argument("prefix+suffix error");
}
}
return retval;
}
};
Any help will be appreciated!
I've been trying to understand what havn't I initialized in this code and I completely(?) understand what is uninitialized but I don't know how to initialize it.
I am getting the error:
==11931== Conditional jump or move depends on uninitialised value(s)
==11931== at 0x804ABA6: Hashtable<int>::put(int, int) (hash_table.h:169)
==11931== by 0x8048F80: test_put() (hash_table_test.cpp:27)
==11931== by 0x804A551: main (hash_table_test.cpp:52)
==11931== Uninitialised value was created by a heap allocation
==11931== at 0x402ADFC: operator new[](unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==11931== by 0x804A9AE: Hashtable<int>::Hashtable() (hash_table.h:64)
==11931== by 0x8048F62: test_put() (hash_table_test.cpp:26)
==11931== by 0x804A551: main (hash_table_test.cpp:52)
from the valgrind so apparantly I havn't been initializing correctly the c'tor for Hashtable class:
Hashtable() :
ht_keys(2), ht_size(0), dynamicArray(NULL) {
dynamicArray = new Node[ht_keys];
for (int i = 0; i < ht_keys; i++) {
dynamicArray[i].delete_val = false;
dynamicArray[i].key=0;
dynamicArray[i].default_node = false;
}
}
the dynamic array is of type Node* which it's private fields are:
bool delete_val;
T element;
int key;
bool default_node;
the class Node is inside the class Hashtable.
how can I initialize dynamicArray?
here's the full code:
#include <string>
#include <iostream>
#include "library2.h"
#include <iterator>
using namespace std;
#ifndef HASH_TABLE_HPP_
#define HASH_TABLE_HPP_
#define DIV 2
//type T must have c'tor, operator !=
template<class T>
class Hashtable {
public:
class Node {
public:
Node(const T t) :
delete_val(false), element(t), key(0), default_node(true) {
}
Node(bool v, const Node& n) :
delete_val(v), element(n.element), key(0), default_node(
n.default_node) {
}
Node(const Node& n) :
delete_val(false), element(n.element), key(n.key), default_node(
n.default_node) {
}
Node() :
delete_val(false), key(0), default_node(true) {
}
bool operator==(const Node* n) {
if (n) {
if (element != n->element || default_node != n->default_node) {
return false;
}
return true;
}
return false;
}
bool operator!=(const Node n) {
if (!(*this == n)) {
return false;
}
return true;
}
bool delete_val;
T element;
int key;
bool default_node;
};
Hashtable() :
ht_keys(2), ht_size(0), dynamicArray(NULL) {
dynamicArray = new Node[ht_keys];
for (int i = 0; i < ht_keys; i++) {
dynamicArray[i].delete_val = false;
dynamicArray[i].key=0;
dynamicArray[i].default_node = false;
}
}
//seriously damaged programming...
Hashtable(Node* array, int HT_keys, int HT_size) :
ht_keys(HT_keys), ht_size(HT_size) {
dynamicArray = new Node[ht_keys];
if (array != NULL) {
for (int i = 0; i < ht_keys; i++) {
dynamicArray[i] = array[i];
}
}
}
Hashtable(const Hashtable& ht) {
if (&ht == this) {
return;
}
ht_keys = ht.ht_keys;
ht_size = ht.ht_size;
dynamicArray = new Node[ht_keys];
for (int i = 0; i < ht.ht_keys; i++) {
this->dynamicArray[i] = ht.dynamicArray[i];
}
}
~Hashtable() {
delete[] this->dynamicArray;
}
Hashtable operator=(const Hashtable& ht) {
Hashtable<T> newHT = ht;
return newHT;
}
//Returns true if some value equal to value exists within the hash table.
bool contains(Node n, int i) {
if (i < 0 || i > ht_keys || !n) {
return false;
}
if (i == ht_keys) {
return false;
}
//make sure that n.delete_val is not set as true.
if (dynamicArray[i]->element == n.element
&& !dynamicArray[i]->delete_val) {
return true;
}
if (dynamicArray[i]->delete_val) {
return contains(n, i + 1);
}
return false;
return true;
}
//Returns true if some key equal to key exists within the hash table.
bool containsKey(int i) {
if (i < 0 || i > ht_keys) {
return false;
}
if (dynamicArray[i]->element && !dynamicArray[i]->delete_val) {
return true;
}
return false;
}
//Returns true if some value equal to value exists within the hash table.
bool containsValue(T e) {
return true;
}
//Returns an enumeration of the values contained in the hash table.
int enumeration() {
return ht_size;
}
//Returns the object that contains the value associated with key.
//If key is not in the hash table, a null object is returned.
Node get(int i) {
if (i >= 0) {
return dynamicArray[i % ht_keys];
}
Node n;
return n;
}
//Returns true if the hash table is empty;
//returns false if it contains at least one key.
bool isEmpty() {
if (ht_size) {
return false;
}
return true;
}
//Returns an enumeration of the keys contained in the hash table.
int keys();
//Inserts a key and a value into the hash table.
//Returns false if key isn't already in the hash table;
//returns true if key is already in the hash table.
bool put(T e, int i) {
if (e && i > 0) {
Node n;
n.default_node = false;
n.delete_val = false;
n.key = i;
n.element = e;
//line 168
for (int j = (i % ht_keys); j < ht_keys; j = ((j + 1) % ht_keys)) { //line 169
if (!dynamicArray[j % ht_keys].element
|| dynamicArray[j % ht_keys].delete_val) {
dynamicArray[j % ht_keys] = n;
ht_size++;
return true;
}else if (i == (j + 1) % ht_keys) {
rehash();
return put(e, i);
}
}
return false;
}
return false;
}
bool put_aux(Node n, int i, Node* Array, int HT_keys) {
for (int j = (i % HT_keys); j < HT_keys; j = ((j + 1) % HT_keys)) {
if (!Array[j % HT_keys].element || Array[j % HT_keys].delete_val) {
Array[j % HT_keys] = n;
return true;
} else if (Array[j % HT_keys].element == n.element) {
return true;
}
}
return false;
}
//Increases the size of the hash table and rehashes all of its keys.
void rehash() {
int old_ht_keys = ht_keys;
ht_keys = DIV * ht_keys;
Node* newArray = new Node[ht_keys];
if (ht_keys > DIV) {
for (int j = 0; j < old_ht_keys; j++) {
put_aux(dynamicArray[j],dynamicArray[j].key,newArray,ht_keys);
}
}
delete[] dynamicArray;
dynamicArray = newArray;
}
//Removes key and its value.
//Returns the value associated with key.
//If key is not in the hash table, a null objecht_sizet is returned.
T remove(int i) {
if (i >= 0 && i < ht_keys) {
Node deleted_node(true, dynamicArray[i % ht_keys]);
dynamicArray[i % ht_keys] = deleted_node;
ht_size--;
return deleted_node.element;
}
return NULL;
}
//Returns the number of entries in the hash table.
int size() {
return this->ht_size;
}
private:
int ht_keys;
int ht_size;
Node* dynamicArray;
};
#endif /* HASH_TABLE_HPP_ */
It seems to be complaining about the line !dynamicArray[j % ht_keys].element (on line 163 of the code you posted; this would be a lot easier if the code you posted matched the code valgrind was using; right now the code you posted is several lines shorter than the code valgrind is using).
You never initialize the element member when you allocate the memory in the constructor. You then attempt to use it here in a conditional statement. valgrind correctly warns you of the problem.
Here's the code :
The place where it crashed is marked with a comment(//////crash).
I don't know what results in the problem.
After I print the size of data got from file,It shows '1' means that the array should only contains 1 element. So it seems that there's no 'bad_allocate error' ...
Could you guys help me ? I would appreciate your kindly help very much. :)
#include<stdio.h>
#include<iostream>
#include<string>
#include<map>
#include<vector>
#include<algorithm>
#include<string.h>
#include<type_traits>
using namespace std;
bool read_int(int& val,FILE*& fp)
{
if(fp == nullptr)
return false;
fread(&val,sizeof(int),1,fp);
return true;
}
bool write_int(int val,FILE*& fp)
{
if(fp == nullptr)
{
return false;
}
fwrite(&val,sizeof(int),1,fp);
return true;
}
struct SANOBJ
{
char path[128];
char nickname[40];
SANOBJ(const char* _p = nullptr,const char* _n = nullptr)
{
if(_p == nullptr || _n == nullptr)
*this = {};
int m = strlen(_p),n = strlen(_n);
if(m < 128) strcpy(path,_p);
if(n < 40) strcpy(nickname,_n);
}
~SANOBJ(){}
SANOBJ(const SANOBJ& other)
{
memcpy(path,other.path,sizeof(char) * 128);
memcpy(nickname,other.nickname,sizeof(char) * 40);
}
bool operator < (const SANOBJ& other) const
{
return string(path) < string(other.path);
}
bool operator == (const SANOBJ& other) const
{
return (strcmp(other.path,path) == 0);
}
};
template <typename source_type> //the 'source_type' type need to have the member 'int m_index'
class FrameQueue
{
public:
FrameQueue() //fill the 1st frame automatically
{
source_type new_node;
new_node.m_index = 0;
m_data.push_back(new_node);
}
FrameQueue(const FrameQueue& other)
{
m_data = other.m_data;
}
bool AddFrame(const source_type& other) // keeps an ascending order
{
int index = _binary_search(other);
if(index != -1)
{
return false;
}
m_data.insert(std::upper_bound(m_data.begin(),m_data.end(),other,
[](const source_type& a,const source_type& b)->bool const{return a.m_index < b.m_index;}
),other);
return true;
}
bool DeleteFrameByElemIndex(int elemIndex) //delete frame according to the index of frame in the queue
{
if(elemIndex < 0)
return false;
if(elemIndex >= m_data.size())
return false;
typename std::vector<source_type>::iterator it ;
it = m_data.begin() + elemIndex;
it = m_data.erase(it);
return true;
}
bool DeleteFrameByFrameIndex(int frameIndex)
{
source_type node = {};
node.m_index = frameIndex;
int index = _binary_search(node);
if(index == -1)
{
return false;
}
typename std::vector<source_type>::iterator it;
it = m_data.begin() + index;
it = m_data.erase(it);
return true;
}
bool Clear() // There would always be a single frame
{
source_type new_node = {};
new_node.m_index = 0;
m_data.clear();
m_data.push_back(new_node);
return true;
}
bool WriteFile(FILE*& fp)
{
if(fp == nullptr)
return false;
bool result = write_int(m_data.size(),fp);
if(result == false)
return false;
fwrite(&(m_data[0]),sizeof(source_type),m_data.size(),fp);
return true;
}
bool ReadFile(FILE*& fp)
{
if(fp == nullptr)
return false;
int data_size;
bool result = read_int(data_size,fp);
if(result == false)
return false;
if(data_size > 0)
{
m_data.resize(data_size);
fread(&(m_data[0]),sizeof(source_type),data_size,fp);
}
return true;
}
private:
int _binary_search(source_type target)
{
int l = 0,r = (int)m_data.size() - 1,mid;
while(l<=r)
{
mid = (l + r) / 2;
if(m_data[l].m_index == target.m_index)
{
return l;
}
if(m_data[r].m_index == target.m_index)
{
return r;
}
if(m_data[mid].m_index == target.m_index)
{
return mid;
}
if(m_data[mid].m_index > target.m_index)
{
r = mid - 1;
}
else
{
l = mid + 1;
}
}
return -1;
}
public:
vector<source_type> m_data;
};
template<typename source_type>
class UniqueSource
{
public:
UniqueSource(){}
~UniqueSource(){}
bool Add(const source_type& other)//return false when insert failed,otherwise return true
{
if(m_map_source_to_index.find(other) == m_map_source_to_index.end())
{
int map_size = m_map_source_to_index.size();
m_data.push_back(other);
m_map_source_to_index.insert(pair<source_type,int>(other,map_size));
m_result.push_back(map_size);
return true;
}
else
{
m_result.push_back(m_map_source_to_index[other]);
return true;
}
return false;
}
bool Delete(int elemIndex) // delete the elem by elem Index,If succeed ,return true,otherwise return false
{
if(elemIndex < 0)
return false;
if(elemIndex >= m_data.size())
return false;
typename std::map<source_type,int>::iterator mit;
typename std::vector<source_type>::iterator vit;
for(mit = m_map_source_to_index.begin();mit!=m_map_source_to_index.end();++mit)
{
m_map_source_to_index.erase(mit);
}
vit = m_data.begin() + elemIndex;
m_data.erase(vit);
return true;
}
bool Clear()
{
m_map_source_to_index.clear();
m_data.clear();
m_result.clear();
return true;
}
bool WriteFile(FILE*& fp)
{
if(fp == nullptr)
return false;
bool result = write_int(m_data.size(),fp);
if(result == false)
return false;
if(m_data.size() > 0)
fwrite(&(m_data[0]),sizeof(source_type),m_data.size(),fp);
result = write_int(m_result.size(),fp);
if(result == false)
return false;
if(m_result.size() > 0)
fwrite(&(m_result[0]),sizeof(int),m_result.size(),fp);
return true;
}
bool ReadFile(FILE*& fp)
{
if(fp == nullptr)
return false;
Clear();
int data_size;
read_int(data_size,fp);
if(data_size > 0)
{
printf("[%d]",data_size);
m_data.resize(data_size); /////////////////Crash!!!!!!!!!!!!
printf("Resize Ok\r\n");
fread(&(m_data[0]),sizeof(source_type),data_size,fp);
}
read_int(data_size,fp);
printf("[%d]",data_size);
if(data_size > 0)
{
m_result.resize(data_size);
fread(&(m_result[0]),sizeof(int),data_size,fp);
}
return true;
}
//private:
map<source_type,int> m_map_source_to_index;
vector<source_type> m_data;
vector<int> m_result; //the index I want
};
int main()
{
UniqueSource<SANOBJ> m;
SANOBJ t = {"123","456"};
m.Add(t);
printf("Added\r\n");
FILE* fp = nullptr;
fp = fopen("test.b","wb");
if(fp == nullptr)
{
printf("Failed...\r\n");
}
bool ret = false;
ret = m.WriteFile(fp);
if(ret)
{
printf("Writed!\r\n");
fclose(fp);
}
fp = fopen("test.b","rb");
if(fp == nullptr)
{
printf("Failed...\r\n");
}
ret = m.ReadFile(fp);
fclose(fp);
printf("Readed\r\n");
for(int i=0;i<m.m_data.size();i++)
printf("%s %s\r\n",m.m_data[i].path,m.m_data[i].nickname);
return 0;
}
*this = {} default-constructs a new SANOBJ instance and then assigns it to *this. This would normally be OK, but here you are calling it from the SANOBJ default constructor (making the logic being something like "to default-construct a SANOBJ, default-construct a SANOBJ and then assign its value to myself"), leading to infinite recursion and eventually a stack overflow.
Sidenote: The copy constructor is not needed.
Yes. The problem is is with *this = {}
If I were you, I'd rewrite SANOBJ constructor like this (this is a rough code and you may need to slightly modify it if you wish)
SANOBJ(const char* _p = nullptr,const char* _n = nullptr)
{
if (( _p != nullptr ) && ((strlen(_p) < 128)))
strcpy(path,_p);
if (( _n != nullptr ) && ((strlen(_n) < 40)))
strcpy(nickname,_n);
}
It'll resolve the problem.
Naturally, I don't play with *this (not this).
If you want to be sure that the member variables are empty (char path[128] and char nickname[40])
set at the beginning of the constructor something like:
path[0] = '\0';
nickname[0] = '\0';
Or use something like on constructor:
SANOBJ(const char* _p = nullptr,const char* _n = nullptr)
: path(), nickname()
{
}
But don't use *this= {}