In this program,I store integer values from 0 to 4 in a string and I want to print this string.
CODE:
int main()
{
string str=" ";
for(int i=0;i<5;i++)
str[i]=i+'0';
cout<<str;
return 0;
}
But when i run this program,it just shows first element(means '0') of string.
Can anybody tell me the reason,Why this program does not print whole string in output?
Actually, when you are using for loop, it is accessing position in string changing it. Since when you have initialized string as string str = " " this means our string is of single whitespace. After which for loop access that string and look for the index str[i] and changes its value to i+'0'.
So, when we are writing code as
for(int i=0; i< 5; i++){
str[i]=i+'0';
cout<<str[i];
}
it seems, like for that block, str[i] value is i+'0', which is printed, but str doesn't update. Due to which when you do cout<<str; it again shows 0 as the answer.
To solve this issue we can use property of concatenation, refer the below code
#include <iostream>
using namespace std;
int main()
{
string str;
for(int i=0;i<5;i++)
str+=i+'0';
cout<<str;
return 0;
}
This gives the required result as 01234.
Hope this helps you.
The code doesn't work as expected because you exceeded the string greatest index which is 0 because the size of your string is 1 as the previous answer say.
This is a modification
int main()
{
std::string str=" ";
for(int i=0;i<5;i++)
str[i]=i+'0';
std::cout<<str;
return 0;
}
You are exceeding array boundaries, because you initialized the string as containing only one space. If you give it more spaces, the code works:
string str = " ";
int main()
{
string str=" "; // str.size() == 1
for(int i=0;i<5;i++)
str[i]=i+'0'; // str.size() is still 1
cout<<str; // str.size() is still 1
}
In str[i], if ...
i>str.size() you are accessing the array out of bounds and get undefined behaviour.
i==str.size() (where the null terminator is) and you change that value, you also get undefined behaviour.
But when i am printing this string with the help of for loop,this program prints whole string.e.g:
for(int i=0; i<5; i++) {
cout<<str[i]<<" ";
}
Why this loop print whole string, but not cout<<str?
You've made changes out of bounds and have undefined behaviour. It's possible that you can read the values back one-by-one (instead of getting a program crash) due to short string optimization - but the size() of str is still 1 since you haven't changed the size.
If your loop had gone further, outside the area used by short string optimization, like this:
for(int i=0; i<25; i++) {
cout<<str[i]<<" ";
}
it would be even more likely to result in a crash.
when we are assigning
string str = " ";
here " " is of type const char[2];size is 2: 1 lenght of character and 1 length for '\0' (Null Terminated) character.
This gets copied into string str by calling operator= overloaded function.
When We are trying to access str[] with more than 0,1 index of subscript[] say 2 its doing memory violation and that is causing the exception "string subscript out of range",
if you try to access [0] and [1] it will work fine or instead of accessing particular location using array subscript, concatenation (+=) will help.
Related
I am trying to create a string by accessing its individual index positions and trying to print it.
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s="";
s[0]='a';
s[1]='b';
s[2]='c';
s[3]='d';
cout << s << endl;
for(int i = 0; i < 4; i++)
cout << s[i] << endl;
return 0;
}
This doesn't print a entire string but does print its individual characters.
Following code prints both the strings and its individual characters.
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s=" ";
s[0]='a';
s[1]='b';
s[2]='c';
s[3]='d';
cout << s << endl;
for(int i = 0; i < 4; i++)
cout << s[i] << endl;
return 0;
}
Why does this happen. Links to any further reading are appreciated.
Strings don't grow automatically
This string has zero size
string s="";
This code is an error because s[0] does not exist (since the string has zero size).
s[0]='a';
Because this is an error your program has undefined behaviour, which means any output is possible, including the strange behaviour you see.
If you want to add a character to a string use push_back (or +=)
s.push_back('a');
s.push_back('b');
s.push_back('c');
s.push_back('d');
Now that the string has some characters you can use [] to access them (or change them).
String, similarly to some other STL(Standard template library) classes is a dynamic template class.
What you're doing in your code is creating an empty string and then trying to insert elements into non-existing indices, which in an STL type class means you try to access a memory which was not allocated.
What you want to do when inserting elements into your string is use the push_back method, which will insert elements to the end of your string (and handle the memory allocation automatically).
If you know how many elements will be inserted before performing those actions, you can minimize the number of memory allocations by using the reserve method before using push_back.
For example, in your code we could opt to something like this:
s.reserve(5);
s.push_back('a');
s.push_back('b');
s.push_back('c');
s.push_back('d');
If we do not reserve memory ahead there could be more allocations and de-allocations as the string increases in size which can be expensive.
I tried to write a function similar to strcat() in c++.
Here is the code of this function:
char *mystrcat(char *str1, char *str2){
int i = 0;
char *buffer = str1;
while(*str1){
str1++; i++;
}
i++;
while(*str2){
str1[i] = *str2;
str2++; i++;
}
str1[++i] = '\0';
str1 = buffer;
return str1;
}
The input values for this function are given by this code:
char string1[100], string2[100];
cout << "Enter string 1 ";
cin >> string1;
cout << "Enter string 2 ";
cin >> string2;
mystrcat(string1, string2);
cout << string1 << endl;
When I ran the code and tried to input two strings, it has given me this output:
Enter string 1 qwerty
Enter string 2 asdf
qwerty
Why the first string is displayed only?
For a start, since you're incrementing both str1 and i in the first loop, you're going to move twice as fast through that array as you think. Thats because you're increasing both:
the base of the array; and
the offset from that base.
You're actually lucky to have chosen an even number of characters, otherwise you'd probably keep going beyond the end of str1 (by missing the \0), resulting in all sorts of fun and hilarity :-)
You should increment one or the other, such as with:
char *mystrcat(char *str1, char *str2) {
int i = 0;
while(str1[i] != '\0')
i++;
while(*str2 != '\0')
str1[i++] = *str2++;
str1[i] = '\0';
return str1;
}
The reason why you only get the first string after the concatenation, is the i++ after the first loop (which I've removed from the above code).
When you exit that loop, i is the index of the str1 terminator character so, an i++ at that point will jump over it. That means that you'll append str2 after that terminator:
qwerty<nul>asdf<nul>
Hence the string will only be qwerty because C strings always stop at the first terminator.
I often find it's useful to be able to start with a memory map and variable register (on paper), then run the code in your head, changing variables along the way. It helps to understand how your program will work. You can start with something like:
1 2
Index: 012345678901234567890
str1: qwerty_
str2: asdf_
i: 0
Then, each line of code in your head will result in i changing, or the string memory blocks changing (the _ at the end indicates the string terminator).
Don't increment the string pointers. Do just
while (str1[i]) {
++i;
}
And start with iterating str2 with another variable, from 0.
What you are doing currently is basically: str1[12] = str[6]
When you want: str1[6] = str2[0]
I am aware of why segmentation faults occur, but I am not able to find out the error with the following code I made to split a string on the basis of whitespaces.
#include<iostream>
#include<string>
#include<vector>
#include<typeinfo>
using namespace std;
vector<string> split(const string& s)
{
//cout << "HERE";
vector<string> tab;
for(unsigned int a = 0; a < s.size(); a++)
{
string temp = to_string(s[a]);
while(to_string(s[a]) != " ")
{
a++;
temp = temp + s[a];
}
tab.push_back(temp);
}
return tab;
}
int main()
{
int n;
cin >> n;
while(n--)
{
string s;
cin >> s;
vector<string> temp = split(s);
for(unsigned int i = 0; i < temp.size(); i++)
{
cout << temp[i] << endl;
}
}
return 0;
}
Also, if I comment out the while loop in the split function, I get numbers when I print out the resulting strings. Is it because of to_string? If I use typeid(variable).name() on the resulting strings that I get when I am printing them in the main function, I get this: NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE.
To answer your final question:
C++ often, but not always, treats a char value as numeric, and certainly does if you pass it to to_string. So to_string(' ') will return "32" (generally), which is the character code for a space converted to a string in decimal.
To convert a character to the corresponding single-element string use e.g. string(1, ' ').
For your segmentation fault the debugger is the right tool.
Your split function is buggy. Your program will always crush because while(to_string(s[a]) != " ") condition on the while loop will cause infinite loop.
It seems strange to me you are using to_string(s[a]). Lets say s[a] is really space char even in this case toString(" ") will return a std::string which contains "32". And "32" is not equal " " so this will cause your loop run infinitely.
And since in the loop you are increasing the index like below.
a++; ---> You increase the index in infite loop so a can go to millions
temp = temp + s[a]; ---> you are using the index and causing index out of range.
You will cause index out of range error.
I want to cout my string, everything works as it should, but when the string is shown, it immediately shows me the "example_4578.exe has stopped running" error. I have noticed that the problem is in the i < str[32].length part, because when I change it to i < 3, it works without any problem. How should I solve this?
std::string str[32];
cin >> str[1];
cout << "str[1]=" << str[1] << endl;
cin >> str[2];
cout << "str[2]=" << str[2] << endl;
for (int i = 0; i < str[32].length; i++)
{
cout << str[i];
}
EDIT 1.
I've made a huge mistake. I actually want to find the "number" of elements/words in "str". In my example, I have only designed two cins. But I actually want to design a "for" loop later on, so that the user can input as many words as he wants, so if he inputs 4 words, I want that code to return those number of words to me. How should I do this? In other words, how can I find out how many elements are in "str"?
Couple of things:
C++ is 0-indexed. What this means is that std::string str[32] has indices that go from 0 to 31, and str[32] should not be accessed. This will cause a crash.
str[31].length() (which is presumably what you wanted) is the length of the last string, not the length of the array. The length of the array is 32, and your loop should read for(int i = 0; i < 32; i++).
The main problem is that you are accessing an element (number 32) that is out of the bounds (0 - 31). To solve this problem and not repeat it again in the future use a range-for loop:
std::string str[32];
for (auto s : str)
std::cout << s;
str[32].length is not what you think.
I guess you meant somthing like: length of a 32-elements array. Right?
What you've written is pointer to funciton length of 33rd element of array.
This is because the types are:
std::string str[32]; // `str` is 32-element array of `std::strings`
str[32]; // `std::string` taken from 33rd position in array `str` (arrays' indexing starts at 0)
std::string has a member function named size_t std::string::length(). When referenced by name, you get its address.
To achieve what you wanted, you'd need to write:
for (int i = 0; i < 32; i++) {
cout << str[i];
}
Unfortunately, plain arrays don't have length (or anything similar) built in. So, you'd either need to use a constant, or (better) use a container, such as std::vector.
I am practising user input handling. My goal is to have the user enter a line of integers separated by space (" "), read them as integers, store them and work on them later. I stumbled upon an interesting problem (Atleast in my oppinion) the way I am doing it, it seems that it is always not reading the last digit which was entered by the user. I will post the entire program here (since there are some extra libreries that are included).
I have left some comments in the program
#include <iostream>
#include <string>
#include <vector>
#include <stdlib.h>
using namespace std;
int main()
{
//this vector will store the integers
vector<int> a;
// this will store the user input
string inp;
getline(cin, inp);
// this string will temporarily store the digits
string tmp;
//be sure that the reading part is okay
cout << inp << endl;
//until you meet something different than a digit, read char by char and add to string
for(int i = 0; i < inp.length(); i++)
{
if(isdigit(inp[i]))
{
tmp +=inp[i];
}
else
{
// when it is not a character, turn to integer, empty string
int value = atoi(tmp.c_str());
a.push_back(value);
tmp = "";
}
}
// paste the entire vector of integers
for(int i = 0; i < a.size(); i++)
{
cout << a[i] << endl;
}
return 0;
}
Replace this line
for(int i = 0; i <inp.length(); i++)
by
for(int i = 0; i <= inp.length(); i++)
DEMO IDEONE
The problem with your code is: In example 25 30 46 whenever i=7, tmp=46. You are not pushing 46 in vector as inp[8] is a newline character, so your for loop terminates after i become 7.
Please Note: i <= inp.length() runs perfectly in most of the compilers as \0 is used/treated as sentinel.However, there are few compilers(like Microsoft Visual C++) that may show Assertion error: string subscript out of range.
If the very end of the line is a digit, you don't hit the else on the last iteration, and that last number never gets pushed into the vector.
The simplest solution would be to replicate the non-digit logic after the loop:
if (!tmp.empty()) // If tmp has content, we need to put it in the vector.
{
int value = atoi(tmp.c_str());
a.push_back(value);
tmp = "";
}
Although I'm sure you can think of a nicer way of structuring it.
Here's a version I came up with using std::stringstream, that also avoids atoi:
int main()
{
std::vector<int> ints;
std::string line;
std::getline (std::cin, line);
std::cout << "Read \"" << line << "\"\n";
std::stringstream ss(line);
int remaining = line.size();
while (remaining)
{
if(std::isdigit(ss.peek())) // Read straight into an int
{
int tmp;
ss >> tmp;
ints.push_back(tmp);
}
else
{
ss.get(); // Eat useless characters
}
remaining = line.size()-ss.tellg();
}
for (auto i : ints)
std::cout << i << '\n';
return 0;
}
Running:
$ ./a.out <<< "12 34 56"
Read "12 34 56"
12
34
56
Note, this is specifically made to work with any old gibberish between the numbers:
$ ./a.out <<< "12-abc34-56"
Read "12-abc34-56"
12
34
56
If there will only be whitespace, this is even easier, as reading ints from a stringstream will ignore that automatically. In which case you just need:
int tmp;
while (ss >> tmp)
{
ints.push_back(tmp);
}
Your program need a string which is ended with a non-digit character to work correctly. Try this string "1 12 14587 15 " because in your algorithm when your forgot the last space, your program store the number into the tmp string but don't save it into the vector. To correct that you need to add a last push_back just after your first loop.
You update a with new value only when when non digit is found. Thus if you have string ending with digits, tmp will contain digital string but you will never get to else that should perform push_back. You may fix this by adding following code after for loop
if(!tmp.empty()){
// when it is not a character, turn to integer, empty string
int value = atoi(tmp.c_str());
a.push_back(value);
tmp = "";
}
Before starting the loop, add a space to the string to be sure to push the last number: inp.push_back(' ')
Your loop is finished after last digit is read, so the last digit is never turned to integer. Just add some code after original for loop.
for(int i = 0; i < inp.length(); i++)
{
/* ...... */
}
// add this to read the last digit
if(tmp.length() > 0){
int value = atoi(tmp.c_str());
a.push_back(value);
tmp = "";
}
You never push back your last value. For instance, consider this input
40 36
Then while you are reading, you push back at the first space. But you never push 36 since there are no more characters.
After the end of your for() loop you can try this:
if(!tmp.empty()) {
a.push_back(tmp);
}
When the last digit of the last number is stored in tmp, after that the loop ends because you have read the last character of the entire string. When the loop ends tmp still contains the last number.
1) You can convert and add the last number to vector after the loop. The last number still available in tmp.
2) Or you can explicitly add non-digit character in the end of the string before the loop.
you ommit input. change your code to reflrct this:
//this vector will store the integers
vector<int> a;
// this will store the user input
string inp;
getline(cin, inp);
// this string will temporarily store the digits
string tmp;
//be sure that the reading part is okay
cout << inp << endl;
//until you meet something different than a digit, read char by char and add to string
for(int i = 0; i < inp.length(); i++)
{
if(isdigit(inp[i]))
{
tmp =inp[i];
int value = atoi(tmp.c_str());
a.push_back(value);
}
else
{
tmp = "";
}
}
// paste the entire vector of integers
for(int i = 0; i < a.size(); i++)
{
cout << a[i] << endl;
}
return 0;
or replace in loop:
for(int i = 0; i <inp.length(); i++)
by
for(int i = 0; i <= inp.length(); i++)