While performing a practice assignment online I came across a problem which I am not able to solve.
The user has to a number(number of sentences he will be entering) and then proceed to enter the sentences one by one, which are to be stored as strings(by the way, declaring a dynamic array of pointers is mandatory). However, since the number of sentences is not a priori deducible, I know that the size of the array of pointers actually is the number of sentences but I can't figure out how to declare a dynamic array of pointers to strings.
Using something I had already known beforehand, I figured out how to do the same but with arrays of characters, not arrays of strings. The line that declared a dynamic array of pointers to dynamic arrays of chars looked like this:
char **ptr=new char*[n] {};
So with my understanding, this creates a pointer ptr which points to a dynamic array of pointers, the elements of which each point to one array of characters. I want to do something similar now, where the result should be that ptr is a pointer to a dynamic array of pointers, the elements of which each point to a string.
Can anyone help out? I'd be thankful!
I think what you are looking for is something like
std::size_t num;
std::cout << "enter the number of sentences\n";
std::cin >> num;
std::string *sentences = new std::string[num];
for(std::size_t i=0; i!=num; ++i) {
std::cout << "enter the " << (i+1) << "th sentence\n";
std::cin >> sentences[i];
}
/*
... (do something with the sentences, accessing them as sentences[i])
*/
delete[] sentences; // free the memory
Note that this style of coding is highly discouraged. The problem is the need to manage the allocated memory: avoid memory leaks and dangling pointers (including exception safety). The correct approach is to use a container or smart pointer. For example:
std::size_t num;
std::cout << "enter the number of sentences\n";
std::cin >> num;
std::vector<std::string> sentences{num};
for(std::size_t i=0; i!=num; ++i) {
std::cout << "enter the " << (i+1) << "th sentence\n";
std::cin >> sentences[i];
}
/*
... (do something with the sentences, accessing them as sentences[i])
*/
or
std::size_t num;
std::cout << "enter the number of sentences\n";
std::cin >> num;
std::unique_ptr<std::string[]> sentences{new std::string[num]};
for(std::size_t i=0; i!=num; ++i) {
std::cout << "enter the " << (i+1) << "th sentence\n";
std::cin >> sentences[i];
}
/*
... (do something with the sentences, accessing them as sentences[i])
*/
when in both cases you don't have to worry about calling delete: the allocated memory will be automatically deleted (even if an exception occurs).
You can avoid pointers completely and use
std::vector<std::string> input;
A std::array needs to know the size at compile time, and you learn this at runtime. The vector works like an array but can have items push_backed at runtime.
You could declare pointer to some strings, using n once you know it:
std::string * pInputs = new std::string[n];
but it's easier to use the vector.
Each pInput will be a string, as with the std::vector version.
Related
#include <iostream>
#include <vector>
int main()
{
unsigned int numVec;
unsigned int input;
std::cout << "Enter Number of Vectors: ";
std::cin >> numVec;
std::vector<int>* Vec;
for (unsigned int i = 0; i < numVec; i++)
{
std::cout << "Enter Vector Value " << i << ": ";
std::cin >> input;
Vec->push_back(input);
}
std::cout << std::endl;
for (unsigned int i = 0; i < Vec->size(); i++)
{
std::cout << "Value at Index (" << i << ") " << Vec->at(i) << std::endl;
}
std::cout << std::endl;
return 0;
}
I am trying to learn how Vectors work as it is a topic that i have withheld learning for a very long time for no apparently reason.
My above code will compile and run however once i put in a number to store in the Vector it will crash.
The program did work before when i was just using a vector without the pointer but just for learning reasons i wanted to try it with a pointer, I am just wondering what am i doing wrong with this code and if someone could possibly flame me for doing something or give me some good advice on what i am doing wrong in this situation so i can learn for future reference.
Replace
std::vector<int>* Vec;
with
std::vector<int> vec;
and replace the pointer to member operator -> with the member selection operator ..
Only on rare occasions do you need to use dynamic storage for a std::vector instance, as that class does an excellent job of managing the memory for you. Currently you are not allocating any memory for your vector, and the behaviour of your code is undefined.
If you must use a pointer then write
std::vector<int>* vec = new std::vector();
and don't forget to call delete vec; when you're done. Consider using std::unique_ptr &c. so the delete is taken care of automatically.
My above code will compile and run however once i put in a number to store in the Vector it will crash.
What vector?
You never created a vector.
You only created a pointer, one which (a) is uninitialised, and (b) does not point to anything, let alone a (c) vector.
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.
Trying to figure out the reasoning behind the mechanics of c strings.
char** text;
text = new char*[5];
for(int i = 0; int < 5; int++) {
cout << endl << "Enter a phrase: ";
cin >> text[i];
cout << text[i];
}
I'm not entirely sure as to why this works for the first 2 iterations, even successfully displaying them, but gets a segfault error on the 3rd iteration.
You are using uninitialized memory. You are experiencing undefined behavior.
The line
text = new char*[5];
allocated memory for five pointers but those pointers haven't been initialized to point to anything valid. Before you can use text[i] to read data, you have to allocate memory for it.
for(int i = 0; int < 5; int++) {
cout << endl << "Enter a phrase: ";
text[i] = new char[SOME_SIZE_LARGE_ENOUGH_FOR_YOUR_NEED];
cin >> text[i];
cout << text[i];
}
Then, it should work.
You've allocated memory for 5 pointers, but you are not allocating anything that those five pointers point to. Assuming that you're using a modern 64-bit CPU with 8 byte-wide pointers, your new operator allocated exactly 40 bytes, five eight-byte pointers. Their initial contents are random, uninitialized memory, and when you write to them, they get interpreted as pointers to random memory addresses, which end up being corrupted with what you've read from std::cin. You got lucky initially, and the first two iterations scribbled over some memory somewhere, but your program continued to limp along, but you won the lottery on the third try; hitting a random address that does not exist, and segfaulting.
Although you can rewrite this to do proper allocation, if you're really trying to write C++, rather than C, here, there's no reason to allocate anything. Why do you want to deal with allocating memory, when C++ will happily do it for you?
std::vector<std::string> text;
for(int i = 0; int < 5; int++)
{
std::cout << std::endl << "Enter a phrase: ";
std::string s;
if (std::getline(std::cin, s).eof())
break;
text.push_back(s);
std::cout << s << std::endl;
}
I am new to c++ programming and I have a basic issue, I want to create N objects, N is is actually a user input.
I am specific about having object names, say beam1, beam2,...,beamX.
2 quick things
Is it possible in C++ to create dynamic object as this?
if it is how do we do tht? I am pasting code for your refrence..
#include "iostream"
# include <conio.h>
using namespace std;
// Static member variable is defined outside the class..
class beam {
public:
int length;
};
int main ()
{
int i=0, no_of_spans, j;
cout<< "Design Of a Continous Beam \n1) No Of Spans : ";
cin >> no_of_spans;
for (i =0; i < no_of_spans; i++) {
j = i;
beam;
cout << "Length of Beam" << j+1 << " is : ";
cin >> beami.length;
}
cout << "\nPress any key to continue..\n";
getch ();
}
This is obviously a code with errors, its put up as an example to get the idea.
As has already been stated by others (Luchian, John, Component and Ed) you can use a std::vector and it will dynamically grow as necessary to store the number of beam objects required.
If you wish to refer to these objects later by name you could store them in a std::map, with the key of the map being the object name (e.g. beam1, beam2, beam3, ..., beamX):
std::map<std::string, beam> beams;
for (int i = 0; i < no_of_spans; i++)
{
j = i;
beam beam;
std::string beam_name("beam" + boost::lexical_cast<std::string>(i + 1));
cout << "Length of " << beam_name << " is : ";
cin >> beam.length;
beams.insert(std::make_pair(beam_name, beam));
}
--
boost::lexical_cast<> is a mechanism for converting (in this case) an int to a std::string. There other ways to achieve this (using std::ostringstream for example).
You can use a std::vector to store the objects.
You use push_back to add elements to the vector.
Something along the lines of:
std::vector<beams> beamCollection;
for (i =0; i < no_of_spans; i++) {
j = i;
beam beami;
cout << "Length of Beam" << j+1 << " is : ";
cin >> beami.length;
beamCollection.push_back(beami);
}
Yes, of course it's possible. There are several ways.
One way, the way I'd prefer if possible/practical, is to use std::vector and push_back, transform or generate_n how ever many objects you needed.
Another way is to use new to allocate an array of the object you want. This is less preferred to using a vector however, because by using new you take on the responsibility of managing the memory -- there needs to be a delete that corresponds to every new. This can be mitigated by using a smart pointer such as std::unique_ptr, but it's often best to just avoid the cactus altogether.
Yes, it is possible. Your best bet is to use an appropriate STL collection and dynamically grow it at runtime by adding / removing objects.
Short answer no - the compiler needs to know the names of variables at compile time.
You need to use an array (or vector).
As a c++ beginner I've written the following code:
int main(void){
struct car{
char * make[200];
int manfYear;
};
int num=0;
cout << "How many cars do you wish to catalogue? ";
cin >> num;
car * Cars = new car [num];
for (int i=1;i<=num;i++){
cout << "Car #" << i << ":" << endl << "Please enter the make: ";
cin.getline(*Cars->make,200);
cout << "Please enter the year made: ";
cin >> Cars->manfYear;
}
My problem is that I can't get my head round a problem where I get a segfault when running the program at the point I need to enter the model of the car. Can someone please explain what I'm doing wrong?
As far as I understand it I'm passing a pointer to the array "make" which should make it work. Is my understanding way off?
Thanks in advance
Dan
Four issues I see right away:
Issue 1
In your struct, you have:
char * make[200];
In English, this is saying, "create an array of 200 pointers to character", when I think you want to say, "create an array of 200 characters." So you should have instead:
char make[200].
Issue 2
You are looping by starting at 1. This will skip the first car in the array - remember arrays are zero-indexed. So you should have instead:
for (int i = 0 ; i < num ; i++)
and for display purposes, you could say:
cout << "Car #" << (i+1) << ":" << endl << "Please enter the make: ";
Issue 3
Where you say:
cin.getline(*Cars->make,200);
and
cin >> Cars->manfYear;
Where in these lines are you specifying which car the user is populating? Nowhere. If you are looping with i, then you need to actually mention i. These should work:
cin.getline(Cars[i].make,200);
and
cin >> Cars[i].manfYear;
Notice that we are using ., not ->. This is because the items in the Cars array are actual instances, not pointers. The Cars array is itself a pointer, but not its contents.
Issue 4
All credit to #Ben C who pointed this out first: mixing the >> operator with getline() function on cin can lead to strange behavior, with leftover CR's from >> going into the getline() call. You could use either all >> (disadvantage: you don't have the 200 limit enforced when reading the make) or all cin.getline() (disadvantage: you will have to use string buffers and then convert them for number of cars and year), or put cin.ignore() after each invocation of >>, like so:
cin >> num;
cin.ignore();
and
cin >> Cars[i].manfYear;
cin.ignore();
Again, all credit to #Ben C for noticing this first.
Last But Not Least
By convention, classes/structs have capital names, and variables have lowercase / camelcase names. Consider renaming the struct from car to Car, and the array from Cars to cars. In other words, the reverse of the capitalization you have right now.
Finally, I concur with all the other posters here: you should consider using string instead of char arrays.
First, use string instead of poor old C char[].
Next: you don't want char * make[200];. You want char make[200];. char * make[200] is an array of 200 pointers to chars, which can be used as 200 null-terminated strings - but then, you would have to new[] each of them. Just use char make[200]; and cin.getline(Cars->make, 200);.
char * make[200] declares an array of 200 pointers; I'm guessing this isn't what you're after.
If you're simply looking to store a string, I'd recommend taking a look at the C++ string type instead.
#include <iostream>
#include <string>
int main()
{
using namespace std;
struct car
{
string make;
int manfYear;
};
int num=0;
cout << "How many cars do you wish to catalogue? ";
cin >> num;
car * Cars = new car [num];
for (int i=1;i<=num;i++)
{
cout << "Car #" << i << ":" << endl << "Please enter the make: ";
std::cin.ignore();
getline(cin, Cars[i-1].make);
cout << "Please enter the year made: ";
cin >> Cars[i-1].manfYear;
}
}
There were also a couple of other minor niggles with your code.
1) You had been using Cars->manfYear - this will only ever point you to the first element of your array. I'm assuming you don't want that; using the subscripting syntax as per Cars[i-1].manfYear will access an individual car object in your array. (Remember that array indexes start from zero! - it would actually make more idiomatic sense for your for loop variable to start at zero as well really)
2) Be wary of the way std::getline and the >> symbol work together. the >> (stream extraction operator) often leaves any newline characters, which means you might see "odd" behaviour with your calls to getline. If you're mixing the two together, then using something like std::cin.ignore() will help you discard the newline character.
First of all, arrays in C++ are indexed from 0..n-1, so your loop needs to run from
for (int i = 0; i < num; i++) { ... }
Secondly, you've declared make as a 200-element array of pointer to char; this is most likely not what you want. If make is supposed to store a character string, declare it as a plain array of char:
struct car{
char make[200];
int manfYear;
};
Finally, rewrite your getline call as
cin.getline(Cars[i].make, sizeof Cars[i].make); // fixed per comment below
Even though Cars is declared as a pointer, you can use the subscript operator on it as though it were an array; by doing so, you implicitly dereference Cars, since a[i] is interpreted as *(a + i). This also means that you will use the . component selection operator as opposed to the -> operator, since the type of Cars[i] is car, not car *.
First of all char *make[200] is not a string of max 200 characters but 200 pointers to char.
Second thing: you are dereferencing the pointer in cin.getline with *: what happens is that you obtain the value contained in first cell of the 200 char* pointers. But you didn't initialize the single pointers, just the higher level one, so you get a segfault.
Just change char* make[200] to char make[200] and *Cars->make to Cars[i].make.