String Class Manipulation - c++

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

Related

Matrix of characters in c++ [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I need matrix of characters to save 'n' subject (some subjects have 3-4 words). The user will enter 'n' number of subjects and names of subjects. I can only use CHAR, not STRING or VECTOR.
#include <iostream>
using namespace std;
int main() {
int n;
cin>>n;
char matrix[n][100];
for(int i=0; i<n; i++) {
cin.getline(matrix[i][100]);
}
}
First problem with your code is that you are trying to make a variable size array with static allocation which C++ won't like (your n varies and you are trying to make char matrix[n][100]). You will need to use dynamic allocation for that.
Second problem is that getline requires an additional parameter to work (max number of characters per word you can take in, which is in your case 100).
And the third problem is that you are trying to put a whole word into a place for a single character in cin.getline(matrix[i][100]);. I'm not sure you understand why are you exactly making a matrix[n][100] so I will briefly explain.
One char stores a single character, like 'a'.
char oneCharacter = 'a';
To make a word out of those you would want few characters, so you make an array of characters. In the example I made an array of character which can take up to 5 of them.
char multipleCharacters[5];
And now you want to store a few words, so you make an array of array of characters. In the example I made an array of array of characters which can take up to 10 words of 5 characters. To make an array which size you are going to input, look up dynamic allocation from the first part of my answer.
char multipleWords[10][5];
Knowing this, can you figure out whats wrong with cin.getline(matrix[i][100]);?
As I said in a comment earlier, this is a terrible assignment. You are being asked to do several things in "odd" ways, not using and learning best practices for writing code.
My advice in general: start by separating the input, output, and "work".
Let's suppose that the code for the real lesson here is all in the "work" part. There are indeed many reasons for learning to manipulate memory this way, and C++ for writing low-level, system, or efficient code is a major part of the craft.
So, you want to arrange n words into a 2-D array of characters. Focus on (just) that, by passing in the data to be so-arranged using normal C++ code. Abstract it as a class to hold the data. Maybe this is the binary image to send to a dumb LCD on a keosk, or label printer? There may be a real reason to do something like this.
Putting in a class you can make sure memory is freed correctly; normally you want no naked new's in your code, and will use existing container types rather than low-level memory. Here, we'll use a unique_ptr of rows.
class project {
static constexpr size_t rowlen = 100;
using row = char[rowlen];
std::unique_ptr<row[]> matrix;
public:
void layout (const vector<string>& inputs);
// todo.. provide a good way to access the data
};
Now don't worry about reading from the user, especially reading directly into an odd format! That just makes this extra challenging for no reason. Take the data (presented in a normal easy-to-use way) and concentrate on doing the low-level memory manipulation chore: Allocate input.size() rows, and for each input string clamp to the maximum length and copy the characters into one row (what about the rest of the chars? Assume should be space or what?)
Clamp the length using std::max. Copy the actual characters using std::copy.
Something like this (untested; just off the top of my head):
void project::layout (const vector<string>& inputs)
{
constexpr auto N = input.size();
matrix = new row[N];
for (const size_t i= 0; i < N; ++i) {
const auto len = std::max(input[i].size(), rowlen);
auto& dest = matrix[i]; // alias the whole row
char* p= &dest[0]; // pointer to first char in the row
std::copy_n (input[i].data(), len, p);
std::fill_n (p+len, rowlen-len, ' ');
}
}
See https://en.cppreference.com/w/cpp/algorithm for details on the std algorithms. Keep that site bookmarked; it is a great way to look things up while you write code.
To do this, you need to understand how pointers work in C (and thus in C++). Also, how the same "place" can be different types: A pointer to the whole row is the same address as the first character of that row, but they are different types. So do things a little piece at a time, just as with the earlier definition of matrix.

Dynamically allocated C-style string has more characters than given length?

I'm using a dynamic C-style string to read in data from a file, but for some reason when I dynamically allocate the C-style string using the given length, it comes out with four extra characters that can be seen using strlen(). The junk in these empty spaces is added on to the end of the read-in string and is displayed on cout. What on earth could be causing this, and how can I fix it?
The C-style string is declared in the beginning of the code, and is used one time before this. The time it is used before this it is also too large, but in that case it does not add extra information to the end. After use, it is deleted and not used again until this point. I'm pretty confused as I have not had this happen or had a problem with it before.
// Length read as 14, which is correct
iFile.read(reinterpret_cast<char *>(&length), sizeof(int));
tempCstring = new char[length]; // Length still 14
cout << strlen(tempCstring); // Console output: 18
// In tempCstring: Powerful Blockýýýý
iFile.read(reinterpret_cast<char *>(tempCstring), length);
// Custom String class takes in value Powerful Blockýýýý and is
// initialized to that
tempString = String(tempCstring);
// Temp character value takes in messed up string
temp.setSpecial(tempString);
delete[] tempCstring; // Temp cString is deleted for next use
When written to file:
// Length set to the length of the cString, m_special
length = strlen(chars[i].getSpecial().getStr());
// Length written to file. (Should I add 1 for null terminator?)
cFile.write(reinterpret_cast<char *>(&length), sizeof(int));
// String written to file
cFile.write(reinterpret_cast<char *>(chars[i].getSpecial().getStr()), length);
Whenever you see junk at the end of a string, the problem is almost always the lack of a terminator. Every C-style string ends in a byte whose value is zero, spelled '\0'. If you did not place one yourself, the standard library keeps reading bytes in memory until it sees a random '\0' that it sees in memory. In other words, the array is read beyond its bounds.
Use memset(tempCString,0,length) in order to zero out the memory following your allocation. However, this is not the soundest solution, as it is covering the real problem under the rug. Show us the context in which this code is used. Then I will be able to say where in your algorithm you will need to insert the null terminator: tempCString[i] = 0, or something like that. Nonetheless, from what you have posted, I can tell that you need to allocate one more character to make room for the terminator.
Also, since you are using C++, why not use std::string? It avoids these kinds of problems.

c++ string in for loop makes length 0

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.

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.

Assigning char value in one array to char value in another array

Sounds easy, but I've got a bug and I'm not sure what's causing it?
nopunccount = 0;
char *ra = new char[sizeof(npa)];
while (nopunccount <= strlen(npa)) {
ra[nopunccount] = npa[strlen(npa) - nopunccount];
nopunccount++;
}
ra never gets a value into it and I have verified that npa has char values to provide within the nopunccount range.
Any help is appreciated // :)
nopunccountstarts as 0, so in the first iteration of the loop the character assigned to ra[0] is npa[strlen(npa)]. This is the terminating '\0' of that string. So the resulting string in ra starts with a '\0' and is therefore considered to be ending at that first byte by the usual string functions.
What does the declaration of npa look like? If it is a pointer, sizeof(npa) will be the size of a pointer, rather than the allocated size. If these are zero-terminated strings (also known as "C strings"), then use strlen, not sizeof. If these aren't strings, you need to track how much you allocated in a separate variable.
I have some other critiques of this code, possibly unrelated to your problem.
while (nopunccount <= strlen(npa)) {
strlen is an O(n) operation. This code will traverse the string npa in every loop iteration. It's best to only compute the length once.
ra[nopunccount] = npa[strlen(npa) - nopunccount];
Same problem here.