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.
Related
I found a program to print out the most frequent character in an array of char.
Here is the code.
void main()
{
int array[255] = {0}; // initialize all elements to 0
char str[] = "thequickbrownfoxjumpedoverthelazydog";
int i, max, index;
for(i = 0; str[i] != 0; i++)
{
++array[str[i]];
}
// then find the most used charater ...
}
I don't really understand what ++array[str[i]];does.
We initialized the array as int array[255] but it still accepts the index as str[i] which I believe is char type.
Is it because str[i] automatically turn into ASCII ? And what ++ preceding the command does ?
In this code
++array[str[i]];
i walks the length of str (because of the setup of the loop we are inside...).
For each character inside str, the expression str[i] gets the value of that character. I use "value" instead of "character", because it later is treated as an integer index.
With that value the expression array[str[i]] accesses one of the entries in the array. Each entry in that array corresponds to one possible ASCII "character".
The ++ increments the value in the array. I.e. it counts the number of occurrences of e.g. 'a'.
In total, the code makes a histogram of ASCII character frequency inside str.
Note however the important warning by WhozCraig, in case you intend to use this. You have to match the assumptions the code makes (copied with permission, for completeness):
Just fyi, not casting that index to unsigned char is a recipe for disaster. Further, this is not using a table guaranteed to hold enough slots to cover the domain. i.e. 1 << CHAR_BIT in width. It will "work" (term used loosely) for your input string presented here. It is not an end-all general solution to char counting.
First, the initialization of the array to size 255 is because the ascii values of the characters are in this range. so for example when you call str[i]=a it translate to the value 97 which is a part of the array. you could see the values in the following ascii table, http://www.asciitable.com
Second, the operator ++array[str[i]]; is called pre-increment which is just adds 1 to the value in the array, in the following case you could use the post-increment and you will get the same result, array[str[i]]++;
reference to read about the post/pre increment:
https://www.geeksforgeeks.org/pre-increment-and-post-increment-in-c/
I am kinda new to programming, so pardon me for any stupid questions :P, i noticed that when i write this
int main()
{
string s;
s[0]='a';
cout<<s.size();
cout<<s<<" ";
cout<<s[0];
return 0;
}
The output is 0 a , firstly why is the size 0? and why didn't anything get printed when i write cout<<s; but it gives a for cout<<s[0]. if i use push_back it gives normal out put.
int main()
{
string s;
s.push_back('a');
cout<<s.size();
cout<<s<<" ";
cout<<s[0];
return 0;
}
output :- 1a a
I might have overlooked something but i would be really appreciate if some could point out the cause.
Thank you.
EDIT: Such fast replies! thanks for your answers, i couldn't figues out how to reply to comments so edited the question body(first time using stackoverflow),
(any help on this would be appreciated as well), one more thing so when i use cout<<s[0] does it give a because a was stored on the next address of string
s?
and once again thanks for clearing that up!
What you've overlooked is that in C++ strings don't automatically grow when you assign characters to them. So
string s;
s[0]='a';
is an error because the s has size zero so there is no 'room' for the character 'a'. The correct way to add a character to a string is to use push_back which is why your second example works.
Because of the error your first example has what's called undefined behaviour (UB for short). This means the output of your program is not predictable at all, and it's more or less a waste of time asking why it outputs what it does. It could just as easily crash.
This:
string s;
creates a string containing no characters. Then this:
s[0]='a';
attempts to make a change to one of those non-existent characters. The result of this is undefined behaviour - your program goes into an unknown state.
If you would like to make your compiler warn you about this problem, you can use the at() member function of string:
s.at(0) = 'a';
Now your program will throw an std::out_of_range exception when you try to change that non-existant character.
Containers don't automatically allocate storage, so you are writing outside the allocated storage. In other words, that's a bug in your program. One advise: Many C++ implementations have a way to activate diagnostics for debugging programs, those would have caught this error.
when I write this
string s;
s[0]='a';
the output is 0, firstly why is the size 0?
The output is zero because operator[i] assumes that the string has sufficient space to store i+1 characters. In your case, string's size is zero, so accessing element at index 0 is undefined behavior.
and why didn't anything get printed when I write to cout
The same thing reason applies: after undefined behavior the program could output anything, but it happens to output nothing.
int main()
{
string s;
s='a';
cout<<s.size();
cout<<s<<" ";
cout<<s[0];
return 0;
}
Just take off [0] after s in initialisation because s is of type string not type char.
Just write s and it will work.
Important note: string (C++ object) and any other library such as array or vectors that could store unlimited characters cannot be used.
For my question:
We are given input 1, which is a sentence of unlimited characters. eg. Life is Beautiful.
Input 2: character who's location we have to find using the reference point (the middle character in input 1 after it is sorted and repeating characters are deleted) taken as zero. eg. fee.
An example:
Input 1: Life is beautiful
Input 2: see
Output: 2, -2, -2
Explanation: So firstly, we remove any spaces from input 1 and make all lowercase, then sort it in ascending order after which we find the reference letter (For above example, it's 'i'). We remove the repeating characters and then finally, put positions to character in input 1.
Example 2
Input 1: abcde
Input 2: aad
Output: -2, -2, 1
If the input 2 contains reference point, then the code returns zero.
Eg.
An example:
Input 1: abcde
Input 2: cab
Output: 0
The input1 is always odd and input2 is always 10 character max.
The problem I have is that I am not sure how to store these inputs without using strings, array etc. And even if I know how to store them, I cannot compare the inputs like input1[1] = input2[1] because we cannot use arrays/strings.
Is list an useful option with regards to important note?
I have mostly done it with the use of array but not sure how to approach it without the array. I tried to loop a character but it only stores the first character.
My practice code:
#include <iostream>
using namespace std;
int main() {
char input1;
for(int i =0; i < 3; i++ ) //for chacking whether the loops work or not.
{
cin >> input1;
}
cout<< input1;
char input2;
}
Please add any relevant tags.
I hope all the edits help.
KushanMehta proposed a C-ish solution. A more C++ one would be to implement a class wrapping a dynamic array of elements. In C++ it could be:
template <class T>
class MyArr {
protected:
T *arr; // a pointer to the dynamic array
size_t len; // the used length
size_t capacity; // the allocated capacity
...
As it contains a pointer to dynamic array, you cannot rely on default members, and should implement copy and move constructor and assignation operator and a destructor.
In order to be able to use all the goodies of C++ algorithm library, you should declare [c]begin() and [c]end() functions pointing to beginning of array and one past last element.
const T* cbegin() const {
return arr;
}
const T* cend() const {
return arr + len;
}
Then you need a subclass for characters implementing some methods to convert all characters to lower case and remove spaces, sort the array and remove duplicates. You should write io specializations for operator << and >> to be able to input strings from stdin and output them
The MyArr class can be used directly to store the resul value: just derive a specialization for int elements and implement the required specifications.
That may not be really easy, but you will learn C++ that way (not C)
You could do one thing to store the sentences by the use of dynamic memory for each character (sounds absurd but it is the only possible thing without actually worrying about the size of the input)
Meaning you take input till the user wants, in the meanwhile you can use malloc and realloc() for each new character, incrementing the size of your pointer to char for every new character.
(This is probably the way vector etc works on the naive level - not sure of this though)
Code snippet for the same:
#include <iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
int main() {
char temp;
char *sentence = (char*) malloc(2*sizeof(char));
int counter = 0;
while( cin>>temp ){
sentence[counter++] = temp;
sentence = (char*) realloc(sentence, (counter+2)*sizeof(char));
}
sentence[counter] = '\0';
cout<<"The sentence is"<<endl<<strlen(sentence)<<endl<<sentence;
}
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);
//...
}
The following code seems to be running when it shouldn't. In this example:
#include <iostream>
using namespace std;
int main()
{
char data[1];
cout<<"Enter data: ";
cin>>data;
cout<<data[2]<<endl;
}
Entering a string with a length greater than 1 (e.g., "Hello"), will produce output as if the array were large enough to hold it (e.g., "l"). Should this not be throwing an error when it tried to store a value that was longer than the array or when it tried to retrieve a value with an index greater than the array length?
The following code seems to be running when it shouldn't.
It is not about "should" or "shouldn't". It is about "may" or "may not".
That is, your program may run, or it may not.
It is because your program invokes undefined behavior. Accessing an array element beyond the array-length invokes undefined behavior which means anything could happen.
The proper way to write your code is to use std::string as:
#include <iostream>
#include <string>
//using namespace std; DONT WRITE THIS HERE
int main()
{
std::string data;
std::cout<<"Enter data: ";
std::cin>>data; //read the entire input string, no matter how long it is!
std::cout<<data<<std::endl; //print the entire string
if ( data.size() > 2 ) //check if data has atleast 3 characters
{
std::cout << data[2] << std::endl; //print 3rd character
}
}
It can crash under different parameters in compilation or compiled on other machine, because running of that code giving undefined result according to documentaton.
It is not safe to be doing this. What it is doing is writing over the memory that happens to lie after the buffer. Afterwards, it is then reading it back out to you.
This is only working because your cin and cout operations don't say: This is a pointer to one char, I will only write one char. Instead it says: enough space is allocated for me to write to. The cin and cout operations keep reading data until they hit the null terminator \0.
To fix this, you can replace this with:
std::string data;
C++ will let you make big memory mistakes.
Some 'rules' that will save you most of the time:
1:Don't use char[]. Instead use string.
2:Don't use pointers to pass or return argument. Pass by reference, return by value.
3:Don't use arrays (e.g. int[]). Use vectors. You still have to check your own bounds.
With just those three you'll be writing some-what "safe" code and non-C-like code.