checking for spaces with c++ - c++

So I've looked around the site for someone having a similar issue but nothing has come up and it's really been perplexing me.
#include <iostream>
#include <string>
using namespace std;
string reverse(string s)
{
int start = 0;
for(int i = 0; i < s.length(); i++)
{
if(s[i]==' '){
string new_word = s.substr(start,i);
cout << new_word << endl;
start = i+1;
}
}
return "hi";
}
int main(){
cout << reverse("Hey there my name is am");
return 0;
}
When I run the tidbit of code above this is what I get as an output.
Hey
there my
my name is
name is am
is am
hi
as you can see the if condition doesn't seem to break on every space. I have also tried isspace(s[i]) and that produced the same result as above. I cannot for the life of me figure out why the if condition is getting skipped on certain white spaces and not others. Has anyone run into a similar issue?

Take a look at the reference of string::substr. It clearly states that len takes the number of characters to include in the substring. In your code you are passing the index of ' ' which is simply wrong because it does not correspond to len. Instead of using s.substr(start,i), simply use s.substr(start,i - start + 1). That should fix the problem.

Related

Why does my function not switch the first character with the last one of my string?

I picked up a challenge on r/dailyprogrammer on reddit which wants me to match a necklace and put the last letter at the beginning of a string. I've considered using nested for loops for this but this has made me really confused.
Instead I chose the way of replacing the last with the first character in an if-statement. But I am not getting my desired output with it, though I've tried everything what comes into my mind.
I used even std::swap() which didn't lead me to success either.
Here's the code:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
string same_necklace(string& sInput, string& sOutput)
{
for (string::size_type i = 0; i < sInput.size(); i++)
{
if (sInput[i] == sInput.size())
{
sInput[0] = sInput[sInput.size()];
}
}
for (string::size_type j = 0; j < sOutput.size(); j++)
{
if (sOutput[j] == sOutput.size() - 1)
{
sOutput[0] = sOutput[sOutput.size()];
}
}
return sInput, sOutput;
}
int main()
{
system("color 2");
string sName{ "" };
string sExpectedOutput{ "" };
cout << "Enter a name: ";
cin >> sName;
cout << "Enter expected output: ";
cin >> sExpectedOutput;
cout << "Result: " << same_necklace(sName , sExpectedOutput) << endl;
return 0;
}
And of course the link to my challenge (don't worry, it's just Reddit!):
https://www.reddit.com/r/dailyprogrammer/comments/ffxabb/20200309_challenge_383_easy_necklace_matching/
While I am waiting (hopefully) for a nice response, I will keep on trying to solve my problem.
In your if you compare the value of the current index (inside the loop) with the size of the string. Those are two unrelated things.
Also, you use a loop though you only want to do something on a single, previously known index.
for (string::size_type i = 0; i < sInput.size(); i++)
{
if (sInput[i] == sInput.size())
{
sInput[0] = sInput[sInput.size()];
}
}
You could change the if condition like this to achieve your goal:
if (i == sInput.size()-1) /* size as the index is one too high to be legal */
But what is sufficient and more elegant is to drop the if and the loop. completely
/* no loop for (string::size_type i = 0; i < sInput.size(); i++)
{ */
/* no if (sInput[i] == sInput.size())
{*/
sInput[0] = sInput[sInput.size()-1]; /* fix the index*/
/* }
} */
I.e.
sInput[0] = sInput[sInput.size()-1]; /* fix the index*/
Same for he output, though you got the correct index already correct there.
This is not intended to solve the challenge which you linked externally,
if you want that you need to describe the challenge completely and directly here.
I.e. this only fixes your code, according to the desription you provide here in the body of your question,
"put the last letter at the beginning of a string".
It does not "switch" or swap first and last. If you want that please find the code you recently wrote (surely, during your quest for learning programming) which swaps the value of two variables. Adapt that code to the two indexes (first and last, 0 and size-1) and it will do the swapping.
So much for the loops and ifs, but there is more wrong in your code.
This
return sInput, sOutput;
does not do what you expect. Read up on the , operator, the comma-operator.
Its result is the second of the two expressions, while the first one is only valuated for side effects.
This means that this
cout << "Result: " << same_necklace(sName , sExpectedOutput) << endl;
will only output the modified sExpectedOutput.
If you want to output both, the modified input and the modified output, then you can simply
cout << "Result: " << sName << " " << sExpectedOutput << endl;
because both have been given as reference to the function and hence both contain the changes the function made.
This also might not answer the challenge, but it explains your misunderstandings and you will be able to adapt to the challenge now.
You have not understand the problem i guess.
Here you need to compare two strings that can be made from neckless characters.
Lets say you have neckless four latters word is nose.
Combination is possible
1)nose
2)osen
3)seno
4)enos
your function (same_necklace) should be able to tell that these strings are belongs to same necklace
if you give any two strings as inputs to your function same_necklace
your function should return true.
if you give one input string from above group and second input string from other random word thats not belongs to above group, your function should return false.
In that sense, you just take your first string as neckless string and compare other string with all possible combination of first string.
just move move you first latter of first input string to end and then compare each resulting string to second input string.
below is the function which you can use
void swap_character(string &test)
{
int length = test.length();
test.insert(length, 1, test[0]);
test.erase(0, 1);
}

