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.
}
Related
I guess I'm still not understanding the limitations of C++ containers and arrays. According to this post and this It is impossible to store items of dynamic size in an STL vector.
However with the following code I can dynamically re-size an element of a vector with the results one would expect if it was ok to have items of varying and changing size in a vector.
string test = "TEST";
vector<string> studentsV;
for (int i = 0; i < 5; ++i)
{
studentsV.push_back(test);
}
studentsV[2].resize(100);
for (string s : studentsV)
{
cout << s << "end" << endl;
}
Result:
TESTend
TESTend
TEST
end
TESTend
TESTend
I can re-size the string element to any size, and it works fine. I can also do the same with a regular C-style array. So, what is the difference between the above posts and what I am doing, and can you give an example of what "dynamic item size" really means, because apparently I am not understanding.
A std::string uses dynamic memory to increase the size of the string being stored. This is not what those articles are talking about.
What they mean, is that sizeof(std::string) is constant. The actual object representing a std::string will always have the same size, but it might do additional allocations in another part of memory.
A std::vector is really just a friendly wrapper around a dynamically-sized array. The definition of an array in C or C++ is a contiguous block of memory where all elements are of equal size.
can you give an example of what "dynamic item size" really means, because apparently I am not understanding.
This is the core of your question.
Namely: if all C++ classes (even ones that manage dynamic memory as part of their implementations) have a fixed and known footprint size via sizeof()...just what sort of thing is it that you can't put in a std::vector?
Since something like a std::string and a std::bitset are classes of different sizes, you couldn't have a vector of [string string bitset string bitset string]. But the type system already wouldn't let you do that. So that can't be what they're talking about.
They're just saying there's no hook for supporting structures like this from the C world:
struct packetheader {
int id;
int filename_len;
};
struct packet {
struct packetheader h;
char filename[1];
};
You couldn't make a std::vector<packet> and expect to find some parameter to push_back letting you specify a per-item size. You'd lose any data you'd allocated outside of the structure boundary.
So to use something like that, you'd have to do std::vector<packet*> and store pointers.
The size of std::string is not dynamic. std::string is probably implemented with a pointer to a dynamically allocated memory. This makes sizeof(std::string) static and possibly different from the size of the actual string.
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 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...
I apologise if I'm completely misunderstanding C++ at the moment, so my question might be quite simple to solve. I'm trying to pass a character array into a function by value, create a new array of the same size and fill it with certain elements, and return that array from the function. This is the code I have so far:
char *breedMutation(char genome []){
size_t genes = sizeof(genome);
char * mutation = new char[genes];
for (size_t a = 0 ;a < genes; a++) {
mutation[a] = 'b';
}
return mutation;
}
The for loop is what updates the new array; right now, it's just dummy code, but hopefully the idea of the function is clear. When I call this function in main, however, I get an error of initializer fails to determine size of ‘mutation’. This is the code I have in main:
int main()
{
char target [] = "Das weisse leid"; //dummy message
char mutation [] = breedMutation(target);
return 0;
}
I need to learn more about pointers and character arrays, which I realise, but I'm trying to learn by example as well.
EDIT: This code, which I'm trying to modify for character arrays, is the basis for breedMutation.
int *f(size_t s){
int *ret=new int[s];
for (size_t a=0;a<s;a++)
ret[a]=a;
return ret;
}
Your error is because you can't declare mutation as a char[] and assign it the value of the char* being returned by breedMutation. If you want to do that, mutation should be declared as a char* and then deleted once you're done with it to avoid memory leaks in a real application.
Your breedMutation function, apart from dynamically allocating an array and returning it, is nothing like f. f simply creates an array of size s and fills each index in the array incrementally starting at 0. breedMutation would just fill the array with 'b' if you didn't have a logic error.
That error is that sizeof(genome); will return the size of a char*, which is generally 4 or 8 bytes on a common machine. You'll need to pass the size in as f does since arrays are demoted to pointers when passed to a function. However, with that snippet I don't see why you'd need to pass a char genome[] at all.
Also, in C++ you're better off using a container such as an std::vector or even std::array as opposed to dynamically allocated arrays (ones where you use new to create them) so that you don't have to worry about freeing them or keeping track of their size. In this case, std::string would be a good idea since it looks like you're trying to work with strings.
If you explain what exactly you're trying to do it might help us tell you how to go about your problem.
The line:
size_t genes = sizeof(genome);
will return the sizeof(char*) and not the number of elements in the genome array. You will need to pass the number of elements to the breedMutation() function:
breedMutation(target, strlen(target));
or find some other way of providing that information to the function.
Hope that helps.
EDIT: assuming it is the number of the elements in genome that you actually want.
Array are very limited.
Prefer to use std::vector (or std::string)
std::string breedMutation(std::string const& genome)
{
std::string mutation;
return mutation;
}
int main()
{
std::string target = "Das weisse leid"; //dummy message
std::string mutation = breedMutation(target);
}
Try replacing the second line of main() with:
char* mutation = breedMutation(target);
Also, don't forget to delete your mutation variable at the end.
struct Test
{
int var;
char *arr;
}
int main()
{
Test a;
a.arr = new char[50];
}
The above code would create a dynamic array in the structure but the dynamic array would not be actually memory allocated within the structure, its memory would be allocated somewhere else. I want this array to be allocated in the structure as with the fixed array but I don't want to use fixed array. Any ideas?
I've tried my best to clarify my question, hope you understand.
I want to send this structure through UDP and UDP takes continues memory buffer to send that's why I want this structure to have continuous memory.
You can not do that as the new memory is from heap/ free store and your a will be allocated on stack....
you can allocate using malloc/new a continous memory block of sizeof Test + your required size and make the pointer arr to point at the end of the Test structure.
If you need it in function scope on stack you can use alloca.
Test *a = (Test*)alloca(sizeof(Test)+yoursize);
a->arr = (char*)a+sizeof(Test)...
No you cannot have variable length arrays in C++.
So you cannot do that.
You can have a fixed length array or you can use the approach you have given.
Another approach is,
You can use placement new to place your array at an pre-allocated memory location. This memory could be on stack.
Your code don't compile. You should compile it with all warnings enabled, and improve it till you got no warnings. And are your studying C or C++? If it is C++, consider using std::vector
struct Test {
int var;
char arr[1];
};
int main()
{
std::vector<char> buf;
buf.resize(sizeof(Test) + 50);
Test *foo = reinterpret_cast<Test *>(&buf[0]);
foo->arr[40] = 'b';
}
You can pass array size to structs constructor and allocate memory for array there. Don't forget to deallocate it somewhere, e.g. in destructor:
struct Test
{
int m_var;
char *arr;
public:
Test(int var) : m_var(var)
{
arr = new char[m_var];
}
~Test()
{
delete[] arr;
arr = 0;
}
};
void main(int argc, char* argv[])
{
Test t(50);
return 0;
}
Although it hasn't been "blessed" like it has in C, most compilers will still let you use the "struct hack":
struct variable_array {
size_t size;
char data[1];
};
The "trick" is that when you allocate it, you allocate enough space for the data you want to store (but this means it must be dynamically allocated):
variable_array *a = (variable_array *) ::operator new(sizeof(*a) + data_size);
a->size = data_size;
In theory, this isn't required to work -- the compiler could do a bound-check on references to the data member to ensure you don't index beyond the one element you've defined it to hold in the struct definition. In reality, I don't know of a single compiler that does such a thing, and kind of doubt that such a thing exists. Quite a lot of C code has done things like this for years, so a compiler that did such a check just wouldn't work with a lot of real-world code, even though the standard allows it. C99 also adds this (with minutely different syntax) as an official feature of the language.
Bottom line: it's a bit clumsy, but the possibility of really not working is almost entirely theoretical.
Not truly dynamic allocation, but might solve your problem (depends on if you always know the desired size of the array at compile time)
template <size_t ArraySize>
struct Test
{
int var;
char arr[ArraySize];
}
int main()
{
Test<50> a;
}