I need to copy numbers from a string to another string in c++. I wrote this code but it only copies the first number in the string.
class Number{
private:
string value;
public:
void Print(){
cout<<value;
}
Number(string dgr){
int i = 0;
for(int j=0; j<dgr.length();j++){
if(isdigit(dgr[j])){
value[i]=dgr[j];
i++;
}
}
}
};
With the code you show, the string value is an empty string. That means all indexing into it will be out of bounds and you will have undefined behavior.
Instead append the characters to the string:
value += dgr[j];
operator [] in the string can be used to modify already existing characters. It does not extend the length of the string. So, if you pre-assign some value to 'value' you would see the characters modified there (up to the length of this string).
What you rally need is something like this:
value += dgr[j];
I am unable to comment but as a response to:
Wow thanks but still have a problem. when I input "a6s54da65sd4a" it returns "6546541877994624". What's that "1877994624" part? When I recompile and run it the number won't change.
I can't see the value being reset or initialized anywhere. What is the size of value?
I would use append instead of accessing various elements in "value". Something like value.append(1, dgr[j]);
Related
void staircase(int n)
{
for(int i = 1 ; i <= n ; i++)
{
string h(i,'#');
string s(n-i,' ');
cout<<s<<h<<endl;
}}
Please explain the first two lines in the for loop. Can we declare like string h(i,'#'); in strings?
Does it means filling the ith position in the string with "#"?
Can we declare like string h(i,'#'); in strings?
Yes. Actually, that's defining the string, not declaring.
Does it means filling the ith position in the string with "#"?
No.
Please use the reference pages. They are and will be your friend in the C++ journey.
For your particular use case, refer to the constructor of std::string especially this one
which has this description
Constructs the string with count copies of character ch.
These are the std::string constructors used in your code. So std::string h(i,'#') constructs a string with i copies of #. Same logic for std::string s(n-i,' ').
In the following program,
int main()
{
int i;
string a;//unallocated string;
for( i=0;i<26;i++)
{
a[i]=i+97;// trying to write a char at index i of a
}
cout<<" a[i] : ";
for(i=0;i<26;i++)
{
cout<<a[i];// printing the characters
}
cout<<"\n a as string : "<<a; // the string disappeared
}
Output :
a[i] : abcdefghijklmnopqrstuvwxyz
a as string :
My questions are
Where are the characters stored at the indices of string a reside ?
Why there is no error when I try to write in an unallocated string ?
Can someone explain what is happening ?
I'm using gcc with c++11
When you do a[i] you are using string::operator[] which explicitly says:
Returns a reference to the character at specified location pos. No bounds checking is performed
a is default constructed so it will have a size of 0. You are trying to index outside those bounds, so anything you read or write there is undefined.
It looks like you're using 26 as a magic number for the upper bound for your loops. Instead use size(a) (or before C++17 use a.size()). Then if you wanted to execute your loops 26 times, just initialize a like this: string a(26, '\0')
Live (Slightly Improved) Example
EDIT:
As pointed out by AndyG C++ does provide us with better ways of initializing our strings in this case iota is an excellent choice. Instead of your initialization for loop you could use:
iota(begin(a), end(a), 'a')
I've updated the example to include this.
To change the contents of a string in a function such that it reflects in the main function we need to accept the string as reference as indicated below.
Changing contents of a std::string with a function
But in the above code we are changing the size of string also(i.e, more than what it can hold), so why is the program not crashing ?
Program to convert decimal to binary, mind it, the code is not complete and I am just testing the 1st part of the code.
void dectobin(string & bin, int n)
{
int i=0;
while(n!=0)
{
bin[i++]= (n % 2) + '0';
n = n / 2;
}
cout << i << endl;
cout << bin.size() << endl;
cout << bin << endl;
}
int main()
{
string s = "1";
dectobin(s,55);
cout << s << endl;
return 0;
}
O/p: 6 1 1 and the program crashes in codeblocks. While the above code in the link works perfectly fine.
It only outputs the correct result, when i initialize the string in main with 6 characters(i.e, length of the number after it converts from decimal to binary).
http://www.cplusplus.com/reference/string/string/capacity/
Notice that this capacity does not suppose a limit on the length of the string. When this capacity is exhausted and more is needed, it is automatically expanded by the object (reallocating it storage space). The theoretical limit on the length of a string is given by member max_size
If the string resizes itself automatically then why do we need the resize function and then why is my decimal to binary code not working?
Your premise is wrong. You are thinking 1) if I access a string out of bound then my program will crash, 2) my program doesn't crash therefore I can't be accessing a string out of bounds, 3) therefore my apparently out of bounds string accesses must actually resize the string.
1) is incorrect. Accessing a string out of bounds results in undefined behaviour. This is means exactly what it says. Your program might crash but it might not, it's behaviour is undefined.
And it's a fact that accessing a string never changes it's size, that's why we have the resize function (and push_back etc.).
We must get questions like yours several times a week. Undefined behaviour is clearly a concept that newbies find surprising.
Check this link about std::string:
char& operator[] (size_t pos);
const char& operator[] (size_t pos) const;
If pos is not greater than the string length, the function never
throws exceptions (no-throw guarantee). Otherwise, it causes
undefined behavior.
In your while loop you are accessing the bin string with index that is greater than bin.size()
You aren't changing the size of the string anywhere. If the string you pass into the function is of length one and you access it at indices larger than 0, i.e., at bin[1], bin[2], you are not modifying the string but some other memory locations after the string - there might be something else stored there. Corrupting memory in this way does not necessarily directly lead to a crash or an exception. It will once you access those memory locations later on in your program.
Accepting a reference to a string makes it possible to change instances of strings from the calling code inside the called code:
void access(std::string & str) {
// str is the same instance as the function
// is called with.
// without the reference, a copy would be made,
// then there would be two distinct instances
}
// ...
std::string input = "test";
access(input);
// ...
So any function or operator that is called on a reference is effectively called on the referenced instance.
When, similar to your linked question, the code
str = " new contents";
is inside of the body of the access function, then operator= of the input instance is called.
This (copy assignment) operator is discarding the previous contents of the string, and then copying the characters of its argument into newly allocated storage, whose needed length is determined before.
On the other hand, when you have code like
str[1] = 'a';
inside the access function, then this calls operator[] on the input instance. This operator is only providing access to the underlying storage of the string, and not doing any resizing.
So your issues aren't related to the reference, but to misusing the index operator[]:
Calling that operator with an argument that's not less than the strings size/length leads to undefined behaviour.
To fix that, you could resize the string manually before using the index operator.
As a side note: IMO you should try to write your function in a more functional way:
std::string toOct(std::string const &);
That is, instead of modifying the oases string, create a new one.
The bounds of the string are limited by its current content. That is why when you initialise the string with 6 characters you will stay inside bounds for conversion of 55 to binary and program runs without error.
The automatic expansion feature of strings can be utilised using
std::string::operator+=
to append characters at the end of current string. Changed code snippet will look like this:
void dectobin(string & bin, int n){
//...
bin += (n % 2) + '0';
//...
}
Plus you don't need to initialise the original string in main() and your program should now run for arbitrary decimals as well.
int main(){
//...
string s;
dectobin(s,55);
//...
}
Is it possible to fix size of string variable. For example I want string variable str_new of capacity 5. P.S: I don't want to use char str_new[5]. I want to use string class. So the variable declaration should not use keyword char. Is this possible?
EXAMPLE: string str_new;
Is there any way to make sure that str_new size is fixed as 5. This question might be absurd. Please enlighten.
This code throws exception just after execution of one iteration of 'for' loop. There might be better ways to copy one string to another. But I want to copy it as mentioned below. Can someone tell me how to fix the bug, or below code cannot be fixed as its totally messed up?
string str_old = "abcde";
string str_new;
for (int i = 0; i < 5; i++)
{
str_new[i]= str_old[i];
}
However This code works fine if I do following changes
string str_new = " ";
So do I really need to explicitly initialize with blank spaces. Or there can be any other way.
You are asking two questions, and this sound very much like a homework question.
Is it possible to fix size of string variable.
There isn't any reasonable way to fix the size of a string to a size of X, and I can't think of any possible reason why you would even want to try to do so. That said, if there really is some business/homework rule that requires this, then simply check the size of the string before putting anything into it, if the size of the string plus the size of what you plan on inserting is over '5', then do something else.
For enlightenment on why, read up on the "zero one infinity rule".
This code throws exception just after execution of one iteration of 'for' loop. There might be better ways to copy one string to another.
Your code throws an exception because you are trying to replace the first character of str_new with a different character, but your object doesn't have a first character to replace.
But I want to copy it as mentioned below. Can someone tell me how to fix the bug, or below code cannot be fixed as its totally messed up?
Why do you want to use that for loop? That again leads me to believe this is some sort of homework assignment, because this is definitely not a good way to copy one string into another. A simple assignment is all that is necessary:
string str_new = str_old;
But I get it, you want to use the for loop and you don't even want a loop based on the actual size of str_old. Here you go:
string str_old = "abcde";
string str_new(5, 0);
assert(str_old.size() >= 5);
for (int i = 0; i < 5; ++i) {
str_new[i]= str_old[i];
}
The above code creates a string str_new that has five elements in it that are all equal to 0. It then checks to make sure that str_old actually is 5 characters long. Then it replaces each 0 with a copy of the character at the corresponding position in str_old.
Don't put that kind of code in a real program, but if it satisfies the homework assignment, then go for it.
Why don't you do
string.reserve()
If you want initialized a string of the right capacity, you can do
string.resize()
void resize (size_t n);
void resize (size_t n, char c);
Resize string
Resizes the string to a length of n characters.
void reserve (size_t n = 0);
Request a change in capacity
Requests that the string capacity be adapted to a planned change in size to a length of up to n characters.
If n is greater than the current string capacity, the function causes the container to increase its capacity to n characters (or greater).
I have the following code, for some reason when I try to use a for loop to declare string attribs from string wholecommand, attribs.length() returns 0 and
When i try:
cout<<attribs;
It outputs nothing.
for(int q=0;q<wholecommand.length();q++){
cout<<atrribs[q];
}
The code above is the only way i can get output. What is wrong with my code and how can I get it to output data without using a for loop?
#include<iostream>
#include<string>
using namespace std;
int main(){
string wholecommand="apple";
string atrribs;
for(int a=0;a<wholecommand.length();a++){
atrribs[a]= wholecommand[a];
}
cout<<"Content of Wholecommand: "<<wholecommand<<endl; //returns apple
cout<<"Length of Wholecommand: "<<wholecommand.length()<<endl; //returns 5
cout<<"Content of attributes: "<<atrribs<<endl; ////////contains nothing
cout<<"Length of attributes: "<<atrribs.length()<<endl; ////////returns 0
system("pause");
}
Put a
atrribs.resize(wholecommand.length());
before the for() loop to get this working properly.
You cannot assign values via std::string indices, where the target string wasn't resized to match them.
Though it's questionable, what's the purpose of your code sample as is at all? You can simply achieve the same with
atrribs = wholecommand;
without that for() loop.
attribs is constructed as a string of length 0; that's what the default ctor does. Naturally when you print a string of length 0, nothing shows up. (Even if you got around the problem of referring to elements with indices past that size.)
To make it behave, make sure it's long enough: either set it equal to something big enough (attrib = wholeCommand -- and then you're done!); or resize it; or call it with a ctor to make it big enough (string attrib (5, 'x'); // gives it 5 copies of x).
And as Paul points out above: you could just say string attrib = wholeCommand; and be done with it.
You could do the following:
string atrribs(wholecommand.length(), 0);
From version six of the string constructor, this string constructor takes as the first argument the number of consecutive characters to fill and as the second argument what characters to fill. In this example, atrribs is filled with the null character (0) five consecutive times. I could have used any character in this example.
In the first answer to this question, a resize() was suggested as a solution.
Given the code pattern, assuming that is what you really want to do, resize() adds in a bit of wasted work. You are overwriting each position in attribs. In that case, the work done by resize in growing the string and default constructing the elements is useless.
attribs.reserve() could be better. Of course, you can't use "[a] = " any more.