Prog error: for replacing spaces with "%20" - c++

below is the prog i am compiling for replacing spaces with "%20" but when I run it output window shows blank and a message "arrays5.exe has occurred a prob"
#include <iostream>
#include<cstring>
using namespace std;
void method(char str[], int len) //replaces spaces with "%20"
{
int spaces, newlen,i;
for (i=0;i<len;i++)
if(str[i]==' ') spaces++;
newlen=len+spaces*2;
str[newlen]=0;
for (i=len-1;i>=0;i--)
{
if(str[i]==' ')
{
str[newlen-1]='0';
str[newlen-2]='2';
str[newlen-3]='%';
newlen=newlen-3;
}
else
{
str[newlen-1]=str[i];
newlen=newlen-1;
}
}
}
int main()
{
char str[20]="sa h ";
method(str,5);
cout <<str<<endl;
return 0;
}
Please help me finding the error.Thanks

spaces is uninitialised before you increment it.
You should give it an initial, default value.
An uninitialised variable will have a value which is undefined by the specification. This value could be 0, if you're lucky but it is highly likely that this value will be anything in the range of values which the datatype may represent.
Your program will compile and run fine when spaces is initialised properly.

I'm not fixing your problem, but providing a better solution. If you're using C++, then you should use the STL. You've got lots of classes and methods that do all of the job for you.
You could rewrite your 25 lines long method into this 4 lines long method(example included):
#include <iostream>
#include <string>
using namespace std;
std::string method(std::string str)
{
size_t index;
while((index = str.find(' ')) != std::string::npos)
str = str.replace(index, 1, "%20");
return str;
}
int main()
{
std::string str("sa h ");
str = method(str);
cout <<str<<endl; // outputs sa%20h%20
return 0;
}

I would suggest you use std::string, and use the .replace method. The reason your code doesn't work is because you're overwriting the input string in an odd way so I don't know if your expected output would be correct, however, the actual error you have is that you're potentially rewriting at index locations -3, -2, and -1. Consider the case where your first space is at index zero.
In C++, it's usually better to avoid char* unless you have a clear reason for doing so. As a matter of good style (this is somewhat subjective), I would suggest that you do NOT modify your input arguments directly, but instead return the result.
Ie, your method prototype should be:
std::string method(std::string str)
There is no-longer a need to pass the length of the string, because std::string takes care of that.

Related

Understanding String::Find In C++

I've been given a programming task that involves taking away certain letters in a string. I was trying out different ways to do this when I found the public member function string find. To put it short I was testing out the function via this program :
#include <iostream>
#include <string>
using namespace std;
int main()
{
string Word = "Applejuice";
cout<<Word.find("e")<<endl;
return 0;
}
So when I put in a letter such as "e" I get the number 4 which confuses me because I thought the function will count all the letters in that specific word such as apple juice. Also, when I use a letter that is not used in that word I get numbers like 18446744073709551615 for example when I put in X for e in the code above.
Could someone explain why this is happening, please?
string.find() will return the position of the first character of the first match.
If no matches were found, the function returns string::npos.
Therefore the number (18446744073709551615) you are getting is the string::npos
If you want to search for an only a single character in the string you can use the following code
#include <iostream>
#include <string>
using namespace std;
// Function that return count of the given
// character in the string
int count(string s, char c)
{
// Count variable
int res = 0;
for (int i=0;i<s.length();i++)
// checking character in string
if (s[i] == c)
res++;
return res;
}
// Driver code
int main()
{
string str= "Applejuice";
char c = 'e';
cout << count(str, c) << endl;
return 0;
}
If you want to avoid some random large values as output i.e. string::npos you can just add check for it like following:
if(Word.find("e") != string::npos)
{
...
}
Method find from class string return the position of the first character of the first match. Return type of find is size_t and since size_t is unsigned integral so if no match were found return string::nopos so you should compare the outputof find with string::nopos.
if(Word.find("e") != string::nopos)
{
...
}

String array homework

