This question already has answers here:
What is iterator invalidation?
(3 answers)
Iterator invalidation rules for C++ containers
(6 answers)
Closed 22 days ago.
what is the problem in this code?
string s; cin>>s;
s[0]=s[0]-32;
replace(s.begin(),s.end(),'s','$');
replace(s.begin(),s.end(),'i','!');
replace(s.begin(),s.end(),'o','(');
for (auto i = s.begin(); i != s.end(); ++i)
{
if (*i == '(')
{
s.insert(i + 1, ')');
}
}
s+=".";
cout<<s<<endl;
cd "/home/parvez/Documents/cds/" && g++ Better_Passwords.cpp -o Better_Passwords && "/home/parvez/Do[parvez#HPLP cds]$ cd "/home/parvez/Documents/cds/" && g++ Better_Passwords.cpp -o Better_Passwords && "/home/parvez/Documents/cds/"Better_Passwords
unsophisticated
Segmentation fault (core dumped)
You may not change the string in the for loop such a way
for (auto i = s.begin(); i != s.end(); ++i)
{
if (*i == '(')
{
s.insert(i + 1, ')');
}
}
because after inserting a character the iterator i can be invalid. You need to write for example like
for (auto i = s.begin(); i != s.end(); ++i)
{
if (*i == '(')
{
i = s.insert(i + 1, ')');
}
}
Related
Is there anyway I can optimize this function to take less times for strings with half a million characters?
for (int i = start; i <= end; i++) {
doc.body.push_back(html[i]);
if (html[i] == '<') {
if (html[i + 1] != '/') {
Tag newTag;
int start1 = html[i];
int end1;
for (int y = i; y <= end; y++) {
if (html[y] == '>') {
end1 = y;
break;
}
}
for (int y = start1 + 1; y <= end1; y++) {
if (html[y] == ' ' || html[y] == '>') {
break;
}
newTag.tagType.push_back(html[y]);
}
for (int y = start1; y <= end1; y++) {
newTag.openTag.push_back(html[y]);
}
if (newTag.tagType.find("area") != std::string::npos || newTag.tagType.find("base") != std::string::npos || newTag.tagType.find("br") != std::string::npos || newTag.tagType.find("col") != std::string::npos || newTag.tagType.find("command") != std::string::npos || newTag.tagType.find("embed") != std::string::npos || newTag.tagType.find("hr") != std::string::npos || newTag.tagType.find("img") != std::string::npos || newTag.tagType.find("input") != std::string::npos || newTag.tagType.find("keygen") != std::string::npos || newTag.tagType.find("link") != std::string::npos || newTag.tagType.find("meta") != std::string::npos || newTag.tagType.find("param") != std::string::npos || newTag.tagType.find("source") != std::string::npos || newTag.tagType.find("track") != std::string::npos || newTag.tagType.find("wbr") != std::string::npos) {
newTag.closeTag = "Null";
}
if (newTag.openTag.find("class=") != std::string::npos) {
int start1 = newTag.openTag.find("\"", newTag.openTag.find("class=")) + 1;
int end1 = newTag.openTag.find("\"", start1);
for (int y = start1; y < end1; y++) {
if (html[y] != ' ') {
newTag.tagClass.back().push_back(html[y]);
}
else {
newTag.tagClass.push_back("");
}
}
}
if (newTag.openTag.find("id=") != std::string::npos) {
int start1 = newTag.openTag.find("\"", newTag.openTag.find("id=")) + 1;
int end1 = newTag.openTag.find("\"", start1);
for (int y = start1; y < end1; y++) {
if (html[y] != ' ') {
newTag.tagID.back().push_back(html[y]);
}
else {
newTag.tagID.push_back("");
}
}
}
page.tags.push_back(newTag);
}
else {
int end1;
for (int y = i; y <= stringSize; y++) {
if (html[y] == '>') {
end1 = y;
break;
}
}
//gets everything within the closing tag
std::string storeClose;
for (int y = i; y <= end1; y++) {
storeClose.push_back(html[y]);
}
for (int y = page.tags.size() - 1; y >= 0; y--) {
if (storeClose.find(page.tags[y].tagType) != std::string::npos) {
page.tags[y].closeTag = storeClose;
}
}
}
}
}
I timed how long it took with the chrono library and it took 16 minutes for a string with the length of 300000 characters! This is supposed to be parsing a html document downloaded from the web and its mostly functional. For shorter pages its almost instant but as soon as I reach the higher number the time it takes its exponentially higher!
I answered already yesterday the same question.
But first. Please compile your source code with all warnings enabled. There are tons of compiler warnings that you must resolve.
Additionally: In my opinion you have a hard bug in line int start1 = html[i];. I guess this should be int start1 = i;
Then, because you did not create a minimum reproducable example, I stubbed your code to test it.
Then I copied the HTML source from this file from stackoverflow and copied it in a local file 4 times to get a file size of 1.9MByte.
Then I let it run on my machine in below 4 seconds (including reading the 2MByte) from disk.
I used the profiler to check, where the time is burned. Several rounds.
The timed is mainly burned in string.find, string assignment and vector assignments.
The reason is not that the find-function is slow, but your excessive and unnecessary use of it.
Here you must work.
Look at the lines:
if (newTag.tagType.find("area") != std::string::npos || newTag.tagType.find("base") != std::string::npos || newTag.tagType.find("br") != std::string::npos || newTag.tagType.find("col") != std::string::npos || newTag.tagType.find("command") != std::string::npos || newTag.tagType.find("embed") != std::string::npos || newTag.tagType.find("hr") != std::string::npos || newTag.tagType.find("img") != std::string::npos || newTag.tagType.find("input") != std::string::npos || newTag.tagType.find("keygen") != std::string::npos || newTag.tagType.find("link") != std::string::npos || newTag.tagType.find("meta") != std::string::npos || newTag.tagType.find("param") != std::string::npos || newTag.tagType.find("source") != std::string::npos || newTag.tagType.find("track") != std::string::npos || newTag.tagType.find("wbr") != std::string::npos) {
newTag.closeTag = "Null";
}
That is of course very inefficient.
Anyway. Study you code and refactor it. The design is important.
Please see your stubbed code:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
struct Doc {
std::string body{};
};
struct Tag {
std::vector<std::string> tagID{};
std::string tagType{};
std::string openTag{};
std::string closeTag{};
std::vector<std::string> tagClass{};
};
struct Page {
std::vector<Tag> tags;
};
int main() {
Doc doc{};
Page page{};
std::vector<char> html{};
html.reserve(200000000);
if (std::ifstream ifs("r:\\example.htm"); ifs) {
std::copy(std::istreambuf_iterator<char>(ifs), {}, std::back_inserter(html));
int start = 0;
int end = static_cast<int>(html.size());
for (int i = start; i <= end; i++) {
doc.body.push_back(html[i]);
if (html[i] == '<') {
if (html[i + 1] != '/') {
Tag newTag;
int start1 = i;//html[i];
int end1;
for (int y = i; y <= end; y++) {
if (html[y] == '>') {
end1 = y;
break;
}
}
for (int y = start1 + 1; y <= end1; y++) {
if (html[y] == ' ' || html[y] == '>') {
break;
}
newTag.tagType.push_back(html[y]);
}
for (int y = start1; y <= end1; y++) {
newTag.openTag.push_back(html[y]);
}
if (newTag.tagType.find("area") != std::string::npos || newTag.tagType.find("base") != std::string::npos || newTag.tagType.find("br") != std::string::npos || newTag.tagType.find("col") != std::string::npos || newTag.tagType.find("command") != std::string::npos || newTag.tagType.find("embed") != std::string::npos || newTag.tagType.find("hr") != std::string::npos || newTag.tagType.find("img") != std::string::npos || newTag.tagType.find("input") != std::string::npos || newTag.tagType.find("keygen") != std::string::npos || newTag.tagType.find("link") != std::string::npos || newTag.tagType.find("meta") != std::string::npos || newTag.tagType.find("param") != std::string::npos || newTag.tagType.find("source") != std::string::npos || newTag.tagType.find("track") != std::string::npos || newTag.tagType.find("wbr") != std::string::npos) {
newTag.closeTag = "Null";
}
if (newTag.openTag.find("class=") != std::string::npos) {
int start1 = newTag.openTag.find("\"", newTag.openTag.find("class=")) + 1;
int end1 = newTag.openTag.find("\"", start1);
for (int y = start1; y < end1; y++) {
if (newTag.tagClass.empty()) newTag.tagClass.push_back({});
if (html[y] != ' ') {
if (newTag.tagClass.empty()) newTag.tagClass.push_back({}); // ***********************
newTag.tagClass.back().push_back(html[y]);
}
else {
newTag.tagClass.push_back("");
}
}
}
if (newTag.openTag.find("id=") != std::string::npos) {
int start1 = newTag.openTag.find("\"", newTag.openTag.find("id=")) + 1;
int end1 = newTag.openTag.find("\"", start1);
if (newTag.tagID.empty()) newTag.tagID.push_back({});
for (int y = start1; y < end1; y++) {
if (html[y] != ' ') {
newTag.tagID.back().push_back(html[y]);
}
else {
newTag.tagID.push_back("");
}
}
}
page.tags.push_back(newTag);
}
else {
int end1;
for (int y = i; y <= html.size(); y++) {
if (html[y] == '>') {
end1 = y;
break;
}
}
//gets everything within the closing tag
std::string storeClose;
for (int y = i; y <= end1; y++) {
storeClose.push_back(html[y]);
}
for (int y = page.tags.size() - 1; y >= 0; y--) {
if (storeClose.find(page.tags[y].tagType) != std::string::npos) {
page.tags[y].closeTag = storeClose;
}
}
}
}
}
}
}
And one output of the profile runs:
The test has been performed on a 12 years old Windows 7 machine.
I'm solving a little problem and I met an runtime error and I have no idea where is the source of that error. I'm taking a string word and converting it's uppercase consonants to the corresponding lowercase ones by building another string new_word. The error appears at the else if statement.
The error: C++ exception: std::out_of_range at memory location 0x006FF330.
Please help!
int main()
{
string word, new_word;
string::iterator i;
cin >> word;
for (i = word.begin(); i < word.end(); i++)
{
if (*i != 'A' && *i != 'a' && *i != 'O' && *i != 'o' && *i != 'Y' && *i != 'y' && *i != 'E' && *i != 'e' && *i != 'U' && *i != 'u' && *i != 'I' && *i != 'i')
{
if (*i > 'a' && *i <= 'z')
{
new_word.push_back('.');
new_word.push_back(*i);
}
else if (*i > 'A' && *i <= 'Z')
{
new_word.push_back(word.at(*i)+32);
}
}
}
cout << new_word;
return 0;
}
It seems you mean
new_word.push_back( *i +32);
instead of
new_word.push_back(word.at(*i)+32);
Pay attention to that instead of using magic numbers like 32 you could use the standard C function tolower declared in the header <cctype>. For example
#include <cctype>
//...
new_word.push_back( std::tolower( ( unsigned char )*i ) );
This is supposed to return false if a character in the string isn't a letter or an apostrophe. Any idea why it doesn't work? And is there a better way that I can write it? I'm trying to write code like a C++ purist.
for (std::string::const_iterator it = S.begin(); it != S.end(); ++it)
if ((*it < 'a' || *it >'z') && (*it > 'A' || *it < 'Z') && (*it != ''''))
return false;
I see two mistakes:
'''' should be '\''.
*it > 'A' || *it < 'Z' should be *it < 'A' || *it > 'Z'.
This question already has answers here:
C++ Remove punctuation from String
(12 answers)
Closed 9 years ago.
I got a code. It should give me an output that will erase the middle character between 'z' and 'p'. for example: zipZap("zipXzap"): expected [zpXzp] but found [z pXz p]
std::string zipZap(const std::string& str){
string a = str;
string b = "";
size_t len = str.length();
for (size_t i = 0; i < len; i++){
if (str[i] == 'z')
if (str[i+2] == 'p')
a[i+1] = ' ';
}
return a;
}
When i replaced a[i+1] = ''; it gave me an error.
You are not removing the chars, you are replacing them with ' '.
There are many ways to do this. One simple way is to build a new string, only adding chars when the proper conditions are met:
std::string zipZap(const std::string& str)
{
string a;
size_t len = str.length();
for (size_t i = 0; i < len; i++) {
// Always add first and last chars. As well as ones not between 'z' and 'p'
if (i == 0 || i == len-1 || (str[i-1] != 'z' && str[i+1] != 'p')) {
a += str[i];
}
}
return a;
}
Use string.erase() :
std::string zipZap(const std::string& str){
std::string a = str;
std::string b = "";
size_t len = str.length();
for (size_t i = 0; i < len; i++){
if (a[i] == 'z')
if (a[i+2] == 'p')
a.erase(i+1,1);
}
return a;
}
You're completely right that you cant replace an element of the string with ''.
A string is an array of chars, and '' is not a char at all. It is nothing.
If we look at the cplusplus page for a string
http://www.cplusplus.com/reference/string/string/
We see that we can use erase(iterator p) to "Erase characters from string (public member function)"
So if we change:
for (size_t i = 0; i < len; i++){
if (str[i] == 'z')
if (str[i+2] == 'p')
a.erase(a.begin() + i + 1);
We're closer now, but we can see that len is no longer the same as str.length(). the length of a is now actually 1 char shorter than len. To remedy this however we can simply add:
for (size_t i = 0; i < len; i++){
if (str[i] == 'z')
if (str[i+2] == 'p')
a.erase(a.begin() + i + 1);
len -= 1;
Hope that helps
If you #include <regex>, you can do a regular expression replacement.
std::string zipZap(const std::string& str){
regex exp("z.p");
string a = str;
a = regex_replace(a, exp "zp");
return a;
}
I have the following code which ends up in a segmentation fault.
for (int a=0; a<inputFileList.size(); a++)
{
fileLines = readFile(inputFileList[a].c_str());
for (int i = 0; i < fileLines.size(); i++)
{
if (fileLines[i].find("text") != string::npos)
{
bool warnFound = false, errFound = false;
i++;
while (fileLines[i].find("message") == string::npos && i < fileLines.size())
{
if (fileLines[i].find("error") != string::npos)
errFound = true;
else if (fileLines[i].find("warning") != string::npos)
warnFound = true;
i++;
}
i--;
if (errFound)
errCtr++;
else if (warnFound)
warnCtr++;
else
okCtr++;
}
}
fileLines.clear();
}
When i remove the while-loop, i don't get this error anymore. But i don't know what's wrong with this loop.
Thx for your support
The while should probably read
while (i < fileLines.size() && fileLines[i].find("message") == string::npos)
This :
while (fileLines[i].find("message") == string::npos && i < fileLines.size())
should be:
while (i < fileLines.size() && fileLines[i].find("message") == string::npos )
I'm not sure if it has anything to do with the error you're getting, but you seem to have a problem with the i++ on line 7. It may increase i even when i == fileLines.size() - 1, so fileLines[i].find("message") on the next line would access a non-existing item.