Dynamically Allocated Array of Structures: Assignment Issues (C++) - c++

It's the last problem of the set. I need to created a dynamically allocated array of structures, and then I must access the data in these structures to insert into the output stream. Problem is, the compiler I'm using (g++) won't accept the way I'm assigning values to the structures in the array. Here is the code:
#include <iostream>
#include <cstring>
using namespace std;
struct candy
{
string name;
float weight;
int cal;
};
int main()
{
candy * pc = new candy [3];
pc[0] = {"ChocoBar", 4.5, 230};
pc[1] = {"SugarCrack", 9.3, 690};
pc[2] = {"TamponBar", 1.3, 100};
cout << "Bar None:\n";
cout << "Name: " << pc[0].name << endl;
cout << "Weight: " << pc[0].weight << endl;
cout << "Calories: " << pc[0].cal << "\n\n";
cout << "Bar One:\n";
cout << "Name: " << pc[1].name << endl;
cout << "Weight: " << pc[1].weight << endl;
cout << "Calories: " << pc[1].cal << "\n\n";
cout << "Bar Two:\n";
cout << "Name: " << pc[2].name << endl;
cout << "Weight: " << pc[2].weight << endl;
cout << "Calories: " << pc[2].cal << "\n\n";
delete [] pc;
return 0;
}
Having defined the structure type -- candy; and created a pointer(pc) to hold the address in memory assigned for three structures by new, I then attempted to assign values to the three structures. However, the compiler spit out a message saying that "extended initializer lists are not available...", which tells me that I botched the code such that the compiler doesn't even recognize my structure type as a structure (otherwise it would accept my list of three values).
I've just today learned of arrays, structures, pointers, and dynamic allocation of variables, and when it comes to arrays of structures statically assigned, and structures and arrays dynamically assigned (separately), I completed the exercises on the first try; but dynamically-assigned arrays of structures are giving me copious grief.
Please help.

First of all, you need to include the <string> header for std::string. Second, you need to ensure your compiler supports C++11. That would make the following code legal:
#include <iostream>
#include <string> // for std::string
struct candy
{
std::string name;
float weight;
int cal;
};
int main()
{
candy* pc = new candy[3];
pc[0] = {"ChocoBar", 4.5, 230}; // requires C++11
delete [] pc;
}
Next, you can learn about std::vector, a class template that does the dynamic memory allocation/de-allocation for you, and can resize its storage, effectively acting like an array that can grow in size:
#include <iostream>
#include <string>
#include <vector>
struct candy
{
std::string name;
float weight;
int cal;
};
int main()
{
using std::cout;
using std::endl;
using std::vector;
vector<candy> pc;
pc.push_back({"ChocoBar", 4.5, 230});
pc.push_back({"SugarCrack", 9.3, 690});
for (size_t i = 0; i < pc.size(); ++i)
{
cout << "Name: " << pc[i].name << endl;
}
}
Note that in C++11 you can also initialize the vector with a set of elements:
std::vector<candy> candies{{"ChocoBar", 4.5, 230},
{"SugarCrack", 9.3, 690},
{"TamponBar", 1.3, 100}};

Related

C++: How to access a member variable whose name is stored in an array