So i have a hw problem for my class where i have to store ten names, capitalize them and then sort them alphabetically. We just started using strings and there are some things that are still a little confusing to me. This code can store all the names in a string array, but the UpperCase seems to not be working. I dont know for sure but i think it is because I have second for loop running cap amount of times, which would be 10. And since not every string will have 10 elements, i'm running into problems?..Is that it or is it something else? Well i tried to fix this by using the .length (function?), to find the length of each name in the array, but I always get errors. Any help is appreciated, thanks!
#include<iostream>
#include<string>
using namespace std;
void UpperCase(string names[],int cap);
void print(string names[],int cap);
void swap(string names[],int &x,int &y);
string names[10];
int main(){
char a;
cout<<sizeof(a);
for(int i=0;i<10;i++){
cout<<"Enter a name for student "<<i+1<<" : ";
cin>>names[i];
cout<<endl;
}
UpperCase(names,10);
cout<<endl;
print(names,10);
cout<<endl;
print(names,10);
return 0;
}
void print(string names[],int cap){
for(int i=0;i<cap;i++)
cout<<names[i]<<endl;
}
void UpperCase(string names[],int cap){
for(int student=0;student<cap;student++){
for(int letter=0;letter<names[student].length();letter++){
if(names[student][letter]>='a')
names[student][letter]-=('a'-'A');
}
}
}
Your inner loop should be iterating for the length of the string. string::length() is a function, not a field, so you need the parentheses. There's also a standard library function for converting a character to upper case.
#include <cctype>
using std::toupper;
void UpperCase(string names[],int cap){
for(int student=0;student<cap;student++){
for(int letter=0;letter<names[student].length();letter++){
names[student][letter] = toupper(names[student][letter]);
}
}
}
..., but the UpperCase seems to not be working
So write a minimal program that just calls UpperCase on known input. It makes it easy to debug, and would also make a much better question. We don't need to see the print or swap to help with that, and prompting the user for input isn't relevant to whether UpperCase works or not.
Having said that, you should use std::string::length() - however, you say
Well i tried to fix this by using the .length (function?), to find the length of each name in the array, but I always get errors
but don't show what you actually tried, or what the errors were.
Here's a minimal, complete and self-contained program, using std::toupper as per T.C.'s answer. I changed it to demonstrate more modern style, and to show there are easier ways to confirm your functions work than to write a whole program and then find out it's broken.
#include <algorithm> // for transform, for_each
#include <cctype> // for toupper
#include <string>
#include <vector> // easier to use (correctly) than bare arrays
// change a string to upper case
void str_toupper(std::string &s) {
std::transform(s.begin(), s.end(),
s.begin(),
[](char c) -> char { return std::toupper(c); });
}
// change a vector of strings to upper case
void vec_toupper(std::vector<std::string>& v) {
std::for_each(v.begin(), v.end(), str_toupper);
}
using namespace std;
int main() {
vector<string> const input = { "bob", "alice cooper", "Eve" };
vector<string> const expected = { "BOB", "ALICE COOPER", "EVE" };
vector<string> working = input;
vec_toupper(working);
return working == expected ? 0 : -1;
// use cout or debugger to solve problem only if program returns nonzero
}

Remove character from array where spaces and punctuation marks are found [duplicate]

