I'm pretty unfamiliar with string manipulation in C++ and I can't seem to wrap my head around how to select characters in strings. Below is my program so far. Whenever I run it, however, the program crashes and an error showing "Thread 1: EXC_BAD..." shows up (I'm working on Xcode). For some reason, simply using input[0] works if I want to print the first character from the string, but doesn't when I do input[x] in a loop.
#include <iostream>
#include <string>
int num, characterCount;
string currentChar, previousChar;
int main()
{
cout << "How many lines of input? \n";
cin >> num;
for (int x = 0; x < num; x++)
{
string input;
cin >> input;
previousChar = input[0];
currentChar = input[1];
characterCount = 0;
int y = 0;
while (currentChar != "")
{
y++;
if (previousChar == currentChar)
{
characterCount++;
}
else if (previousChar != currentchar && currentChar != "")
{
cout << characterCount << " " << previousChar;
characterCount = 0;
}
else if (currentChar == "")
{
cout << characterCount << " " << previousChar;
}
previousChar = currentChar;
currentChar = input[y];
}
}
return 0;
}
Btw I know my code's weird, I'm a beginner in C++. If you have any helpful suggestions feel free to comment!
previousChar = input[0];
currentChar = input[1];
If an empty string was entered, there is no input[0] and there is no input[1], so this becomes undefined behavior.
Your overall problem is checking, incorrectly, when the end of the string has been reached. The shown code attempts to extract a character at each position, place this character into a std::string of its own, and then compare it to an empty string.
This is not the right way to do that. This eventually results in undefined behavior, too, and a likely crash. std::strings have a size() method that give the number of characters in the string, so in your case:
input.size()
gives the number of characters in the string. Which can be 0. Then, you can iterate over each character of the string, and then implement your logic.
The reason you are getting the error is:
currentChar = input[y];
The problem with this line is that input[y] might be inaccessible, for instance your input is "Hello". With the way you wrote your code, y would eventually equals 5. However, you the last letter 'o' is input[4]. Because of that, when y=5, you get an error.
There are couple ways you could fix it. One has already mentioned using .size() to make sure, another one has mentioned using iterator:
for(auto iterator = input.begin();iterator!=input.end();++iterator)
However, what I want to mention is that you should be declaring your currentChar and previousChar as char type instead of string since they would always be single characters. Also, depends on the version of C++ and compiler you are using, if you are using C++11, input[5] on "Hello" is actually fine.
When you passed input[5] to a char currentChar type, currentChar gets a null character. So for you while loop, you could test while(currentChar). When currentChar gets the null character, the while loop would test false, and ends the loop.
Below is how I would change inside your for loop. Most of them stays the same, beside changing previousChar and currentChar into char type, and some condition checkings for them, with some minor changes to refine them.
#include <iostream>
#include <string>
int main() {
int num;
std::cout << "How many lines of input? \n";
std::cin >> num;
for (int x = 0; x < num; x++)
{
std::string input;
std::cin >> input;
char previousChar = input[0];
int y = 1;
char currentChar = input[y];
int characterCount = 1;
while(currentChar)
{
y++;
if (previousChar == currentChar)
{
characterCount++;
}
else
{
std::cout << characterCount << " " << previousChar << "\n";
characterCount = 1;
}
previousChar = currentChar;
currentChar = input[y];
}
std::cout << characterCount << " " << previousChar << "\n";
}
}
Also do note that it feels weird to use a while loop when it is iterating through a index number for me. So I would probably use a for loop instead of the while loop:
#include <iostream>
#include <string>
int main() {
int num;
std::cout << "How many lines of input? \n";
std::cin >> num;
for (int x = 0; x < num; x++)
{
std::string input;
std::cin >> input;
char previousChar = input[0];
int y = 1;
char currentChar = input[y];
int characterCount = 0;
for(int y = 1; currentChar; y++)
{
if (previousChar == currentChar)
{
characterCount++;
}
else
{
std::cout << characterCount << " " << previousChar << "\n";
characterCount = 1;
}
previousChar = currentChar;
currentChar = input[y];
}
std::cout << characterCount << " " << previousChar << "\n";
}
}
And here is how you could do it with iterator:
#include <iostream>
#include <string>
int main() {
int num;
std::cout << "How many lines of input? \n";
std::cin >> num;
for (int x = 0; x < num; x++)
{
std::string input;
std::cin >> input;
char previousChar, currentChar;
previousChar = input[0];
int characterCount = 1;
for(auto it = input.begin()+1; it != input.end();it++)
{
currentChar = *it;
if (previousChar == currentChar)
{
characterCount++;
}
else
{
std::cout << characterCount << " " << previousChar << "\n";
characterCount = 1;
}
previousChar = currentChar;
}
std::cout << characterCount << " " << previousChar << "\n";
}
}
From what I get by reading your code you are trying to print the number of duplicate characters. How I would go about doing this is as follows:
#include <iostream>
#include <string>
int num, characterCount;
int main()
{
std::cout << "How many lines of input? \n";
std::cin >> num;
for (int x = 0; x < num; x++)
{
characterCount=0;
std::string input;
std::cin >> input;
for(auto iterator = input.begin();iterator!=input.end();++iterator)
{
if(iterator == input.end()-1)
std::cout <<"Duplicates: " << characterCount
<< " " <<"Character: "<< *iterator << "\n";
else
{
if(*iterator == *std::next(iterator,1))
characterCount++;
else
{
std::cout <<"Duplicates: " << characterCount
<< " " <<"Character: "<< *iterator << "\n";
characterCount=0;
}
}
}
}
return 0;
}
First of all, you weren't using the std namespace. You need to use std:: like I did below before every call from that particular namespace or you can just using namespace std at the top of the file after the include directives.
Second of all I ditched your algorithm using previous character and current character in favour of an approach using iterators.. A string is a standard c++ container from the standard template library so we can use iterators to go over it (or a standard for loop if you so desire).
The code prints duplicates for each character in the string, much as you wanted to do I think.
Related
//EDIT
the code below works only in case that str1 has only 1 beginning letter of str2; how to fix it?
for ex. if str1 / 2 = overflow / flo it works.
but if str1 is overflowfabc (has two "f"s) --> it doesn't work
//
I need to check for a word in a string using simple loop. The idea is:
find an element in str1 that is equal to 1. element of str2
if it exists, we set flag = 1, and it remains 1 if following elements are also equal. If they are not, flag is set to 0.
.
#include <iostream>
using namespace std;
int main() {
string str1, str2;
int flag;
cout << "Enter a string 1: ";
getline(cin, str1);
cout << "Enter a string 2: ";
getline(cin, str2);
for(int i = 0; i < str1.size(); i++)
{
if (str1[i] == str2[0]) // find element in str1 that is equal to first element of str2
{
flag = 1; //
for(int j = i+1; j < i + str2.size(); j++)
if (str1[j] != str2[j-i]) // checking if following elements are also equal
{
flag = 0; // if any of them is not equal
break;
}
if (flag==1)
cout << "str2 is Substring of str1" ;
else
cout << "str2 is NOT Substring" ;
}
}
return 0;
}
bool isSubStr(const string& parent, const string& child)
{
// Check each starting position
for (int i=0; i<(parent.size()-child.size()+1); ++i)
{
// Check if the substring starts at this position
// TODO make this a helper method to avoid the need for a flag
bool isSubString = true;
for (int j=0; j<child.size(); ++j)
{
if (parent[i + j] != child[j])
{
isSubString = false;
break;
}
}
if (isSubString)
{
return true;
}
}
return false;
}
The string class in C++ contains a function named find, and in my opinion you should use that.
The documentation can be found here.
An excerpt about the Return value:
The position of the first character of the first match.If no matches
were found, the function returns string::npos.
#include <iostream>
using namespace std;
int main() {
string str1, str2;
cout << "Enter a string 1: ";
getline(cin, str1);
cout << "Enter a string 2: ";
getline(cin, str2);
size_t found = str1.find(str2);
if (found != string::npos)
cout << "str2 is Substring of str1" << endl;
else
cout << "str2 is NOT Substring" << endl;
return 0;
}
It is shorter and easier to understand. So why not going with that ?
Otherwise I believe your code is not correct in more than one aspect; e.g.
you print out the text depending on the flag variable within the for loop. This does not look right to me.
the second for loop looks strange to me. I believe you are trying to program something that you believe might be considered sophisticated and well thought. To be honest with you, I suggest that do not try to do that. Do simple and clear.
Following your comment I took the time to try to improve your code.
#include <iostream>
using namespace std;
int main() {
string str1, str2;
int flag = 0;
cout << "Enter a string 1: ";
getline(cin, str1);
cout << "Enter a string 2: ";
getline(cin, str2);
for(unsigned int i = 0; i < str1.size(); i++) {
if (str1[i] == str2[0]) { // find element in str1 that is equal to first element of str2
unsigned int j = 0;
for( ; j < str2.size(); j++) {
if ( str1[i+j] != str2[j] ) { // checking if following elements are also equal
break;
}
}
if ( j == str2.size() ) { // if j equals the size of substring then all chars seem equal
flag = 1;
break;
}
}
}
if ( flag )
cout << "str2 is Substring of str1" ;
else
cout << "str2 is NOT Substring" ;
return 0;
}
I wrote code to check the input, I set the HavePunct flag always false. However when I input hello,world!! it returns the wrong results to me. Please let me know if you see any problems with my code:
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main() {
string s,result_s;
char ch;
bool HavePunct = false;
int sLen = s.size();
cout << "Enter a string:" << endl;
getline(cin, s);
//检测字符串是否有符号
for (string::size_type i = 0;i != sLen; ++i) {
ch = s[i];
if (ispunct(ch)) {
HavePunct = true;
}
else
result_s += ch;
}
if (HavePunct) {
cout << "Result:" << result_s;
}
else {
cerr << "No punction in enter string!" << endl;
system("pause");
return -1;
}
system("pause");
return 0;
}
You are computing the length of the line before you enter any input. Hence, sLen is always zero. Move that line so it is after the line where you read the input.
cout << "Enter a string:" << endl;
getline(cin, s);
int sLen = s.size();
I cannot be sure, however it would seem because your iterator's upper bound is determined by the variable sLen, which you assign to be s.size() before you receive a string, therefore effectively making your upper bound 0 and causing your for loop never to execute.
Try this and let me know:
getline(cin, s);
int sLen = s.size();
for (string::size_type i = 0;i != sLen; ++i) {
ch = s[i];
if (ispunct(ch)) {
HavePunct = true;
}
else
result_s += ch;
}
I've tried so many times in different way to concatenate two strings, one way gives me segment fail,and the other way don't give me error but not it's making the correct function of concatenate. I need result is like this aa, what am I doing wrong?
#include <iostream>
using namespace std;
char str1[20], str2[20], str3[20];
void stringConcat(char[], char[], char[]);
void stringConcat(char str1[], char str2[], char str3[])
{
int i = 0, j = 0;
if (str1[i] != '\0') {
str3[i] = str1[i];
i++;
}
if (str2[j] != '\0') {
str3[i + j] = str2[j];
j++;
}
str3[i] = '\0';
}
int main()
{
int compare;
cout << "First string" << endl;
cin >> str1;
cout << "Second string" << endl;
cin >> str2;
stringConcat(str1, str2, str3);
cout << "result: " << str3 << endl;
return 0;
}
i am trying to print an array of unknown length backwards so wrote that the loop should start at the terminator and go to the first letter printing each letter but it keeps printing only the first
#include <iostream>
using namespace std;
int main()
{
char word[10];
int i;
cout << "Enter a word: " ;
cin >> word;
for ( word[i]= '\0'; word[1] <0; word[i] --)
{
cout << word[i] << endl;
}
return 0;
}
You can print you C-style string backwards whith this one-liner:
reverse_copy(word,word+strlen(word),ostream_iterator<char>(cout));
Also please consider using std::string:
string word;
cin >> word;
copy(word.rbegin(),word.rend(),ostream_iterator<char>(cout));
You will need to #include the following headers for the above examples to work:
<algorithm>, <iostream>, <iterator>, <string> and <cstring>
Replace your loop it does nothing:
for (i= strlen(word); i >=0; i--)
{
cout << word[i] << endl; //endl is optional
}
Also for in case of long strings you may have to increase size of char array or its better to use
string word;
for (i= word.size(); i >=0; i--)
{
cout << word[i] << endl; //endl is optional
}
Here is a simple way to print a C-style string backwards.
for (size_t i = 0, i_end = std::strlen(word); i != i_end; ++i)
{
std::cout << word[i_end - i - 1];
}
std::cout << "\n";
Note that I save the result of strlen so that it is not called every time.
To get the result you want, you might want to use this code...
char word[10];
int sz;
do {
cout << "Enter a word: ";
cin >> word;
sz = strlen(word);
} while (sz > 10);
for (int i = sz; i >= 0; i--)
{
cout << word[i];
}
This is my first program on C++. I successfully build it. When I run it, Windows keep giving me program is stop working, the same result that I try to run it with eclipse.
Here is my code:
#include <iostream>
#include <cmath>
#include <stdlib.h>
#include <vector>
using namespace std;
int main(){
string input;
vector<double> value;
int count = 0;
while(input != "#") {
cout << "Enter value " << count + 1 << "\n";
cin >> input;
cout << input;
if (input != "#") {
value[count] = atof(input.c_str());
}
count++;
}
cout << count;
double sum = 0;
for (int i = 0; i < count; i++) {
sum += value[i];
}
double ave = sum/count;
double dev = 0;
for (int i = 0; i < count; i++) {
dev += pow((value[i] - ave), 2);
}
dev = sqrt(dev / (count - 1));
cout << "\nThe average is " << ave << "\n";
cout << "The standard deviation is" << dev << "\n";
return 0;
}
Anyone has any idea? Thank you.
value[count] = atof(input.c_str());
is a problem since value does not have enough space in it. Use
value.push_back(atof(input.c_str()));
instead.
You also have a logic error in the while loop. count will be incremented even when the input is "#". I recommend changing it to:
while(true) {
cout << "Enter value " << count + 1 << "\n";
cin >> input;
cout << input;
if (input == "#") {
break;
}
value.push_back(atof(input.c_str()));
}
count = value.size();
I tried the code on other's computer. It works great. I think something goes wrong for my compiler.