Suppose I have a string array like this:
string registers[2] = {"r0","r1"}
And a struct like this:
struct cpu {
int r1;
}
I tried something like this:
cpu *p = (cpu*)malloc(sizeof(cpu));
cout << p->registers[1] << endl;
But this gave a compilation error. How to implement this?
EDIT: Problem description
I need to access the member of a cpu class using an index so I thought I could just put the names of the memebers in an array and then get the name of the member using the index
Your code is completely illformed. Expression p->registers uses default operator -> which requires left-hand operator to be a pointer to a type which would have a member with name used as right-hand operator (registers). Your cpu doesn't contain registers.
Steps to emulate behaviour like one you desire for whatever reason that is:
design a way to associate particular string to a member of cpu, by index or pointer to member.
map the string value to an index or a pointer to member.
C++ allows to encapsulate that using member operators,which would result in something like p["r0"] yielding a reference to r0.
In simplest case, when all elements are of same type, you may just use a std::map or a class designed similarly, e.g.
struct cpu {
std::map<std::string, int> registers;
// constructor initializes the map
cpu() : registers ( { {"r0", 0},
{"r1", 0}
})
{}
};
Here an expression p->registers["r0"] would give you reference to value associated with "r0" key, etc.
NB The creation of cpu object should be
cpu *p = new cpu();
Here is an example that uses a mapping of string to cpu member:
#include <iostream>
#include <string>
#include <map>
using namespace std;
struct cpu {
int r0;
int r1;
};
map<string,int cpu::*> registers = {
{"r0",&cpu::r0},
{"r1",&cpu::r1}
};
int main()
{
cpu x{0, 1};
cout << " x.r1 = " << x.r1 << ", x.*registers[\"r1\"] = " << x.*registers["r1"] << "\n";
x.*registers["r1"] = 2;
cout << " x.r1 = " << x.r1 << ", x.*registers[\"r1\"] = " << x.*registers["r1"] << "\n";
cpu *p = &x;
p->*registers["r1"] = 3;
cout << "p->r1 = " << p->r1 << ", p->*registers[\"r1\"] = " << p->*registers["r1"] << "\n";
return 0;
}
Try it here: https://onlinegdb.com/d2KqBH0Mo
And here is one that, like your original example, uses an integer index into an array:
#include <iostream>
#include <string>
#include <map>
using namespace std;
struct cpu {
int r0;
int r1;
};
int cpu::* registers[] = {
&cpu::r0,
&cpu::r1
};
int main()
{
cpu x{0, 1};
cout << " x.r1 = " << x.r1 << ", x.*registers[1] = " << x.*registers[1] << "\n";
x.*registers[1] = 2;
cout << " x.r1 = " << x.r1 << ", x.*registers[1] = " << x.*registers[1] << "\n";
cpu *p = &x;
p->*registers[1] = 3;
cout << "p->r1 = " << p->r1 << ", p->*registers[1] = " << p->*registers[1] << "\n";
return 0;
}
Try it here: https://onlinegdb.com/3hWpmEijs

Difference in the usage of function prototype with / without pointers

I'm following simple C++ tutorial.
#include <iostream>
using namespace std;
int main()
{
int a = 1, b = 2;
cout << "Before swapping " << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
swap(a,b);
cout << endl;
cout << "After swapping " << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
return 0;
}
void swap(int &n1, int &n2)
{
int temp;
temp = n1;
n1 = n2;
n2 = temp;
}
The above code works fine (both g++ and icc), but if I were to use pointers in the functions the code fails if I do not include the prototype at the head of the program.
#include <iostream>
using namespace std;
void swap(int*, int*); // The code fails if I comment this line.
int main()
{
int a = 1, b = 2;
cout << "Before swapping" << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
swap(&a, &b);
cout << endl;
cout << "After swapping" << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
return 0;
}
void swap(int* n1, int* n2)
{
int temp;
temp = *n1;
*n1 = *n2;
*n2 = temp;
}
As far as I know, C++ compiling process is top-bottom, so the 2nd code seems more reasonable in which the information of the function is provided before int main() is encountered. My question is, why the 1st code works fine even without the knowledge of function before int main()?
The issue with the first program is you're not actually calling your own swap function. At the top of the file, you have:
using namespace std;
which brings std::swap into scope and that's the function that you're actually calling. If you put a cout statement in your own swap you'll see that it's never actually called. Alternatively, if you declare your swap before main, you'll get an ambiguous call.
Note that this code is not required to behave like this, since iostream doesn't necessarily bring std::swap into scope, in which case you'll get the error that there is no swap to call.
In the second program, the call to swap(&a, &b) fails because there is no overload of std::swap that accepts 2 temporary pointers. If you declare your swap function before the call in main, then it calls your own function.
The real bug in your code is the using namespace std;. Never do that and you'll avoid issues of this nature.
The reason why the first version works is because it doesn't call your swap(...) function at all. The namespace std provides - Edit: depending on the headers you (and the standard headers themselves) include - swap(...) functions for various types and integers are one of them. If you would remove using namespace std you would have to type std::swap(...) to achieve the same effect (same goes for std::cout, std::endl).
That's one reason why using namespace is a double-edged sword for beginners in my opinion but that's another topic.
Your code is fine; but you're right, it fails if you comment on the line you point to.
But actually, as the others tell you, there is a Swap function in c ++, so it doesn't matter if you create a prototype of the function and do it later because the compiler calls its own swap function.
But since swap works for any data type, except for pointers, then you will understand the reason for your problem, since in this case you do have to create your own swap function that accepts pointers as parameters.
Just move your function above main to make it work correctly, nothing more:
#include <iostream>
using namespace std;
//void swap(int*, int*); // The code fails if I comment this line.
void swap(int* n1, int* n2)
{
int temp;
temp = *n1;
*n1 = *n2;
*n2 = temp;
}
int main()
{
int a = 1, b = 2;
cout << "Before swapping" << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
swap(&a, &b);
cout << endl;
cout << "After swapping" << endl;
cout << "a = " << a << endl;
cout << "b = " << b << endl;
return 0;
}