This question already has answers here:
C++ Remove punctuation from String
(12 answers)
Closed 9 years ago.
In my program, I am checking whole cstring, if any spaces or punctuation marks are found, just add empty character to that location but the complilor is giving me an error: empty character constant.
Please help me out, in my loop i am checking like this
if(ispunct(str1[start])) {
str1[start]=''; // << empty character constant.
}
if(isspace(str1[start])) {
str1[start]=''; // << empty character constant.
}
This is where my errors are please correct me.
for eg the word is str,, ing, output should be string.
There is no such thing as an empty character.
If you mean a space then change '' to ' ' (with a space in it).
If you mean NUL then change it to '\0'.
Edit: the answer is no longer relevant now that the OP has edited the question. Leaving up for posterity's sake.
If you're wanting to add a null character, use '\0'. If you're wanting to use a different character, using the appropriate character for that. You can't assign it nothing. That's meaningless. That's like saying
int myHexInt = 0x;
or
long long myIndeger = L;
The compiler will error. Put in the value you wanted. In the char case, that's a value from 0 to 255.
UPDATE:
From the edit to OP's question, it's apparent that he/she wanted to trim a string of punctuation and space characters.
As detailed in the flagged possible duplicate, one way is to use remove_copy_if:
string test = "THisisa test;;';';';";
string temp, finalresult;
remove_copy_if(test.begin(), test.end(), std::back_inserter(temp), ptr_fun<int, int>(&ispunct));
remove_copy_if(temp.begin(), temp.end(), std::back_inserter(finalresult), ptr_fun<int, int>(&isspace));
ORIGINAL
Examining your question, replacing spaces with spaces is redundant, so you really need to figure out how to replace punctuation characters with spaces. You can do so using a comparison function (by wrapping std::ispunct) in tandem with std::replace_if from the STL:
#include <string>
#include <algorithm>
#include <iostream>
#include <cctype>
using namespace std;
bool is_punct(const char& c) {
return ispunct(c);
}
int main() {
string test = "THisisa test;;';';';";
char test2[] = "THisisa test;;';';'; another";
size_t size = sizeof(test2)/sizeof(test2[0]);
replace_if(test.begin(), test.end(), is_punct, ' ');//for C++ strings
replace_if(&test2[0], &test2[size-1], is_punct, ' ');//for c-strings
cout << test << endl;
cout << test2 << endl;
}
This outputs:
THisisa test
THisisa test another
Try this (as you asked for cstring explicitly):
char str1[100] = "str,, ing";
if(ispunct(str1[start]) || isspace(str1[start])) {
strncpy(str1 + start, str1 + start + 1, strlen(str1) - start + 1);
}
Well, doing this just in pure c language, there are more efficient solutions (have a look at #MichaelPlotke's answer for details).
But as you also explicitly ask for c++, I'd recommend a solution as follows:
Note you can use the standard c++ algorithms for 'plain' c-style character arrays also. You just have to place your predicate conditions for removal into a small helper functor and use it with the std::remove_if() algorithm:
struct is_char_category_in_question {
bool operator()(const char& c) const;
};
And later use it like:
#include <string>
#include <algorithm>
#include <iostream>
#include <cctype>
#include <cstring>
// Best chance to have the predicate elided to be inlined, when writing
// the functor like this:
struct is_char_category_in_question {
bool operator()(const char& c) const {
return std::ispunct(c) || std::isspace(c);
}
};
int main() {
static char str1[100] = "str,, ing";
size_t size = strlen(str1);
// Using std::remove_if() is likely to provide the best balance from perfor-
// mance and code size efficiency you can expect from your compiler
// implementation.
std::remove_if(&str1[0], &str1[size + 1], is_char_category_in_question());
// Regarding specification of the range definitions end of the above state-
// ment, note we have to add 1 to the strlen() calculated size, to catch the
// closing `\0` character of the c-style string being copied correctly and
// terminate the result as well!
std::cout << str1 << endl; // Prints: string
}
See this compilable and working sample also here.
As I don't like the accepted answer, here's mine:
#include <stdio.h>
#include <string.h>
#include <cctype>
int main() {
char str[100] = "str,, ing";
int bad = 0;
int cur = 0;
while (str[cur] != '\0') {
if (bad < cur && !ispunct(str[cur]) && !isspace(str[cur])) {
str[bad] = str[cur];
}
if (ispunct(str[cur]) || isspace(str[cur])) {
cur++;
}
else {
cur++;
bad++;
}
}
str[bad] = '\0';
fprintf(stdout, "cur = %d; bad = %d; str = %s\n", cur, bad, str);
return 0;
}
Which outputs cur = 18; bad = 14; str = string
This has the advantage of being more efficient and more readable, hm, well, in a style I happen to like better (see comments for a lengthy debate / explanation).

Using resize on a string

Hi everyone well I tried looking for an answer but I couldn't find. (I found how to use it) but the thing is that i just don't know why my code isn't working. Here is my code:
#include <iostream>
#include <string>
using namespace std;
string acorta(string palabra, int carac)
{
string acortado;
acortado=palabra;
if(palabra.length() > carac)
{
return acortado;
}
else
{
acortado.resize(carac);
return acortado;
}
}
int main(int argc, char** argv) {
cout<< acorta("Univesidad",5)<<endl; // here it should show "Unive"
cout<< acorta("Secretariado",10)<<endl; //here it should show "Secretaria"
cout<< acorta("Estudio",11)<<endl; //here it should show "Estudio" since th number is long than the word
return 0;
}
well supposedly the program should receive a string and a integer because it should return the string as long as the int says. For example ("Laptop",4) it should return "Lapt". If the int is larger than the word then it should return the whole word.
The problem is that the program return the whole word when it shouldn't do the. So i think the the problem is that it is not going in to my function. Please correct me if i am wrong.
if(palabra.length() > carac)
You're telling it to return the original string if it's longer than the integer you pass in. You want to invert that:
if(palabra.length() <= carac)
Better yet, don't repeat yourself and no need for unnecessary copies of the parameter, which is already a copy of the original:
if(palabra.length() > carac)
{
palabra.resize(carac);
}
return palabra;
Or, you could make use of the substr function, though if you don't want to do needless substrings, you can tweak it:
return palabra.substr(0, carac);
If you do that, you don't even need a copy of the string anymore:
string acorta(const string &palabra, int carac)

Finding all occurrences of a character in a string

I have comma delimited strings I need to pull values from. The problem is these strings will never be a fixed size. So I decided to iterate through the groups of commas and read what is in between. In order to do that I made a function that returns every occurrence's position in a sample string.
Is this a smart way to do it? Is this considered bad code?
#include <string>
#include <iostream>
#include <vector>
#include <Windows.h>
using namespace std;
vector<int> findLocation(string sample, char findIt);
int main()
{
string test = "19,,112456.0,a,34656";
char findIt = ',';
vector<int> results = findLocation(test,findIt);
return 0;
}
vector<int> findLocation(string sample, char findIt)
{
vector<int> characterLocations;
for(int i =0; i < sample.size(); i++)
if(sample[i] == findIt)
characterLocations.push_back(sample[i]);
return characterLocations;
}
vector<int> findLocation(string sample, char findIt)
{
vector<int> characterLocations;
for(int i =0; i < sample.size(); i++)
if(sample[i] == findIt)
characterLocations.push_back(sample[i]);
return characterLocations;
}
As currently written, this will simply return a vector containing the int representations of the characters themselves, not their positions, which is what you really want, if I read your question correctly.
Replace this line:
characterLocations.push_back(sample[i]);
with this line:
characterLocations.push_back(i);
And that should give you the vector you want.
If I were reviewing this, I would see this and assume that what you're really trying to do is tokenize a string, and there's already good ways to do that.
Best way I've seen to do this is with boost::tokenizer. It lets you specify how the string is delimited and then gives you a nice iterator interface to iterate through each value.
using namespace boost;
string sample = "Hello,My,Name,Is,Doug";
escaped_list_seperator<char> sep("" /*escape char*/, ","/*seperator*/, "" /*quotes*/)
tokenizer<escaped_list_seperator<char> > myTokens(sample, sep)
//iterate through the contents
for (tokenizer<escaped_list_seperator<char>>::iterator iter = myTokens.begin();
iter != myTokens.end();
++iter)
{
std::cout << *iter << std::endl;
}
Output:
Hello
My
Name
Is
Doug
Edit If you don't want a dependency on boost, you can also use getline with an istringstream as in this answer. To copy somewhat from that answer:
std::string str = "Hello,My,Name,Is,Doug";
std::istringstream stream(str);
std::string tok1;
while (stream)
{
std::getline(stream, tok1, ',');
std::cout << tok1 << std::endl;
}
Output:
Hello
My
Name
Is
Doug
This may not be directly what you're asking but I think it gets at your overall problem you're trying to solve.
Looks good to me too, one comment is with the naming of your variables and types. You call the vector you are going to return characterLocations which is of type int when really you are pushing back the character itself (which is type char) not its location. I am not sure what the greater application is for, but I think it would make more sense to pass back the locations. Or do a more cookie cutter string tokenize.
Well if your purpose is to find the indices of occurrences the following code will be more efficient as in c++ giving objects as parameters causes the objects to be copied which is insecure and also less efficient. Especially returning a vector is the worst possible practice in this case that's why giving it as a argument reference will be much better.
#include <string>
#include <iostream>
#include <vector>
#include <Windows.h>
using namespace std;
vector<int> findLocation(string sample, char findIt);
int main()
{
string test = "19,,112456.0,a,34656";
char findIt = ',';
vector<int> results;
findLocation(test,findIt, results);
return 0;
}
void findLocation(const string& sample, const char findIt, vector<int>& resultList)
{
const int sz = sample.size();
for(int i =0; i < sz; i++)
{
if(sample[i] == findIt)
{
resultList.push_back(i);
}
}
}
How smart it is also depends on what you do with those subtstrings delimited with commas. In some cases it may be better (e.g. faster, with smaller memory requirements) to avoid searching and splitting and just parse and process the string at the same time, possibly using a state machine.