How to pass a cstring as a function parameter/argument - c++

I have a small program that prints out the capital form of each letter of a word, but I get the error signed/unsigned mismatch when I compile it because I'm passing a cstring as a normal string in this program. How do I pass it correctly so that I can still use text.length()? Here is the error that I get "Tester.cpp(22,23): warning C4018: '<': signed/unsigned mismatch". It's at for (int i = 0; i < text.length(); i++)
#include <iostream>
using namespace std;
string capitalizeFirstLetter(string text);
int main() {
char sentence[100];
for ( ; ; )
{
cin.getline(sentence, 100);
if (sentence != "0")
capitalizeFirstLetter(sentence);
}
return 0;
}
string capitalizeFirstLetter(string text) {
for (int i = 0; i < text.length(); i++)
{
if (i == 0)
{
text[i] = toupper(text[i]);
}
if (text[i] == ' ')
{
++i;
text[i] = toupper(text[i]);
}
}
cout << text;
return text;
}

The simplest way to handle passing sentence as a string is to enclose it in a braced set, to provide direct initialization to the parameter std::string text eg..
for ( ; ; )
{
std::cin.getline(sentence, 100);
if (*sentence)
capitalizeFirstLetter({sentence});
}
This allows the character string sentence to be used as the Direct initialization to initialize std::string text in your capitalizeFirstLetter() function:
std::string capitalizeFirstLetter (std::string text) {
for (size_t i = 0; i < text.length(); i++)
{
if (i == 0)
{
text[i] = toupper(text[i]);
}
if (text[i] == ' ')
{
++i;
text[i] = toupper(text[i]);
}
}
std::cout << text;
return text;
}
Your complete code, after reading Why is “using namespace std;” considered bad practice?, would then be:
#include <iostream>
std::string capitalizeFirstLetter (std::string text) {
for (size_t i = 0; i < text.length(); i++)
{
if (i == 0)
{
text[i] = toupper(text[i]);
}
if (text[i] == ' ')
{
++i;
text[i] = toupper(text[i]);
}
}
std::cout << text;
return text;
}
int main (void) {
char sentence[100];
for ( ; ; )
{
std::cin.getline(sentence, 100);
if (*sentence)
capitalizeFirstLetter({sentence});
}
return 0;
}
(note: dereferencing sentence provides the first character which is then confirmed as something other than the nul-terminating character (ASCII 0))
A Better CapitalizeFirstLetter()
A slightly easier way to approach capitalization is to include <cctype> and an int to hold the last character read. Then the logic simply loops over each character and if the first character is an alpha-character, then capitalize it, otherwise only capitalize the letter when the current character is an alpha-character and the last character was whitespace, e.g.
std::string capitalizeFirstLetter (std::string text)
{
int last = 0
for (auto& c : text)
{
if (isalpha(c))
{
if (!i || isspace (last))
c = toupper(c);
}
last = c;
}
std::cout << text;
return text;
}
(note: the use of a range-based for loop above)
Either way works.

The error is not generating because of you passing a cstring as a normal string to the function but it is due to the fact that you are trying to compare c style string using != operator in the statement
if (sentence != "0")
capitalizeFirstLetter(sentence);
try using strcmp() for that

Several things bugging me here.
First off, don't use using namespace std, it's "ok" in this case, but don't get used to it, it can cause quite some trouble.
See Why is “using namespace std;” considered bad practice?
Next thing is, just use std::string instead of cstrings here, it's easier to write and to read and doesn't produce any measurable performance loss or something. And it's harder to produce bugs this way.
So just use
std::string sentence;
and
getline(std::cin, sentence);
And why do you handle the output inside the function that transforms your string? Just let the main print the transformed string.
So your main could look like this:
int main() {
std::string sentence;
while(true)
{
getline(std::cin, sentence);
auto capitalized = capitalizeFirstLetter(sentence);
std::cout << capitalized;
}
return 0;
}
PS: the 'error' you get is a warning, because you compare int i with text.length() which is of type size_t aka unsigned int or unsigned long int.

