I am working on a lab assignment where the user inputs a string and a starting and stopping point for a substring within the string to be reversed. For example, if a user inputs the string "go bobcats", and the numbers 3 (for starting index) and 7 (for ending index), the output should be "go acbobts". I was able to write a recursive function that reverses an entire string ("go bobcats" becomes "stacbob og"), but I am having trouble with the substring aspect.
code for full string reverse:
void reversing(string s, int start, int end){
if(s.size() == 0){return;}
else{
reversing(s.substr(1), start + 1, end);
cout << s[0];
}
}
For the starting and ending index for this I just entered 0 and 9 because that would be the full length of the string.
How can I adjust the function so that it only reverses the string starting and ending at the indexes the user inputs? Also, with my current function I have to use an endl in the main to make a new line at the end of the output of the string. Is there a way I can do this inside the function? If I put an endl after cout << s[0]; it puts in a new line after each iteration making the output vertical:
s
t
a
c
b
o
b
o
g
Implementation in main:
string s;
int start, end;
cout << "Enter a string: ";
while(cin.peek() == '\n' || cin.peek() == '\r'){
cin.ignore();
}
getline(cin,s);
cout << "Now enter two numbers that are within the bounds of the string. ";
cin >> start >> end;
cout << "This is how your words look now:\n";
reversing(s,start,end);
cout << endl;
A function to reverse the string can swap the elements at both ends of the range and decrease the range by one on both sides.
void reversing(string& s, int start, int end) {
if (start >= end)
return;
swap(s[start], s[end]);
reversing(s, start + 1, end - 1);
}
And then inside main():
// ...
cout << "This is how your words look now:\n";
reversing(s, start, end);
cout << s << endl;
Sometimes it is sad to see how C++ is used to teach everything but not C++. The following is sort of an experiment to see if we can somehow approach std::reverse (the algorithm you should actually use) by actually ignoring the requirements of your homework and doing small digestable steps.
Lets start with a small variation on the solution presented in this answer. Instead of passing the string together with indices we can use iterators. In a nutshell, iterators are the glue between algorithms and data structures, more specifically container. They can refer to elements in a container, just like an index or pointer can do.
void reversing2(std::string::iterator first, std::string::iterator last) {
if (first >= last) return;
std::swap(*first,*last);
reversing2(++first,--last);
}
Iterators can be dereferenced like pointers to get a reference to the element (*first and *last). RandomAccessIterators can be incremented (++first), decremented (--last) and be compared (first >= last), just like you would do it with indices.
The next step is a difficult one, because it requires even more handwaving. Note that apart from the function signature nothing in the above function actually depends on first and last being iterators for elements in a std::string. For example to reverse a subarray of an int[] only the signature would have to change:
void reversing2(int* first, int* last) {
if (first >= last) return;
std::swap(*first,*last);
reversing2(++first,--last);
}
That makes a nice opportunity to get in touch with templates. I know that I am commiting a small crime here, because I cannot give a thorough intro, but will only present you a very narrow case. To make the same code usable for different containers we just have to modify it a little
template <typename IT>
void reversing(IT first,IT last) {
if (first >= last) return;
std::swap(*first,*last);
reversing(++first,--last);
}
This can now be called with any RandomAccessIterator. So this:
#include <string>
#include <iostream>
int main() {
std::string s{"Hello world"};
std::cout << s << '\n';
reversing2(s.begin()+3,s.begin()+7); // pass iterators to 4th and 8th character
std::cout << s << '\n';
reversing(s.begin()+3,s.begin()+7);
std::cout << s << '\n';
int x[]= {1,2,3,4,5,6};
reversing(&x[2],&x[5]); // pointers are iterators too
for (const auto e : x) std::cout << e;
}
Will produce this output:
Hello world
Helow olrld
Hello world
126543
Eventually, and this was the whole motivation for the preceding, we can see that the reversing is quite similar to std::reverse. Of course std::reverse is not recursive and there is one small caveat: standard algorithms typically work on half-open intervals, ie a range made from two iterators first and last where first is included in the interval, but last is one past the last element in the interval. Hence to get the same result, you would have to call it with the second iterator one position further than with the above function:
std::reverse(s.begin()+3,s.begin()+8); // pass iterators to 4th and one past the 8th character
Complete online example
In your function declaration the type of the first parameter is not a referenced type. So the function deals with a copy of an original string passed to the function as an argument.
However in any case your recursive function definition is invalid. At least there is no need to extract a sub-string.
Pay attention to that the second and the third parameters of the function should have the type std::string::size_type. Otherwise the user can supply a negative values for the parameters when they have the type int and the function will have undefined behavior.
Also it is better when the function returns reference to the reversed string itself.
In fact within the function you need to use only one check that the start position is less than the end position.
Here is a demonstrative program that shows how the function can be defined.
#include <iostream>
#include <string>
std::string & reversing( std::string &s, std::string::size_type start, std::string::size_type end )
{
if ( not s.empty() )
{
if ( not ( end < s.size() ) ) end = s.size() - 1;
if ( start < end )
{
std::swap( s[start], s[end] );
reversing( s, start + 1, end - 1 );
}
}
return s;
}
int main()
{
std::string s( "Hello bobaloogie" );
std::cout << s << '\n';
std::cout << reversing( s, 0, 4 ) << '\n';
std::cout << reversing( s, 6, s.size() ) << '\n';
return 0;
}
The program output is
Hello bobaloogie
olleH bobaloogie
olleH eigoolabob
well i also have a solution but without implementing library function just to give you a feel of implementation and it's pretty simple.
adjusting your function - swap the start and last position recursively instead of doing
exhaustively .
endl in the main - if you wish to save the answer in input string only then yes you have to do that in main . Else just before returning from function put 'endl '.
My code goes like this.
#include<bits/stdc++.h>
using namespace std;
void rev(string &str,int s,int l){ // s = start l = last
if(l<s) return ; // base condition when l precedes s
else {
char temp = str[s];
str[s] = str[l];
str[l] = temp;
rev(str,++s,--l);
}
return ;
}
int main(){
string str;
int s,l;
getline(cin,str);
cin>>s>>l;
assert(s<str.size() && l<str.size());
rev(str,s,l);
cout<<str;
}
There are different way to approach this problem, the greedy one is to use substring to pass the exact string to the reverse function:
void reversing(string s){
if(s.size() == 0){return;}
else{
reversing(s.substr(1));
cout << s[0];
}
}
void main(string s, int start, int end) {
string substring = reversing(s.substr(start, end - start + 1));
cout << s.substr(0, start) + substring + s.substr(end + 1);
}
else you need to edit your function that reverse to edit the string only when in such range
void reversing(string s, int start, int end, int index = 0, string output = ""){
if(s.length() == index){return output;}
else{
if (index >= start && index <= end) {
output = output + s[end - (index - start)];
} else {
output += s[index];
}
reversing(s, start, end, index+1, output);
cout << output[output.length()-1];
}
}
I'm trying to get a vector of string from input to create a graph , but i don't know why in middle my code it crashes. please help me fix it. I use Visual Studio.
#include <iostream>
#include <vector>
#include <iterator>
void main(void)
{
{
using namespace std;
int8_t n{ 0 };
cout << "enter the size of graph : ";
cin >> n;
vector<string> graph(n);
string connectionsWith;
vector<string>::iterator i;
string::iterator e;
int p{ 0 };
for (i = graph.begin(); i != graph.end(); ++i)
{
cout << '\n' << "enter the vertices that are connected to " << p << " : ";
cin >> connectionsWith;
graph.push_back(connectionsWith);
p++;
}
p = 0;
for (i = graph.begin(); i != graph.end(); ++i)
{
cout << p << " is connected to " << *i;
p++;
}
}
}
In your constructor of graph, you allocate n string. Inside the loop you add on top of the constructed n strings, n more strings via push back. That potentially invalidates your iterators, as ChrisMM said, also not the most efficient way to implement such a scenario.
So as a solution, instead of
vector<string> graph(n);
do
vector<string> graph;
graph.reserve(n);
and iterate over the index, e.g. from 0 to n, and push back.
Especially in the first loop you are not dereferencing the iterator at all, which suggests that using index based loop would show your intent better.
life_steal pointed out the problem. I would like to add few information and other way to solve the problem.
int8_t n{ 0 };
vector<string> graph(n); // Here initialization happening with ASCII. If input is "1" then it would be "49". Consider changing int8_t to int if you unaware of that.
graph.push_back(connectionsWith); //Instead of this line Use: *i = connectionsWith; it directly assign the value.
This code shows this SIGSEGV error, which I understand, is a segmentation error. Can someone please help!
The code returns the count of distinct case-insensitive alphabetic characters and numeric digits that occur more than once in the input string.
I am using this on a programming challenge so this is only a function.
So, If I input "aabcdef" it should return 2 because 'a' occurs twice. Input can contain alphabets as well as numerics.
int duplicateCount(const char* in)
{
int a[39]={0},b=0;
for(int i=0;i<strlen(in);i++)
{
if(in == NULL)
return 0;
if((int)in[i] < 97)
{
a[(int)in[i]]++;
}
a[tolower(in[i])-'a'+1]++;
}
for(int i=0;i<39;i++)
{
if(a[i]>1)
b++;
}
return b;
}
Problem is here
if((int)in[i] < 97)
{
a[(int)in[i]]++;
}
a[tolower(in[i])-'a'+1]++;
you may write outside of bounds which, as we know, has UB.
Fix
First you have to check if character is letter with isalpha(c)
Then you have to transform character to lower via tolower(c)
And sub the first low case letter in alphabet c - 'a'
Then you can index an array and increment its value.
Here is fixed code
Since we are in c++, you may use std::map
#include <iostream>
#include <map>
int main()
{
std::string text("aabbc");
std::map<char, int> letterCounter;
for(auto& it : text)
{
letterCounter[it]++;
}
for (auto& it : letterCounter)
{
if (it.second > 1)
{
std::cout << "Character " << it.first << " has appeared "
<< it.second << " times." << std::endl;
}
}
return 0;
}
Output
Character a has appeared 2 times.
Character b has appeared 2 times.
I'm trying to make a program that contiues to randomly generate a string of letters, but stop when it has generated a word the user have entered.
I have made it generate the letters but I don't know how to make it recognize a word from it.
for (int i = 1; i < 1000; i++) {
int n = rand() % 26;
char c = (char)(n + 65);
cout << c;
}
return 0;
I'm gonna change the for loop to a while loop when I know how to make it find the users input.
I'm very new to programming so the solution is most likely obvious.
As one of the comments suggests, you need to create a string from your chars. After that, I would suggest looking at:
http://www.cplusplus.com/reference/string/string/find/
its a search function for strings used on other strings... which is exactly what you're looking for.
One of the comments also suggest using == to compare the string you created from chars and the user input string, but there isn't much use in doing it this way when the string::find function does the exact same thing but more efficently
A Modern C++ solution.
The interesting part in the main function which is below.
#include <random>
#include <iostream>
#include <algorithm>
#include <list>
#include <sstream>
void NotFoundMessage(std::list<char>& randomSequence);
void FoundMessage(long long iterationCount);
// Seed with a real random value, if available
std::random_device r;
std::default_random_engine e1(r());
// A random character between 'A' and 'Z'
std::uniform_int_distribution<int> uniform_dist('A', 'Z');
char nextRandomCharacter()
{
return static_cast<char>(uniform_dist(e1));
}
int main()
{
std::string input;
std::cin >> input;
// <--- NEEDS CHECKS IF INPUT IS CORRECT!!!!
std::list< char > randomSequence;
// Fill randomSequence with initial data
for ( const auto& c : input )
{
randomSequence.push_back( nextRandomCharacter() );
}
long long iterationCount = 1;
while ( !std::equal( input.begin(), input.end(),
randomSequence.begin() ) )
{
NotFoundMessage( randomSequence );
// remove character from front and add random char at end.
randomSequence.pop_front();
randomSequence.push_back( nextRandomCharacter() );
iterationCount++;
}
FoundMessage(iterationCount);
}
void NotFoundMessage(std::list<char>& randomSequence)
{
std::cout << "Not found in: ";
for ( const auto& c : randomSequence )
std::cout << c << ' ';
std::cout << '\n';
}
void FoundMessage(long long iterationCount)
{
std::cout << "Found after "
<< iterationCount
<< " iterations."
<< std::endl;
}
So I have a task to convert all occurrences of some word in one string to another string. But there is problem with condition of while loop which makes this error
terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::replace
This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information. Process returned 3 (0x3) execution time : 2.751 s
My code is:
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string str2("three");
string str("one three two four three three");
while ( str.find(str2) != NULL ){
str.replace(str.find(str2),str2.length(),"five");
cout << str << endl; // i put it inside loop to see output
}
cout << str << endl;
return 0;
}
Any suggestions?
You are checking if str.find(str2) had an occurrence comparing it to NULL, but this is wrong, because NULL is a macro that isn't meant for that and often expands into 0, which can be a valid index. You should compare it to std::string::npos. After doing this change, your code will work.
Edit : std::string::npos corresponds to 18446744073709551615 when testing on coliru. So that clearly isn't a valid index in your string.
This condition
while ( str.find(str2) != NULL ){
does not make sense because a call of find can return std::string::npos that is not equal to zero. In this case the code has undefined behavior.
You can apply the following approach
std::string str2("three");
std::string str("one three two four three three");
const char *five = "five";
size_t n = std::strlen(five);
for (std::string::size_type pos = 0;
( pos = str.find(str2, pos) ) != std::string::npos; pos += n)
{
str.replace(pos, str2.length(), five);
}
it's caused because str.find(str2) returns -1 if str2 is not existed in the str. You can use a variable pos to save the found position, so that you will not need to re-invoke find function. The solution is supposed as following:
#include <iostream>
#include <string>
using namespace std;
int main () {
string str2("three");
string str("one three two four three three");
int pos = str.find(str2);
while (pos > 0) {
str.replace(pos, str2.length(), "five");
pos = str.find(str2);
cout << str << endl; // i put it inside loop to see output
}
cout << str << endl;
return 0;
}