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');
}
Related
I have a char pointer , then i convert it into string format. So i would like to capitalize the first character of each word in this string, I wrote the code below :
#include <iostream>
#include <cstring>
#include <stdlib.h>
#include <time.h>
#include <string>
using namespace std;
void transform(char *s);
int main(int argc, char const *argv[])
{
char *str = new char[255];
strcpy(str, "jimmy catter");
string s;
s+=str; //convert char to string
std::cout<<s<<endl;
for (int i = 0; i < s.length(); ++i)
{
if (s[i] == ' ')
{
if (islower(s[i+1])==1)
{
s[i+1] = toupper(s[i+1]);
}
}
}
std::cout<<s<<endl;
return 0;
}
I would like to the output shoule be "Jimmy Catter" , but the result i got is still in the lower format. Could you please help look with this ?
So basically, there are two things here:
islower() should be treated as if it returns a bool, even if it says it returns an int. This is because for a bool, the actual value is false if 0 and true if any value other than 0. This means that if you wanted to still compare to a numerical value you would say islower(s[i]) != 0 since 1 is not the only valid internal value for true.
For the first character (J), there isn't a space before it. So, what we can do is check the current character is the first character OR if the previous character is space. Basically, instead of checking the current character and changing the next character, we check the previous character (or if it's the first character) and then change the current character.
#include <iostream>
#include <cstring>
#include <stdlib.h>
#include <time.h>
#include <string>
using namespace std;
void transform(char *s);
int main(int argc, char const *argv[])
{
char *str = new char[255];
strcpy(str, "jimmy catter");
string s;
s+=str; //convert char to string
std::cout<<s<<endl;
for (int i = 0; i < s.length(); ++i) {
if (i == 0 || s[i - 1] == ' ') {
if (islower(s[i])) {
s[i] = toupper(s[i]);
}
}
}
std::cout<<s<<endl;
return 0;
}
First thing to note here is that islower returns non zero(>0) number if argument is lowercase instead of 1.
Second you are trying to capitalize char by checking if char before it was whitespace. Nothing wrong with this approach but it won't work on first character so you can do it by adding an extra line before the loop. So with some tweaking it works fine now:
#include <iostream>
#include <cstring>
#include <stdlib.h>
#include <time.h>
#include <string>
using namespace std;
// void transform(char *s);
int main(int argc, char const *argv[])
{
string s = "jimmy catter ";
/*
char *str = new char[255];
strcpy(str, "jimmy catter");
string s;
s+=str; //convert char to string
*/
std::cout<<s<<endl;
s[0]=toupper(s[0]);
for (int i = 0; i < s.length()-1; ++i)
{
if (s[i] == ' ')
{
if (islower(s[i+1])>=1)
{
s[i+1] = toupper(s[i+1]);
}
}
}
std::cout<<s<<endl;
return 0;
}
You may use ASCII notations because they are quite clear to understand and execute in such programs.
I modified your code a little bit in the loop part and it gives correct output. Have a look at it.
for (int i = 0; i < s.length(); ++i)
{
if(!i&&97<=s[i]<=122) //handles border condition where first letter is small case
{
s[i] = s[i]-32;
}
if ((i!=s.length-1)&&s[i] == ' ') //prevents invalid output where last character is a space
{
if (97<=s[i+1]<=122) //checks if letter after space is small case
{
s[i+1] = s[i+1]-32;
}
}
}
std::cout<<s<<endl;
return 0;
}
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.
I have to admit, i have no idea how to use pointers, but I tried non the less. the problem with my program is that it shows the string in reverse, except for what was the first letter being missing and the entire string is moved one space forward with the first element being blank.
for example it show " olle" when typing "hello".
#include <iostream>
#include <string>
using namespace std;
string reverse(string word);
int main()
{
char Cstring[50];
cout<<"enter a word: ";
cin>>Cstring;
string results = reverse(Cstring);
cout <<results;
}
string reverse(string word)
{
char *front;
char *rear;
for (int i=0;i< (word.length()/2);i++)
{
front[0]=word[i];
rear[0]=word[word.length()-i];
word[i]=*rear;
word[word.length()-i]=*front;
}
return word;
}
The new code works perfectly. changed the strings to cstrings. the question technicaly asked for cstrings but i find strings easier so i work with strings then make the necesary changes to make it c string. figured out ho to initialize the rear and front as well.
#include <iostream>
#include <cstring>
using namespace std;
string reverse(char word[20]);
int main()
{
char Cstring[20];
cout<<"enter a word: ";
cin>>Cstring;
string results = reverse(Cstring);
cout <<results;
}
string reverse(char word[20])
{
char a='a';
char b='b';
char *front=&a;
char *rear=&b;
for (int i=0;i< (strlen(word)/2);i++)
{
front[0]=word[i];
rear[0]=word[strlen(word)-1-i];
word[i]=*rear;
word[strlen(word)-1-i]=*front;
}
return word;
}
char *front;
char *rear;
then later
front[0]=word[i];
rear[0]=word[strlen(word)-1-i];
Not good. Dereferencing uninitialized pointers invokes undefined behavior.
Apart from that, your code is overly complicated, it calls strlen() during each iteration (and even multiple times), which is superfluous, and the swap logic is also unnecessarily complex. Try using two pointers instead and your code will be much cleaner:
void rev_string(char *str)
{
char *p = str, *s = str + strlen(str) - 1;
while (p < s) {
char tmp = *p;
*p++ = *s;
*s-- = tmp;
}
}
The thing is, however, that in C++ there's rarely a good reason for using raw pointers. How about using std::reverse() instead?
string s = "foobar";
std::reverse(s.begin(), s.end());
inline void swap(char* a, char* b)
{
char tmp = *a;
*a = *b;
*b = tmp;
}
inline void reverse_string(char* pstart, char* pend)
{
while(pstart < pend)
{
swap(pstart++, pend--);
}
}
int main()
{
char pstring[] = "asfasd Lucy Beverman";
auto pstart = std::begin(pstring);
auto pend = std::end(pstring);
pend -= 2; // end points 1 past the null character, so have to go back 2
std::cout << pstring << std::endl;
reverse_string(pstart, pend);
std::cout << pstring << std::endl;
return 0;
}
you can also do it like this:
#include <iostream>
#include <cstring>
using namespace std;
string reverse(char word[20]);
int main()
{
char Cstring[20];
cout<<"enter a word: ";
cin>>Cstring;
string results = reverse(Cstring);
cout <<results;
}
string reverse(char word[20])
{
char a='a';
char b='b';
char *front=&a;
char *rear=&b;
for (int i=0;i< (strlen(word)/2);i++)
{
*front=word[i];
*rear=word[strlen(word)-1-i];
word[i]=*rear;
word[strlen(word)-1-i]=*front;
}
return word;
}
it successfully works on my system ,i.e. on emacs+gcc on windows 7
Taken from C How To Program Deitel & Deitel 8th edition:
void reverse(const char * const sPtr)
{
if (sPtr[0] == '\0')
return;
else
reverse(&sPtr[1]);
putchar(sPtr[0]);
}
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
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.