Allocating dynamically an array of Strings in C++

I have allocated a string array in CPP with initial size and I need to dynamically resize it based on a counter.
This the initialization statement: string buffer[10];
I need to resize it based on a counter.
Is there a realloc function in cpp?
You should use something like a linked list such as std::vector or std::list to do so, here is an example:
#include <iostream>
#include <stdlib.h>
#include <string>
#include <list>
using namespace std;
int main()
{
list<string> buffer;
int count = 0;
while (true)
{
string s;
cin >> s;
if (s._Equal("exit"))
break;
buffer.push_back(s);
count++;
}
cout << endl << endl << "We have a total of " << count << " string(s):";
for (auto i = buffer.begin(); i != buffer.end(); i++)
cout << endl << "- " << (*i).c_str();
cout << endl << endl;
system("pause");
return 0;
}
link: std::vector
std::vector is a sequence container that encapsulates dynamic size arrays.

Assigning a value to char* in a struct

I have problem with my code i cant assign a string value into char* in a struct. Can someone tell me what is wrong with my code and why?
#include <iostream>
using namespace std;
typedef struct{
char* name;
char* city;
int age;
} person;
void main()
{
person * user;
user = (person*)malloc(sizeof(person*));
cout << "Please fill in the user info.." << endl << "Name: ";
cin >> user->name;
cout << "Age: ";
cin >> user->age;
cout << "City";
cin >> user->city;
cout << "The user info is:" << endl << "Name: " << user->name << endl << "Age: " << user->age << endl << "City: " << user->city << endl;
system("pause");
}
Thank you very much.
Your code is a horrible mix of C and C++ style, as Mike's comment says, pick a language and use it properly.
#include <iostream>
#include <string>
using namespace std;
struct person {
string name;
string city;
int age;
};
int main()
{
person user;
cout << "Please fill in the user info.." << endl << "Name: ";
cin >> user.name;
cout << "Age: ";
cin >> user.age;
cout << "City";
cin >> user.city;
cout << "The user info is:\n" << "Name: " << user.name << "\nAge: " << user.age << "\nCity: " << user.city << endl;
system("pause");
}
Don't dynamically allocate when you don't need to (then there's no risk of mallocing the wrong amount of memory, and no risk of not mallocing memory for the strings, which are both mistakes you made in your original program).
main must return int not void
typedef struct {...} x; is not necessary in C++, just say struct x {...};
Don't overuse endl
You've tagged the question with two different languages, and seem to be coding in a ghastly blend of the two. You should choose one language and stick to that.
If this is meant to be C++, then use the standard library:
#include <string>
#include <iostream>
struct person {
std::string name;
std::string city;
int age;
};
int main() { // not void
person user;
// ...
std::cin >> user.name;
// ...
}
If it's meant to be C, then you need to allocate memory for the strings. Either allocate them from the heap:
person user;
user.name = malloc(MAX_NAME_SIZE);
user.city = malloc(MAX_CITY_SIZE);
or embed them in the structure:
typedef struct {
char name[MAX_NAME_SIZE];
char city[MAX_NAME_SIZE];
int name;
} person;
and take care not to overflow these fixed-size buffers when you read from the input.
If you really want to use malloc for the structure itself for some reason, then allocate enough for the structure, not just a pointer:
user = malloc(sizeof(person));
malloc(sizeof(person));
This would create memory for holding 2 char* and 1 int.
You also need to allocate memory for char*s in struct which you missed.
I don't know about c++, but if you choose to stick to c, your user->name is not allocated memory, neither user->city. You need to use malloc() with proper size to allocate memory to the pointer variable, then use those to store the values.
Also,
user = (person*)malloc(sizeof(person*));
should be
user = malloc(sizeof(*user));
Then , void main() should be changed to int main() and need to add return 0. It's a better practice to send back the exit status to the shell.
Note: by seeing the usage of
#include <iostream>
using namespace std;
it looks more of a c++ thing, but IMO, the logic should be same.

object oriented programming,use of static function to count objects

I want to display the objects of the class and the number of objects by using a static function. I typed this code but it does not work. It gives an error Too many types indeclaration" and "undefined symbol getCount. Can anyone help me? where is actually error in this code?
#include<iostream>
#include<string>
class Bag {
private:
static int objectCount;
int Weight;
std::string Brand;
std::string Type;
std::string Material;
std::string Colour;
public:
Bag(int W, std::string B, std::string T, std::string M, std::string C) {
Weight = W;
Brand = B;
Type = T;
Material = M;
Colour = C;
objectCount++;
}
void print() {
std::cout << "\n";
std::cout << "Bag: \n\n";
std::cout << "Weight:\t\t" << Weight << "kg" << '\n';
std::cout << "Brand:\t\t" << Brand << '\n' << "Type:\t\t" << Type << '\n';
std::cout << "Material:\t" << Material << '\n' << "colour:\t\t" << Colour << std::endl;
}
static int getCount() {
return objectCount;
}
};
int Bag::objectCount = 0;
int main() {
Bag bag_1(2, "Slazanger", "Atheletic Bag", "Polyethylene", "Brown");
bag_1.print();
std::cout << "object count " << Bag::getCount() << '\n';
Bag bag_2(4, "Samsonite", "Travel Bag", "Synthetic Fibre", "Gray");
bag_2.print();
std::cout << "object count " << Bag::getCount() << '\n';
Bag bag_3(5, "Herschel", "Duffel bag", "Leather", "Black");
bag_3.print();
std::cout << "object count " << Bag::getCount() << '\n';
Bag bag_4(3, "Kewin Woods", "Hand Bag", "Fibre", "Blue");
bag_4.print();
std::cout << "object count " << Bag::getCount() << std::endl;
while(!std::cin.get());
return 0;
}
You are scoping it incorrectly, getCount is statically scoped to the translation
unit, not the class. Thus it has no symbol named objectCount available to it.
To fix it, merely put the method inside the class.
class Bag {
private:
static int objectCount;
int Weight;
string Brand,Type,Material,Colour;
public:
Bag(int W ,string B ,string T,string M,string C)
{
Weight=W;
Brand=B;
Type=T;
Material=M;
Colour=C;
objectCount++;
}
void print()
{
cout<<"\n";
cout<<"Bag: \n\n";
cout<<"Weight:\t\t"<<Weight<<"kg"<<endl;
cout<<"Brand:\t\t"<<Brand<<endl<<"Type:\t\t"<<Type<<endl;
cout<<"Material:\t"<<Material<<endl<<"colour:\t\t"<<Colour<<endl;
}
static int getCount()
{
cout<< objectCount;
}
};
Aditionally, Borland is a really old compiler and suprised to even still
hear it's name, last release was around 15 years ago so you should really
consider using clang, gcc or msvc and upgrading your learning materials to
something less ancient. There has been alot of evolution in terms of practices,
standards and compiler conformance.
For example, C++ headers don't have an extension, and other small things like that.
This is a working version of your code:
#include <iostream>
#include <cstring>
using namespace std;
class Bag {
private:
static int objectCount;
int Weight;
string Brand, Type, Material, Colour;
public:
Bag(int W, string B, string T, string M, string C) //constructor
{
Weight = W;
Brand = B;
Type = T;
Material = M;
Colour = C;
objectCount++;
}
void print() {
cout << "\n";
cout << "Bag: \n\n";
cout << "Weight:\t\t" << Weight << "kg" << endl;
cout << "Brand:\t\t" << Brand << endl << "Type:\t\t" << Type << endl;
cout << "Material:\t" << Material << endl << "colour:\t\t" << Colour
<< endl;
}
static int getCount() //static function to count objects
{
cout << objectCount;
};
};
int Bag::objectCount = 0;
int main() {
Bag bag_1(2, "Slazanger", "Atheletic Bag", "Polyethylene", "Brown");
Bag bag_2(4, "Samsonite", "Travel Bag", "Synthetic Fibre", "Gray");
Bag bag_3(5, "Herschel", "Duffel bag", "Leather", "Black");
Bag bag_4(3, "Kewin Woods", "Hand Bag", "Fibre", "Blue");
bag_1.print();
cout << "object count" << Bag::getCount();
bag_2.print();
cout << "object count" << Bag::getCount();
bag_3.print();
cout << "object count" << Bag::getCount();
bag_4.print();
cout << "object count" << Bag::getCount();
}
There were several mistakes in the version you posted:
in C++ you don't need the .h when including files
you were using cout without the std:: qualifier or adding using namespace std; to your source. Also, please read this.
your static function was not declared/defined inside your class definition
it should be int main instead of void main
One last note: I removed your #include <conio.h> which should probably read #include <conio> and getch because I compiled this on a linux machine. Feel free to add them back in if you want them.