I don't understand the syntax required for dynamically allocating members of a struct in c++. Basically, I need to fill char array members to exact size using a temp array and strlen. Here is my struct:
struct card
{
char *rank;
char *suit;
char color;
bool dealt;
char *location;
};
Here is the function that uses the struct:
bool importCard(card *deckPtr, char *deckName);
I created an array of 52 cards and assigned a pointer to it, and passed it to the function as the first parameter. (deckPtr) Here is a loop in the function that is supposed to read in card info to the struct data members.
for(index=0;index<52;index++,deckPtr++)
{
fin >> *temp;
charCount=stringLength(temp);
deckPtr.*rank = new char[charCount+1];
stringCopy(*temp, deckPtr.*rank);
fin >> *temp;
charCount=stringLength(temp);
deckPtr.*suit = new char[charCount+1];
stringCopy(*temp, deckPtr.*suit);
if(deckPtr.*suit==('d')||deckPtr.*suit==('h'))
{
(*deckPtr).color='r';
}
else
{
(*deckPtr).color='b';
}
(*deckPtr).dealt=false;
deckPtr.*location = new char[11];
stringCopy(unshPtr, deckPtr.*location);
}
I am getting three compile errors: "rank" "suit" and "location" are "not declared in this scope." What am I doing wrong? Thanks!
The syntax is deckPtr->rank, deckPtr->suit, deckPtr->location = new char[...];.
But your coding style is more like C than C++. Instead, if you use modern C++, with convenient RAII classes like std::string, your code becomes much more simplified: just use std::string instead of raw char* pointers, and you don't have to pay attention to memory allocation and memory freeing: it's all automatically managed by std::string and destructors.
#include <string>
struct card
{
std::string rank;
std::string suit;
char color;
bool dealt;
std::string location;
};
And instead of your custom stringCopy() function you can just use the "natural" operator= overload for std::string (i.e. destString = sourceString;).
And to build an array of 52 cards, just use std::vector:
#include <vector>
std::vector<card> cards(52);
Again, memory allocation is automatically managed by std::vector (and, unlike raw C arrays, you can query the vector for its own element count, using its size() method).
You probably want to use deckPtr->rank, deckPtr->suit, and deckPtr->location to assign something to the char pointers (alternatively, (*deckPtr).rank etc.). Note that * in char *var is not part of the name of the variable. It just states that the variable is a pointer to char.
You need deckPtr->foo instead of deckPtr.*foo
Your problem is that the dereference operator is operating on foo, not on deckPtr, which makes no sense to the C++ compiler, so it uses instead the pointer to member operator. This operator is used to execute member function pointers on an object, which is completely different from accessing a member. Chances are good that in an intro-level c++ class (like it appears you are in) you will never have to worry about using or understanding that operator.
In general, in C/C++ whenever you have a pointer to a struct, you want to use the -> operator, not .. foo->bar is equivalent to (*foo).bar, but it keeps you from messing up and forgetting the parentheses. There's a reason that C had an arrow operator - it's easier and clearer. In my not-so-humble opinion, teachers that impose such arbitrary restrictions actually teach students to write bad code and reinvent wheels, but I don't have their experience in teaching programming...
Related
I would like to perform a deep copy of a char**, but I have no idea how to allocate memory / copy this datatype. This is for a copy constructor in a class that contains a char**. For example, lets say I have this code:
char ** arr1 = new char*[20];
arr1[0] = (char*)"This is index 1";
arr1[1] = (char*)"This is index 2";
char ** arr2;
How do I deep copy the contents of arr1 into arr2? Any help is appreciated!
It’s for a programming assignment, and the teacher wants all strings
to be stored as char*,...
You can tell your teacher that std::string does store strings as char*. If he still doesnt like you to use std::string you should write your own wrapper, because working with bare char* is what you do when you write C, but not in C++. You should write a:
struct my_string {
char* data;
... constructor, operator[], etc...
};
You basically dont need to write more code than you already do, but you should put it in the right place (ie hide it behind a nice interface). You will immediately see the benefit of it when you eg consider ...
...so an array of strings has to be stored as an array of char*.
No. An array of strings is std::array<my_string> (or std::vector<my_string> if it is supposed to be dynamic). And if your teacher insists on not using std::vector, then you should do the same as you just did for strings for vectors (ie encapsulate all the dirty pointer and memory stuff in one place).
This seems more like a C question, but here is an example:
char **AllocateAndDeepCopy(char **arr1, int arr1size)
{
unsigned int i;
char **arr2;
/* Allocate string array */
arr2 = new char*[arr1size];
/* Iterate array elements */
for (i=0; i<arr1size; i++) {
/* Allocate string */
arr2[i] = new char[strlen(arr1[i])+1];
/* Copy contents */
strcpy(arr2[i], arr1[i]);
}
return arr2;
}
Later you have to deallocate arr2 this way:
void DeallocateArr2(char **arr2, int size)
{
for (int i=0; i<size; i++) {
delete arr2[i];
}
delete arr2;
}
I can only shake my head about the sorry state of C++ education. We have a looong way to go there. But since that’s apparently a given, what’s the best you can do?
To copy a C-style data structure like that you have know two things at the point of copy. Both are not inherently provided by a C-style array, so you’ll have to track them explicitely.
The capacity of arr1: 20. If that’s not a compile time constant you have to store it and pass it around. Since you want to implement a copy ctor that means storing the capacity in a non-static member variable of the object.
The number of used indexes in arr1: 2. Same as above. Alternatively make sure that all unused indexes are set to nullptr.
Now you can allocate an arr2 of the correct size and then allocate+memcpy all used indexes.
However, your program will go up in flames regardless, because arr1 and arr2 cannot be treated the same, even though they look identical. The used indexes of arr1 must never ever be deleted because they contain pointers to character literals: They were never newd and live in read-only memory. On the other hand you absolutely must delete the indexes of arr2, because they were newd.
If this brutal disregard of const is really required by the assignment I’d go one step further. I’d introduce another member variable, an array of booleans that tracks which indexes of the char array point to char literals and which were dynamically allocated. During copy you now have all the necessary information to either memcpy or simply set the pointer. Crazy? Definitely, but the whole assignment is, and that way the craziness is visible at least instead of hidden behind an innocent-looking C-style cast. Btw: those should be const_cast<char*> to make it clear what’s going on.
Just take a look at http://en.cppreference.com/w/cpp/algorithm/copy, the deep copy is made by
*d_first++ = *first++;
I want to copy two similar structures in C++. Consider the below three structures.
struct Dest_Bio
{
int age;
char name;
};
struct Source_Bio
{
int age;
char name;
};
struct Details
{
int id;
Dest_Bio* st_bio; //Needs to be populated with values from Source_Bio
};
I have values filled in 'Source_Bio' structure
I want to copy these values in Source_Bio into st_bio in 'Details' structure.
I do not want to create a member for Dest_Bio
I tried the following. It compiles fine but crashes the program on run time.
Source_Bio st_ob;
st_ob.age = 5;
st_ob.name = 't';
Details st_a;
st_a.id = 1;
st_a.st_bio = (Dest_Bio*) malloc(sizeof(Dest_Bio));
memcpy((struct Dest_Bio*)&st_a.st_bio, (struct Source_Bio*)&st_ob,sizeof(Dest_Bio));
How can I get this done? Thanks in advance
The easy way would probably be something like this:
struct Dest_Bio {
int age;
char name; // should this really be a string instead of a single char?
Dest_Bio(Source_Bio const &s) : age(s.age), name(s.name) {}
};
Details st_a;
st_a.id = 1;
st_a.st_bio = new Dest_Bio(st_ob);
Better still, you should probably just eliminate Dest_Bio and Source_Bio and replace both with just Bio and be done with it. You also almost certainly want to replace your Dest_Bio *st_bio with some sort of smart pointer -- a raw pointer is pretty much asking for trouble. Alternatively, just embed a Bio object inside the Details object (probably the preferred choice).
Since you already have the requirement that both Bio types be layout-compatible, make a common type Bio. Then do the copy in C++ rather than C:
st_a.st_bio = new Bio(st_ob);
If they do need to be different types, then you might make Source_Bio convertible to Dest_Bio via a constructor or conversion operator.
That's assuming you have a genuine reason for your third requirement (that it be a pointer rather than a member). Otherwise, make it a member, fixing the potential memory leak, and simplify the code further:
st_a.st_bio = st_ob;
If you really want to muck around with C functions, then you want to copy to st_a.st_bio, not to &st_a.st_bio (i.e. overwriting the object, not the pointer to it). Only do that if you hate whoever will be maintaining the code.
I want to pass a reference to an array from one object GameModel to another PersonModel, store reference and then work with this array inside PersonModel just like inside GameModel, but...
I have a terrible misunderstanding of passing an array process: In the class PersonModel I want to pass an array by reference in a constructor (see code block below). But the marked line throws the compile error
PersonModel::PersonModel( int path[FieldSize::HEIGHT][FieldSize::WIDTH], int permissionLevel ) {
this->path = path; //<------ ERROR here:
//PersonModel.cpp:14:22: error: incompatible types in assignment of 'int (*)[30]' to 'int [31][30]'
this->permissionLevel = permissionLevel;
}
Here is the header file PersonModel.h
#ifndef PERSON_MODEL
#define PERSON_MODEL
#include "data/FieldSize.h"
namespace game{
class IntPosition;
class MotionDirection;
class PersonModel {
protected:
int path[FieldSize::HEIGHT][FieldSize::WIDTH];
int permissionLevel;
public:
PersonModel( int path[FieldSize::HEIGHT][FieldSize::WIDTH], int permissionLevel );
void setMotionDirection ( MotionDirection* md);
void step(long time);
void reset(long time);
};
}
#endif
As I see now, I can change the int path[FieldSize::HEIGHT][FieldSize::WIDTH]; declaration to int (*path)[FieldSize::WIDTH]; but it is much more confusing.
Help me understand this topic: what is the proper way to store the passed reference to an array to work with it later, like with usual 2D array.
UPDATE:
This array is a map of game field tiles properties represented by bit-masks, so it is read-only actually. All the incapsulated objects of GameModel class should read this array, but I definitely don't want to duplicate it or add some extra functionality.
There are no frameworks just bare Android-NDK.
I think you've fallen into the classic trap of believing someone who's told you that "arrays and pointers are the same in C".
The first thing I'd do would be to define a type for the array:
typedef int PathArray[FieldSize::HEIGHT][FieldSize::WIDTH];
You then don't need to worry about confusions between reference to array of ints vs array of references to ints.
Your PersonModel then contains a reference to one of these.
PathArray &path;
and, because its a reference it must be initialised in the constructors initialization list rather than in the constructor body.
PersonModel::PersonModel( PathArray &aPath, int aPermissionLevel ) :
path(aPath),
permissionLevel(aPermissionLevel)
{
}
Of course, holding references like this is a little scary so you might want to consider using a boost::shared_ptr or something similar instead to make the lifetime management more robust.
You cannot assign arrays as you do with value types in C++
int path[x][y] resolves to the type int (*)[y]
Possible solutions are:
Using memcpy/copy
Using std::array
You can't assign to an array like that. However you can use the fact that an array is a contiguous memory area, even when having an array of arrays, and use e.g. memcpy to copy the array:
memcpy(this->path, path, FieldSize::HEIGHT * FieldSize::WIDTH * sizeof(int));
You would have to pass a pointer to the 2d-array as you cannot pass the array as you have stated in the code snippet.
I would suggest using the STL array type. Admittedly std::array is C++ '11 standard and therefore old compiler may not support it. You can also use vector which has been around longer.
vector<vector<int>>path;
You will have to resize the 2d-vector in the constructor.
Indexing would look a bit funny:
path[1].[1] ....
With vectors, you can then pass it by reference.
the name of the array is a pointer on first element
so,
you can try
PersonModel( int (*path)[FieldSize::HEIGHT][FieldSize::WIDTH], int permissionLevel );
In C++ '=' implemented for primitive types like int and double but not for array(array is not a primitive type), so you should never use '=' to assign an array to new array, instead you should use something as memcpy to copy array. memcpy copy a memory over another memory, so you can use it to copy an array over another array:
// memcpy( dst, src, size );
memcpy( this->path, path, FieldSize::HEIGHT * FieldSize * WEIGHT * sizeof(int) );
I have a struc like this:
struct process {int PID;int myMemory[];};
however, when I try to use it
process p;
int memory[2];
p.myMemory = memory;
I get an criptic error from eclipse saying int[0] is not compatible with int[2];
what am i doing wrong?
Thanks!
Don't use static arrays, malloc, or even new if you're using C++. Use std::vector which will ensure correct memory management.
#include <vector>
struct Process {
int pid;
std::vector<int> myMemory;
};
Process p;
p.reserve(2); // allocates enough space on the heap to store 2 ints
p.myMemory.push_back( 4815 ); // add an index-zero element of 4815
p.myMemory.push_back( 162342 ); // add an index-one element of 162342
I might also suggest creating a constructor so that pid does not initially have an undefined value:
struct Process {
Process() : pid(-1), myMemory() {
}
int pid;
std::vector<int> myMemory;
};
I think you should declare myMemory as an int* then malloc() when you know the size of it. After this it can be used like a normal array. Int[0] seems to mean "array with no dimension specified".
EXAMPLE:
int *a; // suppose you'd like to have an array with user specified length
// get dimension (int d)
a = (int *) malloc(d * sizeof(int));
// now you can forget a is a pointer:
a[0] = 5;
a[2] = 1;
free((void *) a); // don't forget this!
All these answers about vector or whatever are confused :) using a dynamically allocated pointer opens up a memory management problem, using vector opens up a performance problem as well as making the data type a non-POD and also preventing memcpy() working.
The right answer is to use
Array<int,2>
where Array is a template the C++ committee didn't bother to put in C++99 but which is in C++0x (although I'm not sure of the name). This is an inline (no memory management or performance issues) first class array which is a wrapper around a C array. I guess Boost has something already.
In C++, array definition is almost equal to pointer constants, meaning that their address cannot be changed, while the values which they point to can be changed. That said, you cannot copy elements of an array into another by the assignment operator. You have to go through the arrays and copy the elements one by one and check for the boundary conditions yourself.
The syntax ...
struct process {int PID;int myMemory[];};
... is not valid C++, but it may be accepted by some compilers as a language extension. In particular, as I recall g++ accepts it. It's in support for the C "struct hack", which is unnecessary in C++.
In C++, if you want a variable length array in a struct, use std::vector or some other array-like class, like
#include <vector>
struct Process
{
int pid;
std::vector<int> memory;
};
By the way, it's a good idea to reserve use of UPPERCASE IDENTIFIERS for macros, so as to reduce the probability of name collisions with macros, and not make people reading the code deaf (it's shouting).
Cheers & hth.,
You cannot make the array (defined using []) to point to another array. Because the array identifier is a const pointer. You can change the value pointed by the pointer but you cannot change the pointer itself. Think of "int array[]" as "int* const array".
The only time you can do that is during initialization.
// OK
int array[] = {1, 2, 3};
// NOT OK
int array[];
array = [1, 2, 3]; // this is no good.
int x[] is normally understood as int * x.
In this case, it is not, so if you want a vector of integers of an undetermined number of positions, change your declaration to:
struct process {int PID;int * myMemory;};
You should change your initialization to:
int memory[2];
p.myMemory = new int[ 10 ];
Assuming that I have a program that has an array of unknown lenght that consists of Customers.
Here, a customer struct:
struct Customer
{
char* lastname;
char* firstname;
int money;
};
And here - an array:
Customer* CustomerDB;
Okay. But the thing is that I want to add and remove customers dynamically during runtime. I don't want to allocate like 100 customers during declaration or during runtime - I want to allocate one at a time when it is needed.
Think of a simple AddCustomer function that allocates memory, enters the given data and then increments a counter (which is probably needed for iteration).
This is my main problem.
What I want is the array to behave exactly like one that has been declared with 100 arrays instead of a dynamical one.
The customer program above is just an example, please don't tell me that it's a bad idea to do that and that or that.
How do I create an AddCustomer function working for the code above?
It is necessary that I can iterate through CustomerDB
Use standard template library std::vector or a vector of pointers.
Use a standard library container, such as vector, deque, or list.
I suppose the AddCustomer function might be implemented like this:
void AddCustomer(Customer** db, int current_count);
where the memory re-allocation might be done in terms of realloc.
However, you do realize that you are not taking advantage of anything that C++ offers, so you could have just posted this as a C question (in C++ this is a no-brainer with vector/deque/list and push_back)?
If you can use std::vector or similar, use that, they're purpose-built for this sort of problem. I'd also replace the raw char * with std::string at the same time.
If you're stuck with the approach above, you might want to change the size of the allocated array using realloc() when the size changes. However that's a very manual way of implementing what a combination of vector & string can do for you much easier and without potential resource leaks.
Here are just some thoughts
Judging from your requirements it sounds as if you would be better off with a list than an array. A list would fit more natural to your requirements regarding the dynamics and having no max limit.
Either you could create your own linked list using a pointer in each list element or use std::dequeue or similar however you would anyway need to take care of what the pointers inside your struct are pointing to. Simplest case in your example would probably to use std::string instead of pointers - then the strings are automatically copied and you don't have to concern yourself with the memory (or use boost::shared_array as pointers).
struct Customer
{
string lastname;
string firstname;
int money;
};
Just my 2c
As you suggested, this is not the "Correct" way to do things - but heres what you asked for.
typedef struct _tag_Customer {
char *LastName;
char *FirstName;
double Money;
} CUSTOMER, *LPCUSTOMER;
typedef struct _tag_Customers {
CUSTOMER *Collection;
int Count;
} CUSTOMERS, *LPCUSTOMERS;
LPCUSTOMER AddCustomer(LPCUSTOMERS pCustomers, const char *sLastName, const char *sFirstName, double dMoney)
{
int iRequiredMemory = (sizeof(CUSTOMER) * (pCustomers->Count + 1));
if(!(pCustomers->Collection = (LPCUSTOMER) realloc(pCustomers->Collection, iRequiredMemory)))
{
return NULL; //Memory allocation error.
}
LPCUSTOMER pCutsomer = &pCustomers->Collection[pCustomers->Count];
pCustomers->Count++;
iRequiredMemory = strlen(sLastName) + 1;
pCutsomer->LastName = (char *) calloc(iRequiredMemory, sizeof(char));
strcpy(pCutsomer->LastName, sLastName);
iRequiredMemory = strlen(sFirstName) + 1;
pCutsomer->FirstName = (char *) calloc(iRequiredMemory, sizeof(char));
strcpy(pCutsomer->FirstName, sLastName);
pCutsomer->Money = dMoney;
return pCutsomer;
}
void main(void)
{
CUSTOMERS Database;
memset(&Database, 0, sizeof(CUSTOMERS));
AddCustomer(&Database, "Smith", "Joe", 100.99);
AddCustomer(&Database, "Jackson", "Jane", 100.99);
AddCustomer(&Database, "Doe", "John", 100.99);
//You'll need to free the Memory, of course.
}