Justifying user input string into lines of equal length

So, full disclosure, I have just started learning C++ and this IS part of an assignment. I'm not looking for an answer, just a some guidance.
I'm looking to justify some text in the form of a string into lines of equal length. Both the text and line length are user-input.
What I've got so far is the code below. It works just fine to do the task at hand. I've thrown a bunch of text at it and it's always output the correct formatting for it. However, I am feeling as though I'm going at it the wrong way - the code feels clunky, as if I was forcing it to do something it wasn't designed to do (if you know what I mean).
Should I be looking (or is there) a more elegant way to do what I'm trying to do. I've considered setting up a 2D array of size [width][#lines] so that I can output it line by line. Would that be a preferable way to do things? Is there some sort of "Best Practice" when it comes to this stuff?
#include <iostream>
#include <string>
using namespace std;
int main()
{
string randtext;
string output;
int width;
// User input text string.
cout << "Enter a Random String of Text: " << endl;
getline(cin, randtext);
// User input line width.
cout << "Enter justification Width" << endl;
cin >> width;
int length = randtext.length();
int i = 0;
// This bit parses through the string.
while (i <= length)
{
// This bit creates lines of length = width.
for (int j = 0; j < width; ++j)
{
if (i + j > length) { break; }
char letter = randtext[i+j];
output += letter;
}
// This bit outputs the lines and then clears everything.
cout << output << endl;
output.clear();
i += width;
}
cin.get();
cin.get();
return 0;
}
Your current code has a bug: array indices are 0-based, meaning that 0 to length - 1 are valid, but length is not a valid index. If your goal is to split a string into fixed-sized chunks without any other conditions or constraints, you might consider using string::substr(). This would reduce the amount of code, and make things clearer.
But I'm wondering whether fixed-sized chunks is actually your goal? When I hear "justified" text, I think about text that has been word wrapped (i.e., split on word boundaries) and then spaces inserted so that the left and right edges of each line are aligned. Example:
The quick red fox jumped over the two lazy dogs.
Justified using 14-character line width:
The quick red
fox jumped
over the two
lazy dogs.
Firstly as far as I know there are no best practices. However I would suggest keeping it as simple as possible. I've used a similar approach to what you have done however I have instead inserted a new line character every width interval to the randtext string and then printed that. This dramatically reduces the code size and improves readability. I have tested this against your code and the output is exactly the same. The code is shown below.
#include <iostream>
#include <string>
#include <conio.h>
int main()
{
using namespace std;
string randtext;
int width;
// User input text string.
cout << "Enter a Random String of Text: " << endl;
getline(cin, randtext);
// User input line width.
cout << "Enter justification Width" << endl;
cin >> width;
// Insert a newline character every nth character given that n = width
for (size_t i = 0; i < randtext.length(); i+=width+1)
{
randtext.insert(i,"\n");
}
cout << randtext << endl;
cin.get();
cin.get();
return 0;
}
In case someone stumbles onto this in the future looking for an answer to a similar question, I ended up scrapping my previous code and used SUBSTR (as suggested by #cbranch)to chop up the text and fed it into a VECTOR as follows:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
string input = "The quick brown fox, jumps over the. Lazy dog. There is, no cow. LEVEL";
int width = 20;
int length = input.size();
int j = 0;
vector<string> input_vector (0);
// For loop that chops up the input using input.substr() and feeds it into a vector that re-sizes as needed.
for (int i = 0; i < length; i+=width)
{
// Dynamic vector resizing as needed.
input_vector.resize(j + 1);
string input_sub = input.substr(i, width);
input_vector[j] = input_sub;
j++;
}
int size_vector = input_vector.size();
// For loop that outputs the chopped out lines as elements of the vector.
for (int k = 0; k < size_vector; ++k)
{
cout << input_vector[k] << endl;
}
return 0;
}

Strange output from C++ in Linux Terminal

I've recently started learning programming using the C++ language. I wrote a simple program that is supposed to reverse a string which I compile in the Terminal using gcc/g++.
#include <iostream>
using namespace std;
string reverse_string(string str)
{
string newstring = "";
int index = -1;
while (str.length() != newstring.length())
{
newstring.append(1, str[index]);
index -= 1;
}
return newstring;
}
int main()
{
string x;
cout << "Type something: "; cin >> x;
string s = reverse_string(x);
cout << s << endl;
return 0;
}
I've rewritten it multiple times but I always get the same output:
Type something: banana
��
Has anyone had a problem like this or know how to fix it?
Your code initializes index to -1, and then uses str[index] but a negative index has no rational meaning in C++. Try instead initializing it like so:
index = str.length() - 1;
I can see several issues with your code. Firstly, you are initializing index to -1, and then decrementing it. Maybe you meant auto index = str.length()-1;?
I recommend you look at std::reverse, which will do the job you're after.
Your main function then becomes:
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int main()
{
string x;
cout << "Type something: ";
cin >> x;
reverse(x.begin(), x.end());
cout << x << endl;
return 0;
}
If you really want to write your own reverse function, I recommend iterators over array indices. See std::reverse_iterator for another approach.
Note, the above will simply reverse the order of bytes within the string. Whilst this is fine for ASCII, it will not work for multi-byte encodings, such as UTF-8.
You should use a memory debugger like valgrind.
It's a good practice to scan your binary with it, and will make you save so much time.

C++ in Xcode pausing

this is my first SO post.
I am very new to programming, and with C++ I thought I might try and make a program that allows the user to submits a block of text (max 500 characters), allows them to enter a 4 letter word and the program return with the amount of times it picks that word up in the text.
I am using X-code and it keeps making a green breakpoint and pausing the program at the 'for' loop function. my code is shown below:
#include <iostream>
#include <string>
#include <math.h>
#define SPACE ' '(char)
using namespace std;
//Submit text (maximum 500 characters) and store in variable
string text;
string textQuery(string msgText) {
do {
cout << msgText << endl;
getline(cin, text); } while (text.size() > 500);
return text;
}
//Query word to search for and store as variable
string word;
string wordQuery(string msgWord) {
cout << msgWord << endl;
cin >> word;
return word;
}
//Using loop, run through the text to identify the word
int counter = 0;
bool debugCheck = false;
int searchWord() {
for (int i = 0; i < text.size(); i++) {
char ch_1 = text.at(i);
char ch_2 = text.at(i + 1);
char ch_3 = text.at(i + 2);
char ch_4 = text.at(i + 3);
cout << i;
if(ch_1 == word.at(0) &&
ch_2 == word.at(1) &&
ch_3 == word.at(2) &&
ch_4 == word.at(3) )
{
counter++;
debugCheck = true;
}
}
return counter;
}
//cout the result
int main() {
string textUserSubmit = textQuery("Please submit text (max 500 characters): ");
string wordUserSubmit = wordQuery("Please select a word to search for: ");
int counterResponse = searchWord();
cout << debugCheck << endl;
cout << "The number of times is: " << counterResponse << endl;
return 0;
}
I get the error at the for loop. Any other advice about how i can make my program work for different words, multiple lengths of words and also how i can highlight the words in text would be helpful.
I really would appreciate if someone could aid me with my problem. Thanks!
I get the error at the for loop.
You should describe the error you get. I happen to have access to Xcode so I can run your code and see what happens, but you should try to spare that of people from whom you want help.
In this case you should describe how the debugger stops the program at the line:
char ch_4 = text.at(i + 3);
includes the message: "Thread 1: signal SIGABRT" and the console output shows
libc++abi.dylib: terminating with uncaught exception of type std::out_of_range: basic_string
Your problem is this: the for loop checks to make sure that i is in the correct range for the string text before using it as an index, but then you also use i+1, i+2, and i+3 as indices without checking that those values are also valid.
Fix that check and the program appears to run fine (given correct input).
Some miscellaneous comments.
Use more consistent indentation. It makes the program easier to read and follow. Here's how I would indent it (using the tool clang-format).
#define SPACE ' '(char) looks like a bad idea, even if you're not using it.
using namespace std; is usually frowned on, though as long as you don't put it in headers it usually won't cause too much trouble. I still could though, and because you probably won't understand the resulting error message you may want to avoid it anyway. If you really don't like writing std:: everywhere then use more limited applications such as using std::string; and using std::cout;.
global variables should be avoided, and you can do so here by simply passing textUserSubmit and wordUserSubmit to searchWord().
there's really no need to make sure text is less than or equal to 500 characters in length. You're using std::string, so it can hold much longer input.
You never check how long word is even though your code requires it to be at least 4 characters long. Fortunately you're using at() to index into it so you don't get undefined behavior, but you should still check. I'd remove the check in textQuery and add one to wordQuery.

Unique Lines and Words? How to implement it?

I'm having trouble with this program. The program is supposed to tell the user the number of lines, words, characters, unique lines, and unique words there are in a given input. So far, words and characters are okay. However, if the user wants to input more than one line, how do I do that? The functions will only output the results of one line at a time, rather than adding the results of both lines together. Also, I can't get the Unique Lines and Unique Words to work properly. I just got into C++ so I don't really have much experience. Can someone please help me?
Problems:
Program reads one line at a time, so when the user inputs multiple times, the program produces the results separately rather than adding it together as one entity.
Unique Lines and Unique Words are not working. Any ideas how to implement it using the library used in the program.
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include <string>
using std::string;
#include <set>
using std::set;
// write this function to help you out with the computation.
unsigned long countLines()
{
return 1;
}
unsigned long countWords(const string& s)
{
int nw =1;
for (size_t i = 0; i < s.size(); i++)
{
if (s[i] == ' ') //everytime the function encounters a whitespace, count increases by 1)//
{
nw++;
}
}
return nw;
}
unsigned long countChars(const string& s)
{
int nc = 0;
for (size_t i = 0; i < s.size(); i++)
{
if ( s[i] != ' ') //everytime the function encounters a character other than a whitespace, count increases//
{
nc++;
}
}
return nc;
}
unsigned long countUnLines(const string& s, set<string>& wl)
{
wl.insert(s);
return wl.size();
}
unsigned long countUnWords(const string& s, set<string>& wl)
{
int m1 = 0;
int m2 = 0;
string substring;
for(m2 = 0; m2 <= s.size(); m2++){
if (m2 != ' ' )
substring = s.substr(m1,m2);
wl.insert(substring);
m1 = m2 + 2;}
}
return wl.size();
int unw = 0;
wl.insert(s);
unw++;
return unw;
}
int main()
{
//stores string
string s;
//stores stats
unsigned long Lines = 0;
unsigned long Words = 0;
unsigned long Chars = 0;
unsigned long ULines = 0;
unsigned long UWords = 0;
//delcare sets
set<string> wl;
while(getline(cin,s))
{
Lines += countLines();
Words += countWords(s);
Chars += countChars(s);
ULines += countUnLines(s,wl);
UWords += countUnWords(s);
cout << Lines << endl;
cout << Words<< endl;
cout << Chars << endl;
cout << ULines << endl;
cout << UWords << endl;
Words = 0;
Chars = 0;
ULines = 0;
UWords = 0;
}
return 0;
}
You are resetting your count variables to zero at the end of your getline while loop. This is why you are only getting results for one line. The user can input multiple lines in your program as it is right now you are just resetting the count.
I think you're headed in the right direction. In order to count unique lines and words you're gonna have to store every line and word in a data structure of some kind, I'd suggest an unordered_map. Each element in the map you'll have a counter for # of occurences of each line/word.
I don't want to give the answer away wholesale, but here are some ideas to get you started.
The function getline() can read in an entire line of input. Do this until there's no more input.
You can use a container like std::set (or better, std::unordered_set) to store the lines read in. Not the most efficient, but it keeps track of all your lines, and only stores the unique ones.
Each line can then be broken down into words. Consider using something like std::stringstream for this.
Store the words in a different std::unordered_set.
The number of unique lines (words) is simply the number of lines (words) stored in the containers. Use the .size() method to obtain this.
Doing the total number of lines, words, and characters can be computed as you read the data in, so I won't go into much detail there.
Each item is googleable, and you may choose to implement different parts differently (if you don't want to use a stringstream, you can always iterate over the line read, for example.) This should get you on the right track.
It's pretty easy to get fairly accurate counts, but can be surprisingly difficult to get correct counts for all of this.
The big problem is the character count. If you open the file (as you usually would) in text mode, the number of characters you count may not match what the OS thinks is there. For the obvious examples, under Windows a CR/LF pair will be translated to a single new-line character, so you'll typically count each line as one character shorter than it really is.
Technically, there's no way to deal with that entirely correctly either -- the translation from external to internal representation when a file is opened in text mode is theoretically arbitrary. At least in theory, opening in binary mode doesn't help a lot either; in binary mode, you can have an arbitrary number of NUL characters after the end of the data that was written to the file.
The latter, however, is pretty much theoretical these days (it was allowed primarily because of CP/M, which most people have long forgotten).
To read lines, but retain the line-end delimiters intact, you can use std::cin.get() instead of std::getline(), then read the delimiters separately from the line itself.
That gives us something like this:
#include <iostream>
#include <set>
#include <string>
#include <iterator>
#include <sstream>
#include <fstream>
int main(int argc, char **argv) {
static char line[4096];
unsigned long chars = 0;
unsigned long words = 0;
unsigned long lines = 0;
std::set<std::string> unique_words;
std::ifstream in(argv[1], std::ios::binary);
while (in.get(line, sizeof(line), '\n')) {
++lines;
chars += strlen(line);
std::istringstream buffer(line);
std::string word;
while (buffer >> word) {
++words;
unique_words.insert(word);
}
while (in.peek() == '\n' || in.peek() == '\r') {
++chars;
in.ignore(1);
}
}
std::cout << "words: " << words << "\n"
<< "lines: " << lines << "\n"
<< "chars: " << chars << "\n"
<< "unique words: " << unique_words.size() << "\n";
}
Note that although this does answer that the OP actually asked at least for most typical OSes (Linux, *BSD, MacOS, Windows), it's probably not what he really wants. My guess is that his teacher isn't really asking for this level of care to try to get an accurate character count.
Also note that if you should encounter a line longer than the buffer, this can still give an inaccurate count of lines -- it'll count each buffer-full of data as a separate line, even if it didn't find a line-delimiter. That can be fixed as well, but it adds still more complexity to a program that's almost certainly already more complex than intended.