I was playing around with d and i stuck in CaStore class, it accepts the user1 but not the user2 data, i get core.exception.RangeError#main.d(60): Range violation, for example to add db.ccuser[0] = user1; without the [0] and next the db.ccuser[0] = user2; without the [0]
import std.stdio;
class CAdata{ string username;}
class Users{
int age;
CAdata[] info;
this(){
setNull();
}
void setNull(){
age = 0;
info ~= new CAdata();
}
}
class CaStore{
Users[] ccuser;
this(){
ccuser ~= new Users();
}
}
void main()
{
Users user1 = new Users();
user1.age = 24;
user1.info[0].username = "bob";
Users user2 = new Users();
user2.age = 24;
user2.info[0].username = "alice";
CaStore db = new CaStore();
db.ccuser[0] = user1;
db.ccuser[1] = user2;
}
You are writing to a position in the array that is out of bounds.
When you declare your array
Users[] ccuser;
its length is initially 0, there is no room for any elements. Then you append one element, yielding a length of 1:
ccuser ~= new Users();
This is why the first line
db.ccuser[0] = user1;
works but the second one gives you an error:
db.ccuser[1] = user2;
You are writing to index 1, but that is past the end of the array.
You can either:
Append to the array instead:
db.ccuser ~= user2;
Or increase the length of the array to make room:
db.ccuser.length = 2;
db.ccuser[1] = user2; // now there is room for two elements, no error
Related
I have a struct of Examinee like below (each has 1 id and their scores of different subjects):
struct Examinee
{
string id;
float math, literature, physic, chemistry, biology, history, geography, civic_education, natural_science,
social_science, foreign_language;
};
Now i want to write a function that reads from a string different values and assign them to an Examinee. The string looks like this (each info is separated by a comma):
BD1200001,9,4.0,5.0,10,3.5,7.5,4.25,7.0,7.75,9.25,2.0
This is what i have done so far:
Examinee readExaminee(string line_info) {
//turn line_info to char*
int Line_info_length = line_info.length();
char* info = new char[Line_info_length + 1];
strcpy(info, line_info.c_str());
//create examinee
Examinee examinee;
//read id into examinee by token
char* token = strtok(info, ",");
examinee.id = token;
//read score and assign to subjects
while (token != NULL)
{
float score = strtof(token, NULL);
//assign score to appropriate subject
token = strtok(NULL, ",");
}
delete[] info;
return examinee;
}
The question is: Can i assign each score to each subject in while loop like above? How can i do that? If not, is assigning each score manually the only way?
I'd change the design of Examinee. Something along these lines:
struct Examinee
{
enum Subject {kSubjMath, kSubjLiterature, ..., kSubjForeignLanguage, kSubjCount};
string id;
float scores[kSubjCount];
};
This way you can access scores in a loop, e.g.
for (int subj = 0; subj < Examinee::kSubjCount; ++subj) {
examinee.scores[subj] = some_score;
}
Or access specific score as examinee.scores[Examinee::kSubjLiterature]
If you are unable or unwilling to change Examinee, you can sort of simulate this locally:
Examinee examinee;
float* scores[] = {&examinee.math, &examinee.literature, ..., &examinee.foreign_language};
for (int subj = 0; subj < std::extent_v<scores>; ++subj) {
*scores[subj] = some_value;
}
Let's say we have got an array of villages. Each village is unique with regards to the array. A village can have multiple stores. The problem is that you only have limited (dynamic) memory and cannot recklessly initialise memory that you will not use. Therefore, If you create a new store in a village, you will need to relocate your village to a different place in the memory since the size of the village has grown. If you add a new village, you will have to relocate as well in order to accumulate for the extra size.
The problem is that you cannot simply use the following:
pVillage = (Village *)realloc( pVillage, ++MAX_VILLAGE * sizeof(Village));
This is because you will create memory for x villages containing 1 store per village. Since it could be the case that existing villages have multiple stores, the memory allocation will fail and could possibly overwrite memory which you shouldn't touch!
My example c++ code is as such:
class Store
{
char* m_pStoreName;
int m_nAmountOfProducts;
public:
Store(char* name, int number);
Store();
};
Store::Store(char* name, int number)
{
char *m_pStoreName = new char[10];
strcpy( m_pStoreName, name );
m_nAmountOfProducts = number;
}
Store::Store()
{
}
int nMaxStore = 1;
class Village
{
int m_nAmountOfStores;
Store *m_pStoreDb = (Store *)malloc( nMaxStore * sizeof(Store) );
public:
char* m_pVillageName;
Village(char* name);
Village();
addStore(Store* st);
};
Village::Village(char* name)
{
char *m_pVillageName = new char[10];
strcpy(m_pVillageName, name);
m_nAmountOfStores = 0;
}
Village::Village()
{
}
Village::addStore(Store* st)
{
if ( m_nAmountOfStores == nMaxStore )
{
//Need more memory
m_pStoreDb = (Store *)realloc( m_pStoreDb, ++nMaxStore * sizeof(Store) ); //Realocate and copy memory
}
//Add to db
*( m_pStoreDb + m_nAmountOfStores++ ) = *st;
}
int nAmountVillages = 0;
int nMaxVillages = 1;
Village *pVillageDB = (Village *)malloc( nMaxVillages * sizeof(Village) );
int main()
{
addNewVillage("Los Angeles", new Store("Store 1", 20));
addNewVillage("San Fransisco", new Store("Store 1", 10 ));
addNewVillage("New York", new Store("Store 1", 15));
addNewVillage("Los Angeles", new Store("Store 2", 12));
addNewVillage("Los Angeles", new Store("Store 3", 22));
addNewVillage("Amsterdam", new Store("Store 1", 212));
addNewVillage("Los Angeles", new Store("Store 4", 2));
return 0;
}
void addNewVillage(char* villageName, Store *store)
{
for ( int x = 0; x < nAmountVillages; x++ )
{
Village *pVil = (pVillageDB + x);
if ( !strcmp(pVil->m_pVillageName, villageName) )
{
//Village found, now add store
pVil->addStore( store );
return;
}
}
//Village appears to be new, add new one after expanding memory
if ( nAmountVillages == nMaxVillages )
{
//Need more memory
pVillageDB = (Village *)realloc( pVillageDB, ++nMaxVillages * sizeof(Village) ); //Realocate and copy memory
}
//Create new village and add store to village
Village *pNewVil = new Village( villageName );
pNewVil->addStore( store );
//Add village to DB
(pVillageDB + nAmountVillages++ ) = pNewVil;
}
My problem, question is:
What is the correct way to dynamically enlarge an array of custom
objects if not all objects have the same size, or if an existing
object in this array grows in size (new stores in a village)?
I have previously created the following function:
int Village::calculateStoreSize()
{
int nSize = 0;
for ( int x = 0; x < m_nAmountOfStores; x++ )
{
Store *pStore = ( m_pStoreDb + x );
nSize += sizeof(*pStore);
}
return nSize;
}
I tried using it in the following function to relocate the store array in a village object:
m_pStoreDb = (Store *)realloc( m_pStoreDb, Village::calculateStoreSize() + sizeof(Store) );
Unfortunately, when adding a new village, everything goes wrong with memory!
There are two types of arrays in C/C++: Static and Dynamic.
Unfortunately even though the latter one suggests that the size can be "easily adjusted" via calls like realloc(), the truth is, always reallocating all the objects of an array just to increase the size by 1 is tedious and should thus be avoided. However there is a workaround!
If I understand your question correctly, you want to dynamically allocate memory for objects of varying size. The casual way to do so is via linked lists. The most basic linked list would look something like this:
struct store {
char* name;
int products;
store* next;
};
class MyLinkedList {
private:
store* first;
public:
//Constructor
MyLinkedList();
//Destructor: iterate through the list and call delete on all elements.
~MyLinkedList();
void Add(const char* name, int products) {
if(this->first == NULL) {
store* new_store = new store;
new_store->name = new char[30];
strcpy(new_store->name, name);
new_store->products = products;
new_store->next = NULL;
this->first = new_store;
} else {
store* iter = this->first;
while(iter->next != NULL) {
iter = iter->next;
}
//Now iter points at the last element within the linked list.
store* new_store = new store;
new_store->name = new char[30];
strcpy(new_store->name, name);
new_store->products = products;
new_store->next = NULL;
iter->next = new_store;
}
}
//...
};
If you don't want to implement your own, you should have a look at the Standard Template Library's std::vector.
See Stackoverflow - Linked Lists in C++ or Wikipedia - Linked Lists for more detail on linked lists, or to get a good description of the STL's std::vector see cpluslus.com - std::vector.
Hope I could help, cheers!
lindebear
PS: You can also nest linked lists, see here.
Here is my code
//private void GetUnsubscribers(string apikey, string MailChimpCampaignID)
//{
// campaignUnsubscribesInput input = new campaignUnsubscribesInput();
// input.api_AccessType = PerceptiveMCAPI.EnumValues.AccessType.Serial;
// input.api_CustomErrorMessages = true;
// input.api_MethodType = PerceptiveMCAPI.EnumValues.MethodType.POST;
// input.api_Validate = true;
// input.api_OutputType = PerceptiveMCAPI.EnumValues.OutputType.XML;
// input.parms.apikey = apikey;
// input.parms.cid = MailChimpCampaignID;
// campaignUnsubscribes unsubscribe = new campaignUnsubscribes();
// campaignUnsubscribesOutput output = unsubscribe.Execute(input);
// Unsubscribers.AddRange(output.result.data);
// string unsubscriber = "0";
// string[] unsubs;
// foreach (listMembers list1 in output.result)
// {
// unsubscriber = list1.ToString();
// }
// string unsubscribers = Unsubscribers.Count.ToString();
// Page.ClientScript.RegisterStartupScript(typeof(Page), "alert", "<script language=JavaScript>alert('Unsubscribers:: '+ ' " + unsubscribers + " ');</script>");
//}
But the problem is, i am unable to pass campaign id to this function because i am creating a new campaign every time, so each time a new id is generated for campaign.
please help, As i am new in this line, so sorry in advance if there is something wrong in the code......................
I've run across a rather bizarre exception while running C++ code in my objective-C application. I'm using libxml2 to read an XSD file. I then store the relevant tags as instances of the Tag class in an std::list. I then copy this list into an std::vector using an iterator on the list. However, every now and then some elements of the list aren't copied to the vector. Any help would be greatly appreciated.
printf("\n length list = %lu, length vector = %lu\n",XSDFile::tagsList.size(), XSDFile::tags.size() );
std::list<Tag>::iterator it = XSDFile::tagsList.begin();
//result: length list = 94, length vector = 0
/*
for(;it!=XSDFile::tagsList.end();++it)
{
XSDFile::tags.push_back(*it); //BAD_ACCESS code 1 . . very bizarre . . . . 25
}
*/
std::copy (XSDFile::tagsList.begin(), XSDFile::tagsList.end(), std::back_inserter (XSDFile::tags));
printf("\n Num tags in vector = %lu\n", XSDFile::tags.size());
if (XSDFile::tagsList.size() != XSDFile::tags.size())
{
printf("\n length list = %lu, length vector = %lu\n",XSDFile::tagsList.size(), XSDFile::tags.size() );
//result: length list = 94, length vector = 83
}
I've found the problem. The memory was corrupted causing the std::list to become corrupted during the parsing of the XSD. I parse the XSD using a function start_element.
xmlSAXHandler handler = {0};
handler.startElement = start_element;
I used malloc guard in xcode to locate the use of freed memory. It pointed to the line:
std::strcpy(message, (char*)name);
So I removed the malloc (actually commented in the code) and it worked. The std::vector now consistently copies all 94 entries of the list. If anyone has an explanation as to why this worked that would be great.
static void start_element(void * ctx, const xmlChar *name, const xmlChar **atts)
{
// int len = strlen((char*)name);
// char *message = (char*)malloc(len*sizeof(char));
// std::strcpy(message, (char*)name);
if (atts != NULL)
{
// atts[0] = type
// atts[1] = value
// len = strlen((char*)atts[1]);
// char *firstAttr = (char*)malloc(len*sizeof(char));
// std::strcpy(firstAttr, (char*)atts[1]);
if(strcmp((char*)name, "xs:include")==0)
{
XSDFile xsd;
xsd.ReadXSDTypes((char*)atts[1]);
}
else if(strcmp((char*)name, "xs:element")==0)
{
doElement(atts);
}
else if(strcmp((char*)name, "xs:sequence")==0)
{
//set the default values
XSDFile::sequenceMin = XSDFile::sequenceMax = 1;
if (sizeof(atts) == 4)
{
if(strcmp((char*)atts[3],"unbounded")==0)
XSDFile::sequenceMax = -1;
int i = 0;
while(atts[i] != NULL)
{
//atts[i] = name
//atts[i+i] = value
std::string name((char*)atts[i]);
std::string value((char*)atts[i+1]);
if(name=="minOccurs")
XSDFile::sequenceMin = (atoi(value.c_str()));
else if(name=="maxOccurs")
XSDFile::sequenceMax = (atoi(value.c_str()));
i += 2;
}
}
}
}
//free(message);
}
I currently have something like this in my proto file:
message MsgA
{
required string symbol = 1 ;
optional int32 freq = 2 [default = 0];
}
message MsgB
{
repeated MsgA val = 1 ;
}
Now I know that in order to use the repeated field in MsgB. I need to do something like this:
MsgB inst;
MsgA some_val = Get_MsgA_Result();
MsgA* res = inst.add_val();
*res = some_val;
Now my question is once we are done with MsgB how do we reclaim the memory allocated by inst.add_val(); ?