Problems with your code :
if (sentence != "0") : illegal comparison. If you want to break on getting 0 as input then try using strcmp (include <cstring>) as if (strcmp(sentence, "0"). (Note that strcmp returns 0 when two strings are equal.) Or simply do if (!(sentence[0] == '0' and sentence[1] == 0)). Moreover this condition should be accompanied with else break; to prevent the for loop from running forever.
for (int i = 0; i < text.length(); i++) : generates warning because of comparison between signed and unsigned types. Change data-type of i to string::size_type to prevent the warning.
<string> (for std::string) and <cctype> (for std::toupper) were not included.
Thanks to #john for pointing this out. Your code has undefined behaviour if last character of a string is a space. Add a check if i is still less than text.length() or not before using text[i].
Another case of error is when an space is there after 0. Move getline to condition of for to fix this. Now there will be no need to input a 0 to terminate program. Moreover, I recommend using while loop for this instead of for.
You may also need to print a newline to separate sentences. Moreover, I would prefer printing the modified sentence in the main() function using the returned string from capitalizeFirstLetter.
It doesn't matter much in short (beginner-level) codes, but avoid acquiring the habit of putting using namespace std; on the top of every code you write. Refer this.
Fixed code :
#include <cctype>
#include <cstring>
#include <iostream>
#include <string>
using namespace std;
string capitalizeFirstLetter(string text);
int main() {
char sentence[100];
while (cin.getline(sentence, 100))
cout << capitalizeFirstLetter(sentence) << '\n';
}
string capitalizeFirstLetter(string text) {
for (string::size_type i = 0; i < text.length(); i++) {
if (i == 0)
text[i] = toupper(text[i]);
if (text[i] == ' ')
if (++i < text.length())
text[i] = toupper(text[i]);
}
return text;
}
Sample Run :
Input :
hello world
foo bar
Output :
Hello World
Foo Bar
My Version (Requires C++20) :
#include <cctype>
#include <iostream>
#include <string>
auto capitalizeFirstLetter(std::string text) {
for (bool newWord = true; auto &&i : text) {
i = newWord ? std::toupper(i) : i;
newWord = std::isspace(i);
}
return text;
}
int main() {
std::string sentence;
while (std::getline(std::cin, sentence))
std::cout << capitalizeFirstLetter(sentence) << std::endl;
}
Sample Run

Related

How to replace "pi" by "3.14"?

How to replace all "pi" from a string by "3.14"? Example: INPUT = "xpix" ___ OUTPUT = "x3.14x" for a string, not character array.
This doesn't work:
#include<iostream>
using namespace std;
void replacePi(string str)
{
if(str.size() <=1)
return ;
replacePi(str.substr(1));
int l = str.length();
if(str[0]=='p' && str[1]=='i')
{
for(int i=l;i>1;i--)
str[i+2] = str[i];
str[0] = '3';
str[1] = '.';
str[2] = '1';
str[3] = '4';
}
}
int main()
{
string s;
cin>>s;
replacePi(s);
cout << s << endl;
}
There is a ready to use function in the C++ lib. It is called: std::regex_replace. You can read the documentation in the CPP Reference here.
Since it uses regexes it is very powerful. The disadvantage is that it may be a little bit too slow during runtime for some uses case. But for your example, this does not matter.
So, a common C++ solution would be:
#include <iostream>
#include <string>
#include <regex>
int main() {
// The test string
std::string input{ "Pi is a magical number. Pi is used in many places. Go for Pi" };
// Use simply the replace function
std::string output = std::regex_replace(input, std::regex("Pi"), "3.14");
// Show the output
std::cout << output << "\n";
}
But my guess is that you are learning C++ and the teacher gave you a task and expects a solution without using elements from the std C++ library. So, a hands on solution.
This can be implemented best with a temporary string. You check character by character from the original string. If the characters do not belong to Pi, then copy them as is to new new string. Else, copy 3.14 to the new string.
At the end, overwrite the original string with the temp string.
Example:
#include <iostream>
#include <string>
using namespace std;
void replacePi(string& str) {
// Our temporay
string temp = "";
// Sanity check
if (str.length() > 1) {
// Iterate over all chararcters in the source string
for (size_t i = 0; i < str.length() - 1; ++i) {
// Check for Pi in source string
if (str[i] == 'P' and str[i + 1] == 'i') {
// Add replacement string to temp
temp += "3.14";
// We consumed two characters, P and i, so increase index one more time
++i;
}
else {
// Take over normal character
temp += str[i];
}
}
str = temp;
}
}
// Test code
int main() {
// The test string
std::string str{ "Pi is a magical number. Pi is used in many places. Go for Pi" };
// Do the replacement
replacePi(str);
// Show result
std::cout << str << '\n';
}
What you need is string::find and string::replace. Here is an example
size_t replace_all(std::string& str, std::string from, std::string to)
{
size_t count = 0;
std::string::size_type pos;
while((pos=str.find(from)) != str.npos)
{
str.replace(pos, from.length(), to);
count++;
}
return count;
}
void replacePi(std::string& str)
{
replace_all(str, "pi", "3.14");
}

Adding the next character on a string C++

I did get the next character on a string (hello-->ifmmp) but in the case of hello* i want to be able to still display the * as the exception, it can be also a number but i guess it does not matter because is not in the alphabet.
this is my code, Where should be the else if?
There is another option but i dont find it optimized, it is to add inside the first for loop this:
string other="123456789!##$%^&*()";
for(int z=0;z<other.length();z++)
{
if(str[i]==other[z])
str2+=other[z];
}
Then this is the main code;
int main()
{
string str = "hello*";
string str2="";
string alphabet = "abcdefghijklmnopqrstuvwxyz";
for(int i=0;i<str.length();i++)
{
for(int j=0;j<alphabet.length();j++)
{
if(str[i]==alphabet[j])
{
str2+=alphabet[j+1];
}
}
}
cout<<str2<<endl;
return 0;
}
I like functions. They solve a lot of problems. For example, if you take the code you already have, paste it into a function, and give it a little tweak
char findreplacement(char ch, const std::string & alphabet)
{
for (int j = 0; j < alphabet.length(); j++)
{
if (ch == alphabet[j])
{
return alphabet[(j+1) % alphabet.length()];
// return the replacement character
// using modulo, %, to handle wrap around z->a
}
}
return ch; // found no replacement. Return original character.
}
you can call the function
for (int i = 0; i < str.length(); i++)
{
str2 += findreplacement(str[i], alphabet);
}
to build str2. Consider using a range-based for here:
for (char ch: str)
{
str2 += findreplacement(ch, alphabet);
}
It's cleaner and a lot harder to screw up.
There is a function isalpha in the standard library which is very useful for classification.
You could do something like this.
(This kind of exercise usually assumes the ASCII encoding of the English alphabet, and this is a very ASCII-specific solution. If you want a different alphabet or a different character encoding, you need to handle that yourself.)
#include <cctype>
#include <string>
#include <iostream>
int main()
{
std::string str = "Hello*Zzz?";
std::string str2;
for (char c: str)
{
if (std::isalpha(c))
{
c += 1;
if (!std::isalpha(c))
{
// Went too far; wrap around to 'a' or 'A'.
c -= 26;
}
}
str2 += c;
}
std::cout << str2 << std::endl;
}
Output:
Ifmmp*Aaa?

How to delete characters in vector of strings?

I am writing a code where I read a subtitle file and remove the text in () including the brackets themselves, that is subtitles for hearing impaired which have background noise in ().
The example:
13
00:01:08,535 --> 00:01:10,127 // remove this
(PIANO PLAYING) // remove this
125
00:07:09,162 --> 00:07:12,393
BOTH: (SINGING WITH RADIO) Teach // remove only the text in parenthesis, including ()
them well and let them lead the way
The code is here:
#include<iostream>
#include<fstream>
#include<string>
#include<vector>
using namespace std;
void subRem();
int main() {
subRem();
system("PAUSE");
}
void subRem() {
ofstream out;
ifstream in;
out.open("whip it2.srt");
if (out.fail()) {
perror("whip it2.srt");
}
in.open("whip it.srt");
if (out.fail()) {
perror("whip it.srt");
}
vector<string> input;
string inc;
while (getline(in, inc)) {
input.push_back(inc);
}
vector<int> len;
for (int i = 0; i < input.size(); i++) {
len.push_back(input[i].size());
}
for (int i = 0; i < input.size(); i++) {
for (int j = 0; j < len[i]; j++) {
if (input[i][j] == '(') {
for (int k = j; k < len[i]; k++) {
j = k;
if (input[i][k] == ')') {
if (k == (len[i] - 1)) {
input[i - 1] = "";
}
input[i][k] = '\0';
break;
}
input[i][k] = '\0';
}
}
}
}
for (int k = 0; k < input.size(); k++) {
out << input[k] << endl;
}
}
I want to delete the characters in parenthesis, so I am using:
input[i][k] = '\0';
The problem is the characters are removed but they are replaced by whitespace, for example:
(SHOUTING) with her?
I get:
___________with her?
(____ are whitespaces because I couldn't make them appear)
There is the white space. If it was string, I could do:
input[i][k] = "";
but with characters I get the error when I do:
input[i][k] = '';
quoted string should contain at least one character
I plan to improve the code further by renaming the line numbers and deleting extra newlines, but I want to create like an app where I can drag and drop the subtitle file and click run, to get the modified subtitle file. What do I need to know to create the GUI? Do I need to learn Qt or some other libraries?
std:;string can contain \0 without problems, it's not the end-of-string character inside a std::string. MikeCAT's suggestion is the correct answer: use std::string::erase.
(Please don't ask multiple questions at once, but yes Qt is a reasonable way to create GUI's)
Try using substr. This method gives you a substring between two given positions. Although this solves the problem for your second problem, it leaves empty subtitles for strings on the first case. I would recommend checking for an empty result and removing the string at all.
Since you're basically copying characters from one file to another, I'd just keep track of whether you're in a subtitle as you copy, and if so, don't copy characters until you encounter a close parenthesis again.
#include <string>
#include <iostream>
#include <sstream>
int main() {
std::istringstream in{
R"(13
00:01:08,535 --> 00:01:10,127
(PIANO PLAYING)
125
00:07:09,162 --> 00:07:12,393
BOTH: (SINGING WITH RADIO) Teach
them well and let them lead the way)"
};
bool in_subtitle = false;
std::string temp;
while (std::getline(in, temp)) {
unsigned line_len = 0;
for (char ch : temp) {
switch (ch) {
case '(': in_subtitle = true; break;
case ')': in_subtitle = false; break;
default:
if (!in_subtitle) {
std::cout << ch;
++line_len;
}
break;
}
}
if (line_len != 0) std::cout << "\n";
}
}
#include <iostream>
#include <regex>
int main() {
std::string text("this text (remove this) and (remove this) end.");
// First Method: with regular expression
std::regex expr("\\(.*?\\)");
std::cout << std::regex_replace (text, expr, "");
// Second Method: with stl
auto begin = text.find_first_of("(");
auto end = text.find_last_of(")") + 1;
if (std::string::npos != begin && std::string::npos != end && begin <= end)
text.erase(begin, end-begin);
// Optional
std::cout << text << std::endl;
}

I am getting a segmentation fault in this code and can't understand why?

I am trying to code a program where it takes a program as an input and prints out all the comments written in that program in a separate line.
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
string str;
while(getline(cin,str)) {
int i;
// cout<<str;
for(i=0;str[i]!='/' && str[i+1] !='/';i++);
//cout<<i;
for(i;str[i]!='\n';i++) {
// cout<<i;
cout<<str[i];
}
cout<<endl;
}
return 0;
}
I am getting a segmentation fault in this code and I can't understand why. This is part of a code of a problem in hackerrank https://www.hackerrank.com/challenges/ide-identifying-comments/copy-from/12957153
As commented in your question your code is wrong. First you are treating std::string object, returned by getline, as character array. Secondly your for loops never end if there is no // or \n found in input string. So obviously it will crash. Below is the modified code.
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
string str;
while(getline(cin,str)) {
int i;
// cout<<str;
size_t len = str.length();
const char *cstr = str.c_str();
for(i=0; (cstr[i]!='/' && cstr[i+1] !='/' && i < len); i++)
//cout<<i;
for(; cstr[i]!='\n' && i < len;i++) {
// cout<<i;
cout<<cstr[i];
}
cout<<endl;
}
return 0;
}
int main() {
while(getline(cin,str)) {
int i, len = str.size();
//always make sure that you are not accessing
//contents after your string has ended
for(i=0; i < (len - 1) && !(str[i] == '/' && str[i+1] == '/'); i++);
//note that i here might be the last alphabet
//if there's no comment
if(i < len && str[i] != '/')
i++;
//checking if str[i] != '\n' is not a good idea
//as c++ stl strings are not temrinated by '\n'
if(i < len) {
for(; i < len; i++)
cout << str[i];
cout << endl;
}
}
return 0;
}
Also note that both of the following codes won't terminate at the 4th character, c++ stl strings are not terminated by these characters.
string str = "hahahaha";
str[4] = '\n';
cout << str;
str[4] = '\0';
cout << str;
This is much easier to write and probably much faster than the other solutions to date.
#include <iostream>
int main()
{
std::string str;
while (std::getline(std::cin, str))
{
size_t loc = str.find("//");
if (loc != str.npos)
{
std::cout << str.substr(loc + 2)<< std::endl;
}
}
return 0;
}
It is also wrong.
Here is a nice, clean, and simple state machine version. Also pretty close to worst-case for speed. Thing is it's closest to being right, even though it is also wrong.
#include <iostream>
enum states
{
seeking1,
seeking2,
comment
};
int main()
{
std::string str;
while (std::getline(std::cin, str))
{
states state = seeking1;
for (char ch:str)
{
switch (state)
{
case seeking1:
if (ch == '/')
{
state = seeking2;
}
break;
case seeking2:
if (ch == '/')
{
state = comment;
}
else
{
state = seeking1;
}
break;
case comment:
std::cout << ch;
break;
}
}
if (state == comment)
{
std::cout << std::endl;
}
}
return 0;
}
Why are these approaches all wrong? Consider the line
cout << "Hi there! I am \\Not A Comment!" << endl;`
You can't just look at the \\, you also need the context. This is why the state machine above is the better option. It can be modified to handle, at the very least, states for handling strings and block comments.

Count character occurrences in a string in C++

How can I count the number of "_" in a string like "bla_bla_blabla_bla"?
#include <algorithm>
std::string s = "a_b_c";
std::string::difference_type n = std::count(s.begin(), s.end(), '_');
Pseudocode:
count = 0
For each character c in string s
Check if c equals '_'
If yes, increase count
EDIT: C++ example code:
int count_underscores(string s) {
int count = 0;
for (int i = 0; i < s.size(); i++)
if (s[i] == '_') count++;
return count;
}
Note that this is code to use together with std::string, if you're using char*, replace s.size() with strlen(s).
Also note: I can understand you want something "as small as possible", but I'd suggest you to use this solution instead. As you see you can use a function to encapsulate the code for you so you won't have to write out the for loop everytime, but can just use count_underscores("my_string_") in the rest of your code. Using advanced C++ algorithms is certainly possible here, but I think it's overkill.
Old-fashioned solution with appropriately named variables. This gives the code some spirit.
#include <cstdio>
int _(char*__){int ___=0;while(*__)___='_'==*__++?___+1:___;return ___;}int main(){char*__="_la_blba_bla__bla___";printf("The string \"%s\" contains %d _ characters\n",__,_(__));}
Edit: about 8 years later, looking at this answer I'm ashamed I did this (even though I justified it to myself as a snarky poke at a low-effort question). This is toxic and not OK. I'm not removing the post; I'm adding this apology to help shifting the atmosphere on StackOverflow. So OP: I apologize and I hope you got your homework right despite my trolling and that answers like mine did not discourage you from participating on the site.
Using the lambda function to check the character is "_" then the only count will be incremented else not a valid character
std::string s = "a_b_c";
size_t count = std::count_if( s.begin(), s.end(), []( char c ){return c =='_';});
std::cout << "The count of numbers: " << count << std::endl;
#include <boost/range/algorithm/count.hpp>
std::string str = "a_b_c";
int cnt = boost::count(str, '_');
You name it... Lambda version... :)
using namespace boost::lambda;
std::string s = "a_b_c";
std::cout << std::count_if (s.begin(), s.end(), _1 == '_') << std::endl;
You need several includes... I leave you that as an exercise...
Count character occurrences in a string is easy:
#include <bits/stdc++.h>
using namespace std;
int main()
{
string s="Sakib Hossain";
int cou=count(s.begin(),s.end(),'a');
cout<<cou;
}
There are several methods of std::string for searching, but find is probably what you're looking for. If you mean a C-style string, then the equivalent is strchr. However, in either case, you can also use a for loop and check each character—the loop is essentially what these two wrap up.
Once you know how to find the next character given a starting position, you continually advance your search (i.e. use a loop), counting as you go.
I would have done it this way :
#include <iostream>
#include <string>
using namespace std;
int main()
{
int count = 0;
string s("Hello_world");
for (int i = 0; i < s.size(); i++)
{
if (s.at(i) == '_')
count++;
}
cout << endl << count;
cin.ignore();
return 0;
}
You can find out occurrence of '_' in source string by using string functions.
find() function takes 2 arguments , first - string whose occurrences we want to find out and second argument takes starting position.While loop is use to find out occurrence till the end of source string.
example:
string str2 = "_";
string strData = "bla_bla_blabla_bla_";
size_t pos = 0,pos2;
while ((pos = strData.find(str2, pos)) < strData.length())
{
printf("\n%d", pos);
pos += str2.length();
}
The range based for loop comes in handy
int countUnderScores(string str)
{
int count = 0;
for (char c: str)
if (c == '_') count++;
return count;
}
int main()
{
string str = "bla_bla_blabla_bla";
int count = countUnderScores(str);
cout << count << endl;
}
I would have done something like that :)
const char* str = "bla_bla_blabla_bla";
char* p = str;
unsigned int count = 0;
while (*p != '\0')
if (*p++ == '_')
count++;
Try
#include <iostream>
#include <string>
using namespace std;
int WordOccurrenceCount( std::string const & str, std::string const & word )
{
int count(0);
std::string::size_type word_pos( 0 );
while ( word_pos!=std::string::npos )
{
word_pos = str.find(word, word_pos );
if ( word_pos != std::string::npos )
{
++count;
// start next search after this word
word_pos += word.length();
}
}
return count;
}
int main()
{
string sting1="theeee peeeearl is in theeee riveeeer";
string word1="e";
cout<<word1<<" occurs "<<WordOccurrenceCount(sting1,word1)<<" times in ["<<sting1 <<"] \n\n";
return 0;
}
public static void main(String[] args) {
char[] array = "aabsbdcbdgratsbdbcfdgs".toCharArray();
char[][] countArr = new char[array.length][2];
int lastIndex = 0;
for (char c : array) {
int foundIndex = -1;
for (int i = 0; i < lastIndex; i++) {
if (countArr[i][0] == c) {
foundIndex = i;
break;
}
}
if (foundIndex >= 0) {
int a = countArr[foundIndex][1];
countArr[foundIndex][1] = (char) ++a;
} else {
countArr[lastIndex][0] = c;
countArr[lastIndex][1] = '1';
lastIndex++;
}
}
for (int i = 0; i < lastIndex; i++) {
System.out.println(countArr[i][0] + " " + countArr[i][1]);
}
}