Got stuck in C++ infinite loop - c++

I'm doing a leetcode challenge to practice my c++
I am supposed to replace all the "." from an ip address to "[.]"
so essentially, x.x.x.x is supposed to become x[.]x[.]x[.]x
My code is :
#include <iostream>
#include <string.h>
using namespace std;
int main(int argc, const char * argv[]) {
string address ="1.1.1.1";
while(address.find(".") != string::npos){
address.replace(address.find("."), 1,"[.]");
}
cout<<address<<endl;
}
However, I am getting stuck in a loop where it is doing :
x.x.x.x
x[.]x.x.x
x[[.]]x.x.x
x[[[.]]]x.x.x
and so on.
How do I get out of this loop? Thank you!

You can specify where to start by the 2nd argument of std::string::find.
#include <iostream>
#include <string>
int main(int argc, const char * argv[]) {
std::string address ="1.1.1.1";
std::string::size_type start_pos = 0, current_pos;
while((current_pos = address.find(".", start_pos)) != std::string::npos){
address.replace(current_pos, 1,"[.]");
start_pos = current_pos + 3; // start next search after the inserted string
}
std::cout<<address<<std::endl;
}

Learn to separate code into functions (this is important). Also it is easier to store result into separate variable, so you do not have to update search point.
std::string escapeDots(const std::string& s)
{
std::string result;
result.reserve(s.size() + 8);
for (auto ch : s) {
if (ch == '.')
result += "[.]";
else
result += ch;
}
return result;
}
This code is more clear the alternative answer and most probably is faster.

With <regex>, it would be
int main()
{
std::string address = "1.1.1.1";
std::cout << std::regex_replace(address, std::regex("\\."), "[.]") << std::endl;
}
Demo.

Related

C++ code doesn't compile because of an error

I'm currently solving problems for my high school final exam at programming in C++. I tried solving a problem in CodeBlocks, but it gives me this error at line 13:
error: invalid conversion from 'const char*' to 'int' [-fpermissive]
I don't see what is wrong.
The problem is about removing the last consonant from a string. The string is "mare frig saci" and it should produce "mare frig sai", removing the last 'c'.
Here is my code:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char s[256];
int i;
cin.get(s,256);
for(i=strlen(s)-1;i=0;i--)
{
if(strchr(s,"aeiou")!=0)
strcpy(s+i+1,s+i-1);
}
cout<<s;
return 0;
}
There are a few problems:
i=0 is not a condition, it's an assignment. i>=0 is probably what you're looking for here
strchr take in a string and char (1), and return a pointer (2), not an int to be compared. Both (1) and (2) condition isn't sastified. In any case, strchr is not ideal to use here.
I recommended using std::string (as it's more easy to use and standard in C++) and std::string::find_last_of, which find the last character in string inside a set of characters, exactly what you wanted here:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s; getline(std::cin, s);
string cons = "bcdfghjklmnpqrstvwxyz";
size_t pos = s.find_last_of(cons);
if (pos != string::npos) //if a consonant is found
{
s.erase(pos, 1);
}
cout << s;
}
std::strchr - The valid signatures are
const char* strchr( const char* str, int ch );
char* strchr( char* str, int ch );
So, you are supplying it with the wrong things.
std::strcpy - "The behavior is undefined if the strings overlap" - so you can't use std::strcpy to move the end of the string to the new place. Instead use std::memmove.
Since the string you mention contains a space at the end, you must add space to the list of vowels.
You assign 0 to i instead of checking it's value.
Example:
#include <cstring>
#include <iostream>
int main() {
char s[256] = " mare frig saci ";
for (size_t len = strlen(s), i = len; i-- > 0;) { // corrected loop
if (std::strchr("aeiou ", s[i]) == nullptr) { // corrected check
std::memmove(s + i, s + i + 1, len - i); // corrected move
break; // and break out
}
}
std::cout << s << '\n';
}

C++ segmentation fault while counting character occurrences in string

I've written a simple function to count occurrences of a character in a string. The compiler is fine. However, as I try to run it, it produced a segmentation fault.
#include <iostream>
using namespace std;
// To count the number of occurences of x in p
// p is a ะก-style null-terminated string
int count_x(char* p, char x)
{
if (p == nullptr)
{
return 0;
}
// start the counter
int count = 0;
while (p != nullptr)
{
if (*p == x)
{
++count;
}
}
return count;
}
int main(int argc, char const *argv[])
{
char myString[] = "Hello";
cout << count_x(myString, 'l');
return 0;
}
There's two mistakes in your code:
You only ever look at the first character in the string.
The last character of a null terminated string is a null character. You're testing the pointer itself.
You need to use std::string
#include <string>
#include <algorithm>
#include <iostream>
int main()
{
std::string str = "Hello";
std::cout << std::count(str.begin(), str.end(), 'l');
}

Function to parse string with tokens

