So I'm still learning C++ and I can't figure out what I am doing wrong. I am using the Code::Blocks IDE and despite including the vector and array header it gives me a big list of errors and says nothing was declared in this scope. The code is very basic:
#include <iostream>
#include <vector>
#include <array>
#include <string>
using namespace std;
int main()
{
string b = const, 10;
vector<string> string1(b);
array<string, b> string2;
return 0;
}
Ok, for the record, THIS IS WHAT I WAS TRYING TO DO:
"Declare a vector object of 10 string objects and an array object of 10 string
objects. Show the necessary header files and don’t use using. Do use a const for
the number of strings."
You errors are, line by line...
string b = const, 10;
That one simply makes no sense, I don't know what you were expecting there. Assign a string to b instead.
string b = "whatever";
vector<string> string1(b);
vector<T> contains no constructor that takes a T. In your case, no constructor which takes a string. If your compiler supports it, you could use:
vector<string> string1 = {b};
If it doesn't, easy enough to just...
vector<string> string1;
string1.push_back(b);
array<string, b> string2;
array<T,size_t> takes a T (string) and the number of elements, a size_t, as its template arguments. b is a string, not a size_t, so this makes no sense. Pass the size as the second template argument.
array<string, 10> string2;
Per #Benjamin Lindley's comment, perhaps you meant to declare a const int with a value of 10 in that first line. If so, then...
int main()
{
const int b = 10;
vector<string> string1(b);
array<string, b> string2;
return 0;
}
Related
I've written this code but I have some errors when I try to initialize an array of Critter objects and don't know what they're about.
My code:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Critter {
private:
string crName;
public:
Critter(string = "Poochie");
string getName() const { return crName; }
};
Critter::Critter(string n) {
crName = n;
}
int main() {
Critter c[10] = { "bob","neo","judy","patrik","popo" }; //here
return 0;
}
The errors:
E0415 - no suitable constructor exists to convert from "const char [4]" to "Critter"
...
4 more like this.
This code worked on a friend's Visual Studio 2017, but not in mine which is the 2019 version.
Thanks.
The initialization you have is for an array of strings, for the objects you need:
Critter c[10] = {Critter("bob"), Critter("neo"), Critter("judy"),
Critter("patrik"), Critter("popo")};
Or
Critter c[10] = {{"bob"}, {"neo"}, {"judy"}, //(*)
{"patrik"}, {"popo"}};
*This second method is credited to #drescherjm comment followed by #dxiv's answer, both mentioned it first.
This second initialization may be what your friend used, and maybe you forgot the braces, the IDE version difference doesn't seem relevant here.
Note that C++ provides a container for fixed size arrays, std::array:
std::array<Critter, 10> c = {Critter("bob"), Critter("neo"),
Critter("judy"), Critter("patrik"), Critter("popo")};
On a side note:
You should avoid using namespace std;
Critter c[10] = { "bob","neo","judy","patrik","popo" };
This defines an array of const char *. To initialize an array of Critter with those strings, instead:
Critter c[10] = { {"bob"}, {"neo"}, {"judy"}, {"patrik"}, {"popo"} };
[ EDIT ] It was pointed out that the same answer was first posted in a comment, only it was hidden in an external link with no indication of what's behind it, which I did not see before posting the above. Credit goes to #drescherjm so I'll leave this here as a CW.
string c[10] = {"bob","neo","judy","patrik","popo"}; Would be correct.
{"bob","neo","judy","patrik","popo"} is an array containing string elements.
You need to do
Critter c[10]={ Critter("bob"),Critter("neo"),Critter("judy"),Critter("patrik"),Critter("popo")};
C++ only allows one "user-defined conversion" at a time.
You're providing char const[N]s (let's call them char const*s for the sake of argument), which need to be turned into std::strings (which count as "user-defined" in this context), which need to be turned into Critters.
That's two conversions, not one.
That's just a limitation of C++, I'm afraid. You'll have to temporarily instantiate either strings or Critters within that initialiser.
I am trying to solve a coding question that requires the results be returned using a given struct. The struct is defined as:
struct Answer
{
const char* const* lastNames;
unsigned numberOfPeople;
}
Where the lastNames is a pointer to last names that are each terminated by a non-alpha char. I can not seem to find any way to convert the vector of strings that I am using to compile all the last names into a variable that I can assign to lastNames. I have tried making a single string with all the last names and assigning it with c_str() like so:
Ans->lastName = allNames.c_str(); but this gives me an error. Due to the limitations of the question I am unable to change the struct variable to anything else. How can I assign a string to a const char* const*
The structure being used effectively uses a C-style approach to defining a variable sized array of pointers to char (with const sprinkled over it). You’ll need storage for both the array of char const* as well as the entities pointed to. Here is how you could build it from a std::vector<std::string>:
std::vector<std::string> strings = somehow_compute_the_strings();
std::vector<char const*> array;
for (std::string const& s: strings) {
array.push_back(s.c_str());
}
Answer answer = { array.data(), array.size() };
Of course, you can’t return answer without the pointer inside pointing to stale data: you’d need to keep the two std::vectors alive. Potentially these two objects could be made members of an object the function is called on. To actually return an object of type Answer without a place to hold on to the std::vectors you could allocate the relevant entities and accept that the result will yield a memory leak unless the caller can clean the result up.
You can't just cast stuff. struct Answer is expecting a char**, so you are going to have to build it and keep it valid as long as the struct Answer is in use. At least they were kind enough to let us know they don't intend to modify it or mess with cleaning up the memory, since it takes "const char * const *".
#include <iostream>
#include <vector>
#include <string>
#include <assert.h>
typedef std::vector<std::string> VectorOfStrings_type;
struct Answer
{
const char* const* lastNames;
unsigned numberOfPeople;
};
class AnswerWrapper
{
private:
// construct and maintain memory so the pointers in the Answer struct will be valid
char ** lastNames;
unsigned int numberOfPeople;
public:
AnswerWrapper(const VectorOfStrings_type &input){
numberOfPeople = input.size();
// create the array of pointers
lastNames = static_cast<char**>(
malloc(numberOfPeople * sizeof(char*))
);
// create each string
for (unsigned int i = 0; i < numberOfPeople; ++i){
const std::string &name = input[i];
// allocate space
lastNames[i] = static_cast<char*>(
malloc(name.size() + 1)
);
// copy string
strncpy(lastNames[i], name.data(), name.size());
// add null terminator
lastNames[i][name.size()] = '\0';
}
}
operator Answer (){
return Answer{ lastNames, numberOfPeople };
}
~AnswerWrapper(){
// critcally important, left as an exercise
assert(0);
}
};
void SomeFunctionWhichUsesAnswer(Answer a){
// presumably you have some legacy C code here
// but here's a quick and easy demo
for (unsigned int i = 0; i < a.numberOfPeople; ++i)
std::cout << a.lastNames[i] << std::endl;
}
int main() {
// Here is your vector of strings
VectorOfStrings_type myData { "custom formatted data goes here", "and more here", "and again" };
// You must construct a buffer for the "Answer" type, which must remain in scope
AnswerWrapper temp{ myData };
// AnswerWrapper is currently in scope, so inside this function, the pointers will be valid
SomeFunctionWhichUsesAnswer(temp);
}
Also, I noticed that the strings in Answer are not referred to as null terminated. That is a separate issue you can take care of.
A const member variable can only be assigned in the constructor.
if you can add to the struct, define a constructor, and use the : lastname(value) syntax; or use the struct Answer myVar{value,number}; initialization, right where you declare your instance.
Another - ugly, dangerous, and frowned upon - alternative is a cast: (char**) lastname = value;, or in C++ syntax reinterpret_cast<char**>(lastname) = value.
If someone is teaching you either of those approaches, change the teacher.
I want to write a function which takes as input a pointer to a vector pointer which point to a string (Dictionary) and a pointer which points to a char (p). The function will check if the char is in the Dictionary and if it isn't there it adds the p in the vector Dictionary.
My code:
#include <iostream>
#include <string>
#include <vector>
using std::string;
using std::vector;
std::vector<string *> dictionary;
void manageDictionary(vector<string *> * dictionary, char *p) {
for (unsigned int i = 0; i < (*dictionary).size(); i++) {
string * pstring = (*dictionary).at(i);
if ((*pstring).compare(p)) {
(*dictionary).push_back(p);
}
}
}
However, the visual studio compiler shows I have an error in the if statement just before the push_back method (.). When I hover on the error, it says "no instance of overloaded function".
I added the std::vector<string *> dictionary; at the beginning, still cannot figure out where the problem is.
dictionnary is a vector of std::string*. std::string* and char* are totally unrelated types. To convert from char* to std::string* will require you to create a new string that contains the value of p for your dictionnary, rather than passing a char* directly. This change will allow your example to compile, but the resulting function is error prone.
#include <string>
#include <vector>
using std::string;
using std::vector;
void manageDictionnary(vector<string *> * dictionnary, char *p) {
for (unsigned int i = 0; i < (*dictionnary).size(); i++) {
string * pstring = (*dictionnary).at(i);
if ((*pstring).compare(p)) {
(*dictionnary).push_back(new string(p));
// Make a new string ^^^^^^^^^^
}
}
}
This solution will require you to delete your strings manually which is not the way things are done in c++. Changing from std::vector<std::string*> to simply std::vector<std::string> will solve this problem, and avoid you headaches in the future. There are other unnecessary pointers that can be removed. Since at(i) returns a string& then we should change pstring to string&. Since dictionnary is not optional (can't be nullptr) and always points to the same vector we can also change it to a vector<string>&.
void manageDictionnary(vector<string> & dictionnary, char *p) {
for (unsigned int i = 0; i < dictionnary.size(); i++) {
string & pstring = dictionnary.at(i);
if (pstring.compare(p)) {
dictionnary.push_back(p);
}
}
}
This latest version will work fine and is much more in line with c++'s philosophy for resource management. I recommend you read on a few topics :
Standard algorithms like std::find.
Range-based for loops.
const-correctness.
pointer vs reference.
Additionally, consider using std::set<string> or std::unordered_set<string> for a more convenient representation of a dictionnary.
In the future, note that the preferred way to access a pointer's methods is ptr->foo() rather than (*ptr).foo().
I have a problem in putting string value into a "structure of vectors of strings".
The simplest reproducible code is as follows:
#include <vector>
#include <string>
#include <iostream>
using namespace std;
struct ttt {
string name;
unsigned int ID;
vector<unsigned int> numList;
};
int main() {
vector<ttt> b;
b.reserve(3);
b[0].ID = 1;
b[0].numList.push_back(3);
b[0].numList.push_back(4);
string dd ("Desk");
b[0].name = dd;
cout << b[0].ID << b[0].name << b[0].numList[2] << endl;
return 0;
}
The code compiles, but it failed to put "Desk" string into b[0].name, a structure element. Segmentation Fault arose at the spot.
I also tried below lines but all of them failed.
b[0].name.push_back(dd);
b[0].name += dd;
My compiler is GCC g++ 4.7.7 20120313,
and I used below compile command.
/usr/bin/g++ --std=gnu++0x -Werror -Wall -Wextra -Warray-bounds
Any help would be deeply appreciated, sincerely.
There are two errors:
Assigning b[0] directly without calling push_back or without initializing it in a constructor call beforehand.
Another offending line is
b[0].numList[2]
because you only have called push_back() twice, and indexing is 0-based.
It would be much better to initialize the vector directly like this:
#include <string>
#include <vector>
#include <iostream>
using namespace std;
struct ttt {
string name;
unsigned int ID;
vector<unsigned int> numList;
};
int main() {
vector<ttt> b{{"Desk", 1, { 3, 4 }}};
cout << b[0].ID << b[0].name << b[0].numList[1] << endl;
}
Live Example
You may not use the subscript operator for an empty vector to assign new values to it. Use instead push_back member function.
For example
std::vector<ttt> b;
b.reserve( 3 );
//...
b.push_back( ttt() );
b.back().ID = 1;
//...
The first error reported by Valgrind on that code is
==28307== Conditional jump or move depends on uninitialised value(s)
==28307== at 0x40154F: void std::vector<unsigned int, std::allocator<unsigned int> >::emplace_back<unsigned int>(unsigned int&&) (vector.tcc:94)
==28307== by 0x4012D7: std::vector<unsigned int, std::allocator<unsigned int> >::push_back(unsigned int&&) (stl_vector.h:933)
==28307== by 0x400F00: main (39273136.cpp:17)
Whilst this might seem a bit cryptic, a bit of experience suggests to check whethe the this argument to push_back() is initialised. Looking through the code, we see:
vector<ttt> b;
b.reserve(3);
b[0].ID = 1;
b[0].numList.push_back(3);
You've told the vector to prepare to have 3 elements, but then you never add any ttt objects to it. When you access b[0], you're using uninitialised memory (Valgrind doesn't complain about the assignment to b[0].ID because the memory has been allocated and belongs to b - but calling push_back attempts to read vector members that may be random garbage).
The obvious solution is to emplace_back() (or otherwise create) the elements of b.
when you call reserve() on a vector, it doesn't create any instances of the contained type. It only allocates the space for the elements.. So when you try to access these locations in the vector, you get undefined behaviour. You must push elements into the vector first or zero-initialize them with a call like vector<ttt> b(6); before trying to do any read or write on them.
Editing just the one line where you declare the vector of ttts and removing the reserve() call fixes this program.
Also beware, because you try to access b[0].numList[2] , the third element, but you only did push_back for two elements.
#include <vector>
#include <string>
#include <iostream>
using namespace std;
struct ttt {
string name;
unsigned int ID;
vector<unsigned int> numList;
};
int main() {
vector<ttt> b(3); //create 3 zero-init elements in vector b
b[0].ID = 1;
b[0].numList.push_back(3);
b[0].numList.push_back(4);
string dd ("Desk");
b[0].name = dd;
cout << b[0].ID << b[0].name << b[0].numList[2] << endl;
//^beware, this hasn't been initialized
return 0;
}
Output: 1Desk0
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
#define attr_size 3
int main(){
const char* attr[attr_size];
int i=0;
for(i=0;i<attr_size;i++){
char* t=(char*)malloc(sizeof(int));
sprintf(t,"%d",i);
string temp="attr";
temp+=t;
attr[i]=temp.c_str();
cout<<attr[i]<<endl;
free(t);
}
for(i=0;i<attr_size;i++){
cout<<attr[i]<<endl;
}
}
And the result is:
attr0
attr1
attr2
attr2
attr
attr2
Actually, I want to get the result that:
attr0
attr1
attr2
attr0
attr1
attr2
Maybe something wrong with loop. Anybody help me?
The problem is that the c_str return a pointer that is temporary. So when the loop continue it's iteration the object you got the pointer from is destructed and the pointer is no longer valid, leading to undefined behavior when you later dereference that pointer.
If you want an array of strings, why not declare it as an array of strings?
There are also other problems with your code, like you only allocating four bytes for a string that can be 12 (with sign and string terminator) characters.
I would suggest you remake your program like this:
#include <iostream>
#include <array>
#include <sstream>
const size_t ATTR_SIZE = 3;
int main()
{
std::array<std::string, ATTR_SIZE> attr;
for (int i = 0; i < ATTR_SIZE; ++i)
{
std::istringstream is;
is << "attr" << i;
attr[i] = is.str();
}
for (const std::string& s : attr)
std::cout << s << '\n';
}
The above uses some C++11 features like std::array (you can use std::vector instead) and range-base for loop (you can use normal iteration instead).