How to use toupper() to convert the first letter to uppercase of each element inside a vector of strings?
This is what I've tried...
string word;
vector<string> text;
while(cin >> word){
text.push_back(word);
}
for(decltype(text.size()) i = 0; i != text.size()) {
text[0] = toupper(text);
}
You can simply do this,
string word;
vector<string> text;
while(cin >> word){
word[0] = static_cast<char>(toupper(static_cast<int>(word[0])));;
text.push_back(word);
}
Now you don't have to iterate through the word list to change the first letter of every entry to upper.
for(auto& s : text)
if (!s.empty()) s[0] = std::toupper(s[0]);
Or more fancy:
std::transform(std::istream_iterator<std::string>{std::cin}, {},
std::back_inserter(text),
[](auto s) {
if (!s.empty()) s[0] = std::toupper(s[0]);
return s;
});
There are a couple of problems with your code.
Your 2nd loop runs endlessly, you need to add ++i to the end of the loop to actually iterate each string in the vector and terminate the loop when the end of the vector is reached:
for(decltype(text.size()) i = 0; i != text.size(); ++i)
On a side note, you can replace decltype(text.size()) with vector<string>::size_type instead, or decltype(text)::size_type.
A range-based for loop would avoid both issues:
for(string &str : text)
Regarding your actual error, this line does not compile:
text[0] = toupper(text);
Because toupper() takes a single character as input, but you are passing it the vector itself, rather than a single character from a single string in the vector. You would have needed to do this instead:
text[i][0] = toupper(text[i][0]);
However, you actually need to convert characters to unsigned char when passing them to toupper(), eg (I'm separating each step so you can see it more clearly):
string &str = text[i];
char ch = str[0];
unsigned char uc = static_cast<unsigned char>(ch);
uc = toupper(uc);
ch = static_cast<char>(uc);
str[0] = ch;
text[i] = str;
Which, obviously, can also be written as a string expression, if you want:
text[i][0] = static_cast<char>(
toupper(
static_cast<unsigned char>(
text[i][0]
)
)
);
The reason why the cast is needed is explained on this reference page:
Parameters
ch - character to be converted. **If the value of ch is not representable as unsigned char and does not equal EOF, the behavior is undefined.
...
Like all other functions from <cctype>, the behavior of std::toupper is undefined if the argument's value is neither representable as unsigned char nor equal to EOF. To use these functions safely with plain chars (or signed chars), the argument should first be converted to unsigned char
Related
So the Problem was given a String Which is a Name like Sam Harris you have to output it's abbreviation what i did was find the space in the string and then taking a string otp which will add str[0] first letter of name str[pos+1] letter after position and also added a . in between but the return statement is returning some random value.Which is not expected.
#include
std::string abbrev(std::string str)
{
int pos{0};
for(int i=0;i<str.length();++i)
{
if(str[i]==' ')
{
pos=i;
break;
}
}
std::string otp=str[0]+"."+str[pos+1];
return otp;
}
int main()
{
std::string str="Sam Harris";
std::cout<<abbrev(str)<<"\n";
return 0;
}
The problem is that this here:
str[0]+"."+str[pos+1];
Isn't constructing a string. It's adding a char* to some chars, effectively performing some invalid pointer arithmetic. Fix it like this:
std::string otp = str[0] + std::string(".") + str[pos + 1];
Now std::string(".") correctly makes a std::string and appends those chars as intended using std::string's operator+.
str[0] and str[pos+1] returns a character at that position with type char. You cannot added a char variable to a constant string "." (double quoted). Overall I think it added up the constant string memory address with char values of each position and assign it to otp. For example, looking at your case, assume constant string "." have an address value 1000. The str[0] will return 'S' with ascii value 83 and str[pos+1] is expected to return 'H' with ascii value 72. Then opt will assigned with a memory address 1155 (83+1000+72), which will be an unknown program memory with junk value, which will be returned by the function. Use stringstream to concatnate string as following:
std::string abbrev(std::string str)
{
int pos{0};
for(int i=0;i<str.length();++i)
{
if(str[i]==' ')
{
pos=i;
break;
}
}
std::stringstream otp;
otp << str[0] << "." << str[pos+1];
return otp.str();
}
So you want the first letter, presumably capitalized, for each separate word in the string? Something like this should work.
std::string input = "Sam Harris";
std::string output = "";
auto n = input.find(" ");
while (n++ != input.npos)
{
output += std::to_upper(input[0]);
input = input.substr(n, input.size() - n);
n = input.find(" ");
}
Not a c++ guy, but I can give this a shot. I suspect, you're getting random stuff because you're overflowing the bounds of arrays for some inputs. Fixing that may fix your bug (example below, assuming your syntax is correct).
std::string abbrev(std::string str) {
for(int i=0;i<str.length()-1;++i) {
if(str[i]==' ') {
return str[0] + '.' + str[i +1];
}
return '';
}
Obviously you'll have to generalize for arbitrary number of spaces.
I wrote a program to remove spaces from string in c++. But when i compile this program i got two errors. They are error: initializer fails to determine size of ‘str1’ and error: array must be initialized with a brace-enclosed initializer.
Can any one show me the error of my code. I am new for C++. I mentioned my code below
#include <stack>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
char *delSpaces(char *str)
{
int i = 0, j = 0;
while (str[i])
{
if (str[i] != ' ')
str[j++] = str[i];
i++;
}
str[j] = '\0';
return str;
}
int main(){
string s;
cin >> s;
char str1[]=s;
cout << delSpaces(str1);
}
char str1[]=s;
is not valid C++.
I recommend changing your function to take a string argument by reference.
But if you can't do that, then one way to get read/write access to the char buffer of non-const s, since C++11, is
&s[0]
Since C++17 you can also use s.data().
However, note that your delSpaces creates a zero-terminated string in the supplied buffer, without knowing anything about a string. Since a string can hold any binary data s.length() would be unaffected by the call to delSpaces. You could fix that by adding a call to s.resize(), but again, a better approach is to express delSpaces with a string& argument.
You can't initialize a char[] buffer with a std::string object, that is why you are getting errors.
You would have to do something more like this instead:
char *str1 = new char[s.size()+1];
std::copy(s.begin(), s.end(), str1);
str1[s.size()] = '\0';
std::cout << delSpaces(str1);
delete[] str1;
A better option would be to change the delSpaces() function to take a std::string by reference instead:
void delSpaces(std::string &str) {
size_t j = 0;
for (size_t i = 0; i < str.size(); ++i) {
if (str[i] != ' ')
str[j++] = str[i];
}
str.resize(j);
}
...
std::string s;
std::cin >> s;
delSpaces(s);
You can even let the STL remove the space characters for you:
void delSpaces(std::string &str) {
str.erase(
std::remove(str.begin(), str.end(), ' '),
str.end()
);
}
That being said, note that by default, when operator>> is reading character data, it ignores leading whitespace and then stops reading when it encounters whitespace, so your use of operator>> in this situation will never return a std::string that has spaces in it, thus your delSpaces() function is pretty useless as shown. Use std::getline() instead, which reads until it encounters a line break, and thus can return a string with spaces in it:
std::getline(std::cin, s);
My function must process strings that look like say hello y(5) or data |x(3)|, and I need to be able to extract the integer shown and store it into a separate int variable called address. However, some strings passing through will not have any integers, and for these the address must default to 0. When a string contains an integer, it will always be in between parentheses. I've attempted to use sscanf, but, being very new to sscanf, I'm encountering problems.. For some reason, the address always reads as 0. Here's my code:
void process(string info)
{
int address = 0; // set to 0 in case info contains no digits
sscanf(info.c_str(), "%d", address);
.
.
.
// remainder of code makes other function calls using the address, etc
}
Any ideas as to why the sscanf fails to find the integer in between parentheses? Thanks!
why the sscanf fails to find the integer in between parentheses
The "%d" in sscanf(info.c_str(), "%d", address) will cause sscanf() to stop scanning once a non-numeric sequence detected. Text like "(5)" will simply stop scanning at the "(".
Instead code need to to skip over non-numeric text.
Pseudo-code
in a loop
search for any of "-+0123456789"
if not found return 0
convert from that point using sscanf() or strtol()
if that succeeds, return number
else advance to next character
Sample code
int address;
const char *p = info.c_str();
for (;;) {
p += strcspn(p, "0123456789+-");
if (*p == 0) return 0;
if (sscanf(p, "%d", &address) == 1) {
return address;
}
p++;
}
Notes:
The strcspn function computes the length of the maximum initial segment of the string pointed to by s1 which consists entirely of characters not from the string pointed to by s2. C11 7.24.5.3 2
If code wants to rely on " it will always be in between parentheses." and input like "abc()def(123)" does not occur which has preceding non-numeric data between ().:
const char *p = info.c_str();
int address;
if (sscanf(p, "%*[^(](%d", &address)==1) {
return address;
}
return 0;
or simply
int address = 0;
sscanf(info.c_str(), "%*[^(](%d", &address);
return address;
You could use something as simple as this where strchr finds the first occurrence of "(" then use atoi to return the integer which will stop at the first non-digit.
char s1[] = "hello y(5)";
char s2[] = "data [x(3)]";
char s3[] = "hello";
int a1 = 0;
int a2 = 0;
int a3 = 0;
char* tok = strchr( s1, '(');
if (tok != NULL)
a1 = atoi(tok+1);
tok = strchr( s2, '(');
if (tok != NULL)
a2 = atoi(tok+1);
tok = strchr(s3,'(');
if (tok != NULL)
a3 = atoi(tok+1);
printf( "a1=%d, a2=%d, a3=%d", a1,a2,a3);
return 0;
When a string contains an integer, it will always be in between
parentheses
To strictly conform with this requirement you can try:
void process(string info)
{
int address;
char c = '5'; //any value other than ) should work
sscanf(info.c_str(), "%*[^(](%d%c", &address, &c);
if(c != ')') address = 0;
.
.
.
}
link to a solution
int address;
sscanf(info.c_str(), "%*[^0-9]%d", &address);
printf("%d", address);
this should extract the integer between the parenthesis
How to split a string and store the words in a separate array without using strtok or istringstream and find the greatest word?? I am only a beginner so I should accomplish this using basic functions in string.h like strlen, strcpy etc. only. Is it possible to do so?? I've tried to do this and I am posting what I have done. Please correct my mistakes.
#include<iostream.h>
#include<stdio.h>
#include<string.h>
void count(char n[])
{
char a[50], b[50];
for(int i=0; n[i]!= '\0'; i++)
{
static int j=0;
for(j=0;n[j]!=' ';j++)
{
a[j]=n[j];
}
static int x=0;
if(strlen(a)>x)
{
strcpy(b,a);
x=strlen(a);
}
}
cout<<"Greatest word is:"<<b;
}
int main( int, char** )
{
char n[100];
gets(n);
count(n);
}
The code in your example looks like it's written in C. Functions like strlen and strcpy originates in C (although they are also part of the C++ standard library for compatibility via the header cstring).
You should start learning C++ using the Standard Library and things will get much easier. Things like splitting strings and finding the greatest element can be done using a few lines of code if you use the functions in the standard library, e.g:
// The text
std::string text = "foo bar foobar";
// Wrap text in stream.
std::istringstream iss{text};
// Read tokens from stream into vector (split at whitespace).
std::vector<std::string> words{std::istream_iterator<std::string>{iss}, std::istream_iterator<std::string>{}};
// Get the greatest word.
auto greatestWord = *std::max_element(std::begin(words), std::end(words), [] (const std::string& lhs, const std::string& rhs) { return lhs.size() < rhs.size(); });
Edit:
If you really want to dig down in the nitty-gritty parts using only functions from std::string, here's how you can do to split the text into words (I leave finding the greatest word to you, which shouldn't be too hard):
// Use vector to store words.
std::vector<std::string> words;
std::string text = "foo bar foobar";
std::string::size_type beg = 0, end;
do {
end = text.find(' ', beg);
if (end == std::string::npos) {
end = text.size();
}
words.emplace_back(text.substr(beg, end - beg));
beg = end + 1;
} while (beg < text.size());
I would write two functions. The first one skips blank characters for example
const char * SkipSpaces( const char *p )
{
while ( *p == ' ' || *p == '\t' ) ++p;
return ( p );
}
And the second one copies non blank characters
const char * CopyWord( char *s1, const char *s2 )
{
while ( *s2 != ' ' && *s2 != '\t' && *s2 != '\0' ) *s1++ = *s2++;
*s1 = '\0';
return ( s2 );
}
try to get a word in a small array(obviously no word is >35 characters) you can get the word by checking two successive spaces and then put that array in strlen() function and then check if the previous word was larger then drop that word else keep the new word
after all this do not forget to initialize the word array with '\0' or null character after every word catch or this would happen:-
let's say 1st word in that array was 'happen' and 2nd 'to' if you don't initialize then your array will be after 1st catch :
happen
and 2nd catch :
*to*ppen
Try this. Here ctr will be the number of elements in the array(or vector) of individual words of the sentence. You can split the sentence from whatever letter you want by changing function call in main.
#include<iostream>
#include<string>
#include<vector>
using namespace std;
void split(string s, char ch){
vector <string> vec;
string tempStr;
int ctr{};
int index{s.length()};
for(int i{}; i<=index; i++){
tempStr += s[i];
if(s[i]==ch || s[i]=='\0'){
vec.push_back(tempStr);
ctr++;
tempStr="";
continue;
}
}
for(string S: vec)
cout<<S<<endl;
}
int main(){
string s;
getline(cin, s);
split(s, ' ');
return 0;
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Splitting a string in C++
Im trying to create a function that mimics the behavior of the getline() function, with the option to use a delimiter to split the string into tokens.
The function accepts 2 strings (the second is being passed by reference) and a char type for the delimiter. It loops through each character of the first string, copying it to the second string and stops looping when it reaches the delimiter. It returns true if the first string have more characters after the delimiter and false otherwise. The position of the last character is being saved in a static variable.
for some reason the the program is going into an infinite loop and is not executing anything:
const int LINE_SIZE = 160;
bool strSplit(string sFirst, string & sLast, char cDelim) {
static int iCount = 0;
for(int i = iCount; i < LINE_SIZE; i++) {
if(sFirst[i] != cDelim)
sLast[i-iCount] = sFirst[i];
else {
iCount = i+1;
return true;
}
}
return false;
}
The function is used in the following way:
while(strSplit(sLine, sToken, '|')) {
cout << sToken << endl;
}
Why is it going into an infinite loop, and why is it not working?
I should add that i'm interested in a solution without using istringstream, if that's possible.
It is not exactly what you asked for, but have you considered std::istringstream and std::getline?
// UNTESTED
std::istringstream iss(sLine);
while(std::getline(iss, sToken, '|')) {
std::cout << sToken << "\n";
}
EDIT:
Why is it going into an infinite loop, and why is it not working?
We can't know, you didn't provide enough information. Try to create an SSCCE and post that.
I can tell you that the following line is very suspicious:
sLast[i-iCount] = sFirst[i];
This line will result in undefined behavior (including, perhaps, what you have seen) in any of the following conditions:
i >= sFirst.size()
i-iCount >= sLast.size()
i-iCount < 0
It appears to me likely that all of those conditions are true. If the passed-in string is, for example, shorter than 160 lines, or if iCount ever grows to be bigger than the offset of the first delimiter, then you'll get undefined behavior.
LINE_SIZE is probably larger than the number of characters in the string object, so the code runs off the end of the string's storage, and pretty much anything can happen.
Instead of rolling your own, string::find does what you need.
std::string::size_type pos = 0;
std::string::size_type new_pos = sFirst.find('|', pos);
The call to find finds the first occurrence of '|' that's at or after the position 'pos'. If it succeeds, it returns the index of the '|' that it found. If it fails, it returns std::string::npos. Use it in a loop, and after each match, copy the text from [pos, new_pos) into the target string, and update pos to new_pos + 1.
are you sure it's the strSplit() function that doesn't return or is it your caller while loop that's infinite?
Shouldn't your caller loop be something like:
while(strSplit(sLine, sToken, '|')) {
cout << sToken << endl;
cin >> sLine >> endl;
}
-- edit --
if value of sLine is such that it makes strSplit() to return true then the while loop becomes infinite.. so do something to change the value of sLine for each iteration of the loop.. e.g. put in a cin..
Check this out
std::vector<std::string> spliString(const std::string &str,
const std::string &separator)
{
vector<string> ret;
string::size_type strLen = str.length();
char *buff;
char *pch;
buff = new char[strLen + 1];
buff[strLen] = '\0';
std::copy(str.begin(), str.end(), buff);
pch = strtok(buff, separator.c_str());
while(pch != NULL)
{
ret.push_back(string(pch));
pch = strtok(NULL, separator.c_str());
}
delete[] buff;
return ret;
}