I know how to program in C# and VB but not have idea about how to use C++ and have to program a little exe to a barcode scanner that use C++ :(
In this moment I try to parse a scanned barcode that have multiple data sepparated with a "/", I find that exist a strtok function, tested it "manually" and worked ok but I not implemented yet a working function to call it correctly, what I have now:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int elemStr(char *str, char sep)
{
int cantElem;
unsigned ich;
cantElem = 0;
if (strlen(str) > 0) //at least 1 elem
cantElem++;
for (ich = 0; ich < strlen(str); ich++)
{
if (str[ich] == sep)
cantElem++;
}
return cantElem;
}
char* getElemStr(char *str, char sep[], int elem)
{
char *tempStr = NULL;
char *tok;
int currElem = 1;
// 1st data
strcpy( tempStr, str);
tok = strtok( tempStr, sep);
while( currElem != elem )
{
// Get next tokens:
tok = strtok( NULL, sep );
currElem++;
}
return tok;
}
void main( void )
{
char barcode[] = "710015733801Z/1/35";
char sep[] = "/";
char sep1 = sep[0];
char barcd[20];
char piezaChar[4];
int pieza;
char mtsChar[4];
int cantElem;
cantElem = elemStr(barcode, sep1 );
if (cantElem >= 1)
{
strcpy(barcd, getElemStr(barcode,sep,1) ); //pasa a str resultado;
printf("Cod: %s\n", barcd ); //STACK OVERFLOW HERE!
}
}
if I use strtok witout a function "getElemStr" it work ok but I try to use it on other places too.
Can I use strtok like this? You have a working example?
pd: I not have idea about pointers (sorry), good doc to learn about that?
Since you specifically asked about C++, I'm going to ignore your very c-style code and show you how to do this in C++:
#include <boost/algorithm/string.hpp>
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::string barcode = "710015733801Z/1/35";
std::string sep = "/";
std::vector<std::string> v;
boost::split(v, barcode, boost::is_any_of(sep));
for(size_t i=0; i<v.size(); ++i)
std::cout << v[i] << '\n';
}
strtok destroys your original string. So i don't think it can be used with a char* that points to a static string. Static strings get copied to a read only portion of the executable.
Here is a C++ solution that doesn't use boost.
#include <string>
#include <sstream>
#include <iostream>
int main()
{
std::string barcode = "710015733801Z/1/35";
std::stringstream ss(barcode);
std::string elem;
while(std::getline(ss, elem, '/'))
{
//do something else meaningful with elem
std::cout << elem << std::endl;
}
return 0;
}
Output:
710015733801Z
1
35

How do you use string.erase and string.find?

Why cant i call string.find in string.erase like so: str.erase(str.find(a[1]),str.size())?
edit:code added
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
// html tags
string tags[5]={"<!--...-->","<!DOCTYPE>","<a>","<abbr>","<acronym>"};
//
//check if string exists
int boolStringExists(string a, string b)
{
if(a.find(b)>0)
{
return 1;
}
if(a.find(b)<=0)
{
return 0;
}
}
//erase tag from string a
void eraseTags(string a,string b[])
{
for(int i=0; i<5;i++)
{
int x=(boolStringExists(a,b[i]));
while (x>0)
{
a.erase(a.find(b[i]),b[i].size());
x=(boolStringExists(a,b[i]));
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
fstream file;
file.open("h:\\a.htm");
string k,m;
while(getline(file, k))
m += k ;
eraseTags(m,tags);
return 0;
}
Gives this message: "this application has requested the runtime to terminate it in an unusual way.Please contact the application's support team for more information."
If the string is not found, find returns string::npos, and then your code wouldn't work and will give runtime error. See this gives error : https://ideone.com/NEhqn
So better write this:
size_t pos = str.find(a[1]);
if ( pos != std::string::npos)
str.erase(pos); //str.size() is not needed!
Now this doesn't give error : https://ideone.com/IF2Hy
There's nothing wrong with that call (assuming a[1] exists and is found in str at least once)
#include <iostream>
#include <string>
int main()
{
std::string str = "Hello, world!";
std::string a = "wwwwww";
str.erase(str.find(a[1]), str.size());
std::cout << str << '\n';
}
test run: https://ideone.com/8wibR
EDIT: Your full source code fails to check if b[1] is actually found in str. The function boolStringExists() returns 1 if a.find(b) is greater than zero, and the value of std::string::npos which it returns when b is not found in a IS greater than zero.
To fix this while keeping the rest of your logic intact, change that function to
//check if string exists
bool boolStringExists(string a, string b)
{
return a.find(b) != string::npos;
}
It seems you want to erase everything that comes after str.find(a[1]). In that case you can omit the second argument.
#include <iostream>
#include <string>
int main(int argc, char *argv[]) {
std::string str = "Hello, world!";
std::string needle = "o,";
str.erase(str.find(needle));
std::cout << str << "\n";
}
In this example I used needle instead of a[1], but the principle is the same.

How to run multiple arguments in Cygwin

I've been trying to run a program that will invert the order of a string and to run it, I have to type a second argument in prompt.
int main(int argc, char* argv[])
{
string text = argv[2];
for (int num=text.size(); num>0; num--)
{
cout << text.at(num);
}
return 0;
}
e.g. ./program lorem result: merol
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char* argv[])
{
string text = argv[1];
for (int num=text.size() - 1; num >= 0; num--)
{
cout << text.at(num);
}
return 0;
}
You missed the includes and used string::at wrong. There are size() chars in the string but you start counting at 0. Then the loop has to run until num >= 0 and not num > 0. You also used the wrong index into argv.
This would still be an abomination of C++. A clearer way would be:
#include <iostream>
#include <string>
#include <algorithm>
int main(int argc, char* argv[])
{
std::string text = argv[1];
for(std::string::reverse_iterator it = text.rbegin(); it != text.rend(); ++it) {
std::cout << *it;
}
std::cout << std::endl;
//or if you want further usage of the reversed string
std::reverse(text.begin(), text.end());
std::cout << text;
return 0;
}
I think you're getting an exception because num is out of bounds. size() is returning a value one larger than the biggest valid index into the string, so at() is throwing an exception.