I'm trying to reverse a string using stacks. It correctly reverses the string, but the for loop crashes when i reaches 0. I get a "string subscript out of range" error. Currently the for loop only decrements to 1. How can I get it to push and display s1[0]?
This is the main code:
#include <cstdlib> // Provides EXIT_SUCCESS
#include <iostream> // Provides cin, cout
#include <stack> // Provides stack
#include <string> // Provides string
using namespace std;
. . .
string reverse(string & s1)
{
stack<char> stk1;
string::size_type i;
// this for loop sets the rest of the characters
for (i = s1.size() - 1; i > 0; i--)
{
stk1.push(s1[i]);
cout << stk1.top();
}
return "The function was a success. Now that's what I call reverse psychology.";
}
This is the header file:
#ifndef MAIN_SAVITCH_STACK1_H
#define MAIN_SAVITCH_STACK1_H
#include <cstdlib> // Provides size_t
namespace main_savitch_7A
{
template <class Item>
class stack
{
public:
// TYPEDEFS AND MEMBER CONSTANT -- See Appendix E if this fails to compile.
typedef std::size_t size_type;
typedef Item value_type;
static const size_type CAPACITY = 30;
// CONSTRUCTOR
stack( ) { used = 0; }
// MODIFICATION MEMBER FUNCTIONS
void push(const Item& entry);
void pop( );
// CONSTANT MEMBER FUNCTIONS
bool empty( ) const { return (used == 0); }
size_type size( ) const { return used; }
Item top( ) const;
private:
Item data[CAPACITY]; // Partially filled array
size_type used; // How much of array is being used
};
}
#include "stack1.template" // Include the implementation.
#endif
And this is the stack implementation (a template file):
#include <cassert> // Provides assert
namespace main_savitch_7A
{
template <class Item>
const typename stack<Item>::size_type stack<Item>::CAPACITY;
template <class Item>
void stack<Item>::push(const Item& entry)
// Library facilities used: cassert
{
assert(size( ) < CAPACITY);
data[used] = entry;
++used;
}
template <class Item>
void stack<Item>::pop( )
// Library facilities used: cassert
{
assert(!empty( ));
--used;
}
template <class Item>
Item stack<Item>::top( ) const
// Library facilities used: cassert
{
assert(!empty( ));
return data[used-1];
}
}
I want to change the for loop to this, but it doesn't work:
// this for loop sets the rest of the characters
for (i = s1.size() - 1; i >= 0; i--) // i > -1 doesn't work either
{
stk1.push(s1[i]);
cout << stk1.top();
}
cout << s1[0] << "\n\n";
return "The function was a success. Now that's what I call reverse psychology.";
}
I can think of the following couple of options.
Using the string::size_type for the loop counter:
string::size_type i;
for (i = s1.size(); i > 0; i--)
{
stk1.push(s1[i-1]);
cout << stk1.top();
}
or
Using an int for the loop counter:
int i = 0;
for (i = s1.size()-1; i >= 0; i--)
{
stk1.push(s1[i]);
cout << stk1.top();
}
i is unsigned so it wraps around when it is decremented if it is equal to 0. You need to use a signed type for it or to check the boundary condition without involving negative numbers(that is, do not compare it with -1 and do not decrement it if it is 0).
Related
#include<iostream>
using namespace std;
void reverse(int arr[],int n){
int start=0,end=n-1;
int temp;
while(start<=end){
temp=arr[end];
arr[end]=arr[start];
arr[start]=temp;
}
start++;
end--;
}
void print(int arr[],int n){
for(int i=0;i<n;i++){
cout<<arr;
}
cout<<endl;
}
int main(){
int arr[5]={1,2,3,4,5};
int brr[6]={3,6,8,2,1,0};
reverse(arr,5);
reverse(brr,6);
print(arr,5);
print(brr,6);
}
I am not able to run this code at any compiler, can anyone tell me where I am making the mistake
after running it I am getting nothing
I am not to happy about the material that is teaching you C++.
For one it still uses "C" style arrays, and it is learning you to write
using namespace std; which will lead to problems (name clashes) in big projects. So if you have a teacher tell him about this.
Here is a more C++ oriented example :
#include <algorithm>
#include <iostream>
#include <vector>
// Using namespace std; <-- No unlearn this
// don't use "C" style arrays, use std::array or std::vector
// "C" style arrays are inherently more "buggy" to use.
// for one it easy to get mismatch array size and the size you pass.
void reverse(std::vector<int>& values)
{
//std::reverse(values.begin(), values.end()); C++ has this out of the box for you
std::size_t left_pos = 0ul;
std::size_t right_pos = values.size() - 1; // last index in array
/// manually, you start with first and last element and swap them
// then move left position one to the right, and right position one to the left
// repeat until left_pos and right_pos cross.
for (; left_pos < right_pos; ++left_pos, --right_pos)
{
// c++ has a swap method to swap values
std::swap(values[left_pos], values[right_pos]);
}
}
// prints the content of the vector
std::ostream& operator<<(std::ostream& os, const std::vector<int>& values)
{
bool print_comma{ false };
for (const int value : values)
{
if (print_comma) std::cout << ",";
std::cout << value;
print_comma = true;
}
std::cout << "\n";
return os;
}
int main()
{
std::vector<int> arr1{ 1,2,3,4,5 };
reverse(arr1);
std::cout << arr1;
return 0;
}
Just for your information: I would recommend you to just use std::reverse() for the concrete example. Also, do not use raw arrays.
#include <algorithm>
#include <iostream>
template <typename T>
void print(const T& arr) {
for (auto &value: arr) {
std::cout << value << " ";
}
std::cout << "\n";
}
int main(){
std::array arr={1,2,3,4,5}; // Or just use a std::vector
std::array brr={3,6,8,2,1,0};
std::reverse(arr.begin(), arr.end());
std::reverse(brr.begin(), brr.end());
print(arr);
print(brr);
}
I want an array that have new attributed values if the value is x.
I can do that in PHP with that code:
$test = array(1=>55, 2=>66);
on above code if test[0] = 1, the new value of test[0] is going to be 55.
I want to do that in C++.
Normal C++ arrays do not have keys. There are always 0-indexed.
But we have std::map which is what PHP also use internally for key-based containers.
https://en.cppreference.com/w/cpp/container/map
You can make your own attributed values class in C++, so it has that behavior.
You can make it so the behavior is hard coded into the class. Or if you want to get fancier you can make the class having a value mapping passed in.
Here's an example with the value mapping passed into the class.
#include <cstddef>
#include <iostream>
#include <map>
#include <stdexcept>
#include <vector>
using sad_panda = std::logic_error;
using std::cout;
using std::map;
using std::size_t;
using std::vector;
namespace {
class AttributedValues {
vector<int> v;
map<int, int> attr_to_value;
public:
AttributedValues(map<int, int> mapping);
void set(size_t index, int value);
int operator[](size_t index) const;
};
AttributedValues::AttributedValues(map<int, int> mapping)
: attr_to_value{mapping}
{ }
void AttributedValues::set(size_t index, int value) {
if (index >= v.size()) {
v.resize(index+1);
}
auto iter = attr_to_value.find(value);
if (iter != attr_to_value.end()) {
value = iter->second;
}
v[index] = value;
}
int AttributedValues::operator[](size_t index) const {
if (index >= v.size()) {
throw sad_panda("AttributedValues::operator[] index out of range");
}
return v[index];
}
} // anon
int main() {
auto test = AttributedValues{{{1, 55}, {2, 66}}};
test.set(0, 1);
test.set(10, 2);
cout << test[0] << "\n";
cout << test[10] << "\n";
}
I am trying to run binary_search on vector of custom objects.
struct T{
string name;
T(string n):name(n){};
bool operator < ( T * n ) const {
return name < n -> name;
}
bool operator == ( T * n ) const {
return name == n -> name;
}
};
vector<T *> t;
t.push_back(new T("one"));
t.push_back(new T("two"));
t.push_back(new T("three"));
bool has_3 = binary_search( t.begin(), t.end(), new T("two") ) ;
if( has_3 ){
cout <<"Its there" << endl;
}
The comparation function should be just fine yet when i run the code has_3 equals to 0 = the element isnt present in vector. Is this problem caused by my overloading of < ? I see no reason why this shouldnt find the value. Considering the order of insertion into vector it should be sorted
Thanks for help.
There are several reasons why this shouldn't find the value:
The range must be sorted; your range is out of alphabetical order
Your comparison functionality is defined between T and T*, while you search a vector of T* for a T*.
You can fix the first problem by swapping "two" and "three", and the second problem by making a vector of T:
struct T{
string name;
T(string n):name(n){};
bool operator < ( const T &n ) const {
return name < n.name;
}
// operator == is not necessary for binary_search
};
int main() {
vector<T> t;
t.push_back(T("one"));
t.push_back(T("three"));
t.push_back(T("two"));
bool has_3 = binary_search( t.begin(), t.end(), T("two") ) ;
if( has_3 ){
cout <<"Its there" << endl;
}
return 0;
}
Demo 1.
If you do have no way but to construct a vector of pointers, you have this ugly work-around available (I strongly recommend against it):
struct T{
string name;
T(string n):name(n){};
};
bool operator < (const T& l, const T *r) {
return l.name < r->name;
}
bool operator < (const T *l, const T &r) {
return l->name < r.name;
}
Now you can search like this:
bool has_3 = binary_search( t.begin(), t.end(), T("two") ) ;
if( has_3 ){
cout <<"Its there" << endl;
}
Demo 2.
It's a really dumb requirement to work with a vector of pointers to dynamically allocated objects. But here is an approach that will work.
#include <iostream>
#include <string>
#include <algorithm>
struct T
{
std::string name;
T(std::string n):name(n){};
};
// this is the comparater needed to work with pointers, but it should
// NOT be a member of T
bool pointer_comparer(const T *left, const T *right)
{
// this assumes both left and right point to valid objects
return left->name < right->name;
}
int main()
{
std::vector<T *> t;
t.push_back(new T("one"));
t.push_back(new T("two"));
t.push_back(new T("three"));
// t is unsorted. We need to sort it since binary_search will
// ASSUME it is sorted
std::sort(t.begin(), t.end(), pointer_comparer);
T *value_needed = new T("two");
bool has_3 = std::binary_search( t.begin(), t.end(), value_needed, pointer_comparer);
if(has_3)
{
std::cout <<"Its there" << std::endl;
}
// since we've been stupidly allocating objects, we need to release them
delete value_needed;
for (std::vector<T *>::iterator i = t.begin(), end = t.end();
i != end; ++i)
{
delete (*i);
}
// and since t now contains a set of dangling pointers, we need to discard them too
t.resize(0);
return 0;
}
Why do I say the requirement to work with a vector of pointers to dynamically allocated objects. Compare the above with an approach that works with a vector<T> rather than a vector<T *>.
#include <iostream>
#include <string>
#include <algorithm>
struct T
{
std::string name;
T(std::string n):name(n){};
bool operator < (const T &) const
{
return name < n.name;
};
};
int main()
{
std::vector<T> t;
t.push_back(T("one"));
t.push_back(T("two"));
t.push_back(T("three"));
// t is unsorted. We need to sort it since binary_search will
// ASSUME it is sorted
std::sort(t.begin(), t.end());
bool has_3 = std::binary_search(t.begin(), t.end(), T("two"));
if(has_3)
{
std::cout <<"Its there" << std::endl;
}
// we need do nothing here. All objects use above will be properly released
return 0;
}
Note: I've written the above so it works with ALL C++ standards. Assuming C++11 and later, simplifications are possible in both cases.
I'm trying to keep a vector of commands so that it keeps 10 most recent. I have a push_back and a pop_back, but how do I delete the oldest without shifting everything in a for loop? Is erase the only way to do this?
Use std::deque which is a vector-like container that's good at removal and insertion at both ends.
If you're amenable to using boost, I'd recommend looking at circular_buffer, which deals with this exact problem extremely efficiently (it avoids moving elements around unnecessarily, and instead just manipulates a couple of pointers):
// Create a circular buffer with a capacity for 3 integers.
boost::circular_buffer<int> cb(3);
// Insert threee elements into the buffer.
cb.push_back(1);
cb.push_back(2);
cb.push_back(3);
cb.push_back(4);
cb.push_back(5);
The last two ops simply overwrite the elements of the first two.
Write a wrapper around a vector to give yourself a circular buffer. Something like this:
include <vector>
/**
Circular vector wrapper
When the vector is full, old data is overwritten
*/
class cCircularVector
{
public:
// An iterator that points to the physical begining of the vector
typedef std::vector< short >::iterator iterator;
iterator begin() { return myVector.begin(); }
iterator end() { return myVector.end(); }
// The size ( capacity ) of the vector
int size() { return (int) myVector.size(); }
void clear() { myVector.clear(); next = 0; }
void resize( int s ) { myVector.resize( s ); }
// Constructor, specifying the capacity
cCircularVector( int capacity )
: next( 0 )
{
myVector.resize( capacity );
}
// Add new data, over-writing oldest if full
void push_back( short v )
{
myVector[ next] = v;
advance();
}
int getNext()
{
return next;
}
private:
std::vector< short > myVector;
int next;
void advance()
{
next++;
if( next == (int)myVector.size() )
next = 0;
}
};
What about something like this:
http://ideone.com/SLSNpc
Note: It's just a base, you still need to work a bit on it. The idea is that it's easy to use because it has it's own iterator, which will give you the output you want. As you can see the last value inserted is the one shown first, which I'm guessing is what you want.
#include <iostream>
#include <vector>
template<class T, size_t MaxSize>
class TopN
{
public:
void push_back(T v)
{
if (m_vector.size() < MaxSize)
m_vector.push_back(v);
else
m_vector[m_pos] = v;
if (++m_pos == MaxSize)
m_pos = 0;
}
class DummyIterator
{
public:
TopN &r; // a direct reference to our boss.
int p, m; // m: how many elements we can pull from vector, p: position of the cursor.
DummyIterator(TopN& t) : r(t), p(t.m_pos), m(t.m_vector.size()){}
operator bool() const { return (m > 0); }
T& operator *()
{
static T e = 0; // this could be removed
if (m <= 0) // if someone tries to extract data from an empty vector
return e; // instead of throwing an error, we return a dummy value
m--;
if (--p < 0)
p = MaxSize - 1;
return r.m_vector[p];
}
};
decltype(auto) begin() { return m_vector.begin(); }
decltype(auto) end() { return m_vector.end(); }
DummyIterator get_dummy_iterator()
{
return DummyIterator(*this);
}
private:
std::vector<T> m_vector;
int m_pos = 0;
};
template<typename T, size_t S>
void show(TopN<T,S>& t)
{
for (auto it = t.get_dummy_iterator(); it; )
std::cout << *it << '\t';
std::cout << std::endl;
};
int main(int argc, char* argv[])
{
TopN<int,10> top10;
for (int i = 1; i <= 10; i++)
top10.push_back(5 * i);
show(top10);
top10.push_back(60);
show(top10);
top10.push_back(65);
show(top10);
return 0;
}
Let us assume I have different functions accessing a single String str (getting a single character of it) and I want to loop through this string with every access...how could I achieve this?
For example:
string str = "abc";
function1(); // returns "a"
function2(); // returns "b"
function3(); // returns "c"
function4(); // returns "a" again
function2(); // returns "b" again
...
So basically I have different functions accessing this string str and I need some kind of iterator which gets back to the first character of str if the end of str is reached.
If you really want to use an iterator instead of indexing, you could use a cyclic_iterator, something like this:
#ifndef CYCLIC_ITERATOR_H_INC_
#define CYCLIC_ITERATOR_H_INC_
#include <iterator>
template <class FwdIt>
class cyclic_iterator_t : public std::iterator<std::input_iterator_tag, typename FwdIt::value_type> {
FwdIt begin;
FwdIt end;
FwdIt current;
public:
cyclic_iterator_t(FwdIt begin, FwdIt end) : begin(begin), end(end), current(begin) {}
cyclic_iterator_t operator++() {
if (++current == end)
current = begin;
return *this;
}
typename FwdIt::value_type operator *() const { return *current; }
};
template <class Container>
cyclic_iterator_t<typename Container::iterator> cyclic_iterator(Container &c) {
return cyclic_iterator_t<typename Container::iterator>(c.begin(), c.end());
}
#endif
This is quite minimal as iterators go--for example, it currently only supports pre-increment, not post-increment (and it's a forward iterator, so about all you can do with the iterator is increment it and dereference it).
Nonetheless, for the job you envision, it seems to be adequate.
I would just index out of the string using the % modulus operator. This will get you the wraparound behavior you want.
#include <iostream>
#include <string>
int main()
{
std::string str = "abc";
for (int i = 0; i < 10; ++i)
{
std::cout << str[i % str.size()] << " ";
}
}
Output
a b c a b c a b c a
I don't know how many times you need this to work, but here you are(You can edit it to fit with your needs):
#include <iostream>
#include <string>
int main()
{
std::string str = "abc";
bool bAgain = true;
int Max = str.length() + 1;
for(int i = 0; i < Max; i++)
{
std::cout << str[i] << "\n";
if(bAgain)
{
if(i == Max - 1)
{
i = -1;
bAgain = false;
continue;
}
}
}
}
`
Output
a
b
c
a
b
c