c++ string in for loop makes length 0 - c++

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.

Related

Reversing input, output string is unexpectedly empty

#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1;
cin>>s1;
int n=s1.size();
string s2;
for(int a=0;a<n;a++)
{
s2[a]=s1[n-1-a];
}
cout<<s2;
}
However I am not getting any output, But I can print elements of reversed string. Can anybody please help.
string s2; // no size allocated
for(int a=0;a<n;a++)
{
s2[a]=s1[n-1-a]; // write to somewhere in s2 that doesn't exist yet
You are writing into elements of s2 that you never created. This is Undefined Behaviour, and anything may happen, including appearing to work normally. In this case, you are probably overwriting some random place in memory. It might crash, or that memory might really exist but not break anything else right away. You might even be able to read that back later, but it would only seem to work by pure accident.
You could catch this problem by always using s2.at(a) to access the data, as it will do a range check for you. ([] does not do a range check). There's a cost to this of course, and sometimes people will skip it in circumstances where they are certain the index cannot be out of bounds. That's debateable. In this case, even though you were probably sure you got the maths right, it still would have helped catch this bug.
You need to either create that space up front, i.e. by creating a string full of the right number of dummy values, or create the space for each element on demand with push_back. I'd probably go with the first option:
string s2(s1.size(), '\0'); // fill with the right number of NULs
for(int a=0;a<n;a++)
{
s2.at(a)=s1.at(n-1-a); // overwrite the NULs
You might want to choose a printable dummy character that doesn't appear in your test data, for example '#', since then it becomes very visible when you print it out if you have failed to correctly overwrite some element. E.g. if you try to reverse "abc" but when you print it out you get "cb#" it would be obvious you have some off-by-one error.
The second option is a bit more expensive since it might have to do several allocations and copies as the string grows, but here's how it would look:
string s2; // no space allocated yet
for(int a=0;a<n;a++)
{
s2.push_back(s1.at(n-1-a)); // create space on demand
I assume you are doing this as a learning exercise, but I would recommend against writing your own reverse, since the language provides it in the library.
You are utilizing something called Undefined Behaviour in your code. You try to access element of s2 at a position, but your string does not have that many chars (it's empty).
You can use std::string::push_back function to add a character on the last postion, so your code would look like this:
for(int a=0;a<n;a++)
{
s2.push_back(s1[n-1-a]);
}
EDIT, to address the other question, your console window probably closes before you can notice. That's why "you don't get any output".
Try this: How to stop C++ console application from exiting immediately?
You can use the inbuilt reverse function in c++
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s1 = "string1";
reverse(s1.begin(),s1.end());
cout << s1;
return 0;
}
Hope that helps :)
You can just construct the string with reverse iterators:
std::string reverse ( std::string const& in )
{
return std::string { in.crbegin(), in.crend() };
}

std::out the outer dimension of a 2d char

Create a console application with the following code (renaming f to your entry point):
#include <iostream>
void f(){
char a[5][5];
std::cin>>a[0]>>a[1]>>a[2]>>a[3]>>a[4];
for (int y = 0; y<5; y++)std::cout<<a[y]<<'\n';
}
and input 5 lines of 5 characters such as :
abcde
abcde
abcde
abcde
abcde
I expected the output to be identical to the input or throw an error, but instead I got:
abcdeabcdeabcdeabcdeabcde
abcdeabcdeabcdeabcde
abcdeabcdeabcde
abcdeabcde
abcde
When investigated using the debugger, each a[y] value is equal to abcde and not the displayed output.
What on earth is going on here? Why is this happening, and is there a way to stop it?
Is it related to the
Stack around the variable 'a' was corrupted
Error that gets thrown after it std::couts?
I'm well aware of other ways to get the desired output using nested loops, but I'm wondering if there's a way to iterate only the outer dimension so it uses fewer characters - this is for a code golf challenge. It makes quite a difference:
for(int y=0;y<5;y++)std::cout<<a[y]<<'\n';
vs
for(int y=0;y<5;y++){for(int x=0;x<5;x++)std::cout<<a[y][x]}std::cout<<'\n';
The problem is caused by the fact that you are trying to store "abcde" in a char array with 5 elements. You need at least one more element in the array to hold the terminating null character.
As a consequence, your program has undefined behavior. We can try to make sense of the output but it's futile.
Use
char a[5][6]; // Anything greater than 5 will work for your input
If you don't want your code to be tied to a hard coded size, you can use std::string.
std::string a[5];
A C-string is an sequence of characters that ends with a null terminator. That means "abcde" is actually 6 characters long, the 5 you see plus the null terminator.
Since you only allocated enough space for the input without the null terminator trying to put the string into the array writes off the end of the array and is undefined behavior. What you need is
char a[5][6];
As that will have enough space for the 5 characters plus the null terminator.

String Class Manipulation

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).

Segmentation Fault on Assigning string Array

I have been trying to return an array of strings for a function for a couple of days to no avail. While I was searching around StackOverflow, I found that it would be a better idea to have a parameter that will be assigned the value of an array. So, here is my code example (not the actual usage, but a mockup of how I am trying to use the function). I am sorry if the code is a bit sloppy. I have been testing things out with it for a while.
void splitOn(string message, string delim, string***toCh) {
string** rString = new string*;
string lArr[numberOf(message, delim)+1];
for(int index=0; index<numberOf(message, delim)+2; index++) {
lArr[index]=message.substr(0, message.find(delim)).c_str();
message = message.substr(message.find(delim)+1, message.length());
rString[index]=&lArr[index];
cout << "IN LOOP "<<*rString[index]<<endl;
}
rString[numberOf(message, string(delim))] = &message;
toCh=&rString;
}
int main(){
string***arr;
splitOn("fox.over.lazy.dog", ".", arr);
cout << **arr[0]<<endl;
Note:
numberOf() takes a string and a delimiter(string) and returns how many times the delimiter is found within the string.
strings are from std::string
lArr (the local array within the loop) and *rString all give correct output.
Although I am trying to assign the array to a parameter, learning how to return an array is more appealing to me.
I could hack this together with a file and getLine(), but I would prefer to learn how to properly do this.
You're trying to return local variables, which will never work. You and your caller need to agree on how to allocate the return value. In C++ as the commenters mention this would normally be done by passing a reference to a vector to handle your allocation for you.
In C you have two options, you can either get the caller to pass in a big enough allocation, or use multiple calls to malloc in the callee (not forgetting the calls to free in the caller!)
For instance, if you pass a writable character array, you can simply overwrite the separator characters with null characters to split it up into individual strings without having to allocate new copies.

C++ Multi dimensional array from external file question

I'm trying to get a contiguous line with values separated by "&" to load into a multi-dimensional array. Here's the way I'm trying to do it - Everything checks out in the code, except the string "str" which contains my separated values in the format "value1, value2, value3, etc..." just loads that whole string into array[0][0]. I know there are better ways of doing this, but what I would like to know is why C++ won't treat "str" as if I had typed out the individual values and hard coded "array".
Here is the code:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main(int argc, char* argv[])
{
string str, strTotal;
ifstream in;
in.open("Desktop/01_001.PAC");
getline(in,str);
while ( in ) {
strTotal += str;
getline(in,str);
}
string searchString( "&" );
string replaceString( ", " );
assert( searchString != replaceString );
string::size_type pos = 0;
while ( (pos = str.find(searchString, pos)) != string::npos ) {
str.replace( pos, searchString.size(), replaceString );
pos++;
}
string array[4][5] = {str};
cout << array[0][0];
return(0);
}
And here is the external file ("Desktop/01_001.PAC"):
void&void&void&void&a&a1&a2&a3&b&b1&b2&b3&c&c1&c2&c3&d&d1&d2&d3
Thanks in advance!
Because code and data are different things. Your code is compiled before it runs.
It sounds as if this is what you expect:
The string contains the text "foo, bar, baz".
The statement string[] whatever = {str}; is run.
Since "str" contains "foo, bar, baz", you want it to have the same effect as if the line of code were actually string[] whatever = {"foo", "bar", "baz"}.
Asking something like this implies a complete misunderstanding of how programming works.
Nothing this magical will ever happen in C++. It cannot, because (a) what if you actually wanted to put 'str' into the array? (b) what if 'foo', 'bar' and 'baz' were also variables in your program - should they be interpreted the same way?
Variable names are not text. They no longer exist, for all practical purposes, at the time that your code runs. They are only there so that you, as the programmer, can say "the value that is used over here should be the same one that is used over there".
Further, array initializations in C++ do not care how many elements are actually in the initialization vs. the declared size of the array. Any additional elements will be default-initialized (i.e., assigned empty strings).
A string cannot be treated like an array of strings, because it isn't one. If you want an array of strings, then build it, using the individual string elements as you determine them.
But since you don't know in advance how many elements there are, you should use std::vector instead of an array. And why are you trying to arrange the data into a 2-dimensional structure? How are you expecting to know how "wide" it should be?
If I'm reading your code correctly, you appear to be searching through the string (loaded from file), and only assigning the very last result to an array index (x=4, y=5). So your code is doing something like this:
while (have not found last variable)
search for next variable in string
assign variable to (4,5) in matrix
So that last assignment might even work, but since you only assign at the end, the array is not going to be filled the way I think you want it to be filled.
I'm going to assume the matrix you want is always the same size, otherwise things get more complicated. In this case, you could use something like this:
let xMax = 4
let yMax = 5
for (x from 0 to xMax)
for (y from 0 to yMax)
find the next variable in the string
assign it to the current (x,y) location in matrix
Debug statements are your friend here! Try the above solution without saving it to an array, and instead print out each term, to see if it is working correctly.
I would also point out that the string "void" is not the C++ keyword void, and so will not work if you want an array index to be void. Try getting your code to work without voids at first.