I have huge arrays of nested structures which makes it impossible to allot that kind of space and forces me to use heap. But I am facing difficulties using malloc.
The gist of the problem is below.
struct year_of_joining
{
struct district
{
struct colleges
{
struct departments
{
struct sections
{
struct students
{
int sex;
}student[100];
}section_no[8];
}department_no[17];
}college[153];
}dist[13];
};
If I use
int main()
{
int i=0;
struct year_of_joining** year;
year = malloc(100 * sizeof(struct year_of_joining));
for (i = 0; i < 100; i++)
{
year[i] = malloc(sizeof(struct year_of_joining));
}
year[1]->dist[0].college[0].department_no[0].section_no[0].student[8].sex = 1;//works fine
printf("%d", year[1]->dist[0].college[0].department_no[0].section_no[0].student[8].sex);//prints 1
free(year);
return 0;
}
It works fine but when I create a pointer to pointer for dist like year_of_joining and use indirection operator it does not compile:
year[1]->dist[2]->college[0].department_no[0].section_no[0].student[8].sex = 9;//error C2039: 'dist' : is not a member of 'year_of_joining'
How do I solve this? Am I even on the right track?
I think you are way off track here.
Note that a single struct year_of_joining is approximately 100 MiB of data. An array of 100 such structures requires approximately 10 GiB of data (and that is only recording the sex of the students — no other information at all).
struct year_of_joining** year;
year = malloc(100 * sizeof(struct year_of_joining));
This memory allocation allocates enough space for millions of pointers. You almost certainly intended to use:
struct year_of_joining *year = malloc(100 * sizeof(struct year_of_joining));
struct year_of_joining *year = malloc(100 * sizeof(*year));
This allocates 100 years worth of the structure.
However, it seems improbable that you have 13 districts, each of which has exactly 153 colleges, each college having exactly 17 departments, each of which has 8 sections, with each section having exactly 100 students. That corresponds to over 25 million students every year!
You are going to need a vastly more flexible arrangement, where each of the structures contains a pointer to a list of the nested structures, so you can have bigger sections but smaller colleges, etc. It will need to work more along the lines of:
struct students
{
char name[32];
int sex;
// ... and other data ...
};
struct sections
{
char name[32];
// ... and other data ...
int n_students;
struct students *students;
};
struct departments
{
char name[32];
int n_sections;
struct sections *sections;
}
struct colleges
{
char name[32];
// ... and other data ...
int n_departments;
struct departments *departments;
};
struct district
{
char name[32];
// ... and other data ..
int n_colleges;
struct college *colleges;
};
struct year_of_joining
{
int year;
// ... and other data ...
int n_districts;
struct district *districts;
};
Even that feels not entirely correct, but it would be a better way of organizing the data than the original, if only because if a department only has one section and enrolls only ten students (because it is a minority-interest department), then it allocates only enough space for one section and ten students, rather than allocating space for 800 students and 8 sections.
You are not on the right track. Your struct is really huge, and you will need to recompile your program if the size of your input (e.g. number of students) ever gets too big.
I suggest you model your data as smaller structs that can be individually allocated, perhaps using pointers or ID numbers to link them together.
Another language like Ruby might be a better choice than C, allowing you to focus more on your data than on the details of its storage in memory. In general, C is good for fast, low-level interactions with the operating system, while languages with garbage compilers and dynamic typing will be much easier for writing reports and aggregating data.
Anyway, suppose you want to use C. The data structure you choose will depend on several things. What is the precise real-world structure of the data you are modelling? What performance characteristics do you need? Does it need to be fast to add things, or fast to extract certain statistics from the data? Without knowing that answers to these questions, it is hard for us to come up with a usable answer for your application. But Jonathan Leffler has taken a good guess. Here is my guess:
#include <stdint.h>
struct student
{
char * name;
uint32_t sex;
uint32_t year_of_joining;
// Index into an array of sections.
// You could also use a pointer to a section (section *)
// but the pointer would become invalid if you ever moved the
// sections in memory (e.g. by calling realloc on an array
// of sections).
uint32_t section_id;
};
struct section
{
char * name;
uint32_t department_id;
};
struct department
{
char * name;
uint32_t college_id;
};
struct college
{
char * name;
uint32_t district_id;
};
struct district
{
char * name;
};
// These typedefs make it so we don't have to
// write "struct" when using the structs.
typedef struct student student;
typedef struct section section;
typedef struct department department;
typedef struct college college;
typedef struct district district;
// Dynamically sized arrays for holding things.
student * student_array;
section * section_array;
department * department_array;
college * college_array;
district * district_array;
Related
I have a task to do and the content of the task is:
Please suggest a definition of linked list, which will keep the person's name and age in a flexible structure. Then write the procedure for inserting elements with the given name and age.
What exactly is a flexible structure? How to define it? And then how to malloc the size?
typedef struct Test {
int age; // ?
char name[?]; // ?
struct Test * next;
}Structure;
int main(void) {
Structure *one = malloc(???);
}
You are on the right track. However, there is no "flexible structure". You want to use a flexible array member (avail since C99) in a struct:
typedef struct {
int age;
size_t name_size; // size of the array, not length of the name!
char name[]; // Flexible array member
} Structure;
int main(void) {
Structure *one = malloc(sizeof(*one) + SIZE_OF_NAME_ARRAY);
}
Note I added a name_size field. C does not store the size of allocated arrays, so you might need this for safe copy/compare, etc. (prevent buffer overflows).
Using *one makes this term independent of the actual type used. The size of such a struct is as if the arrray had zero elements. However, it will be properly aligned, so it can differ from the same struct without the array.
Also note that you have to change the allocated size if you use other than a char array to something like sizeof(element_type) * ARRAY_SIZE. This is not necessary for chars, as their size is defined by the standard to be 1.
my guess: a flexible struct would be one that could handle any age and any name.
A unsigned int field would handle any age (within reason).
A char * field would handle any name.
The struct itself would be:
struct nameAge { unsigned int age; char * pName; };
an instance of the struct would be:
struct nameAge myNameAge;
Setting the age field would be:
myNameAge.age = ageValue;
Setting the name field would be:
myNameAge.name = malloc( numCharactersInName+1 );
strcpy( myNameAge.name, nameString );
How the code obtained the ageValue for age and/or the characters for NameString is up to the programmer to decide/implement.
typedef struct
{
int k;
union
{
int i;
int j;
}use;
}std;
Directly we can use the variable i and j in structure why it is used within union.
In your example, i.e.
typedef struct
{
int k;
union
{
int i;
int j;
}use;
}std;
it doesn't seem to make much sense as i and j are the same type and the names of the variables isn't that descriptive.
It can make sense to have the same type for union elements if that would make the code easier to write, read, understand and maintain. Example:
...
union
{
int numberOfCars;
int numberOfBicycles;
}use;
...
When writing code for handling cars you could use numberOfCars and when writing code for handling bicycles you could use numberOfBicycles. In this way the code would be easier to understand/maintain and the two code blocks could still share a common structure.
In one code block you could have:
std carDealer;
carDealer.use.numberOfCars = 9;
and in another code block (other file perhaps), you could have:
std bicyclesDealer;
bicyclesDealer.use.numberOfBicycles = 9;
A more typical case for unions is that the elements are of different type.
Suppose we wish to store information about employees in an organization.
Name Grade Age
If grade=HSK(Highly skilled)
hobby name
credit card number
If Grade=SSK(Semi skilled)
Vehicle no.
Distance from Company
We can use a single structure for it but then it would lead to wastage of memory coz either hobby name & credit card no. or vehicle no. & distance from com. is used at a time. Both of them are never used simultaneously. So, here union inside structure can be used effectively:
Code:
struct info1
{
char hobby[10];
int crcardno;
};
struct info2
{
char vehno[10];
int dist;
};
union info
{
struct info1 a;
struct info2 b;
};
struct emp
{
char n[20];
char grade[4];
int age;
union info f;
};
struct emp e;
HOPE YOU UNDERSTAND.......
Source : http://cboard.cprogramming.com/c-programming/122228-union-inside-structure.html
I'm trying to create a struct which contains the country, state, city and the name of a local shop. Unfortunately, I get this error:
No member named bavaria in struct country
So it seems that the error occurs here:
strcpy(germany.bavaria.ingolstadt.westpark, "Westpark");
What am I doing wrong?
This is my complete code:
#include <stdio.h>
#include <string.h>
int main() {
struct country {
char countryname[100];
struct state {
char statename[100];
struct city {
char cityname[100];
int postal;
struct shop {
char shopname[100];
} shop;
} city;
} state;
} country;
struct country germany;
struct state bavaria;
struct city ingolstadt;
struct shop westpark;
strcpy(germany.countryname, "Germany");
strcpy(germany.bavaria.ingolstadt.westpark, "Westpark");
return 0;
}
Let's separate the definitions out from where they're used to make it easier to read:
struct shop {
char shopname[100];
};
struct city {
char cityname[100];
int postal;
struct shop shop;
};
struct state {
char statename[100];
struct city city;
};
struct country {
char countryname[100];
struct state state;
};
Now you have:
struct country germany;
struct state bavaria;
struct city ingolstadt;
struct shop westpark;
strcpy(germany.bavaria.ingolstadt.westpark, "Westpark");
Here's the issue: struct country does not have a member called bavaria. It only has a member called state. What you want is:
strcpy(germany.state.city.shop.shopname, "Westpark");
What you probably really want is this:
struct country germany;
strcpy(germany.countryname, "Germany");
strcpy(germany.state.statename, "Bavaria");
strcpy(germany.state.city.cityname, "Ingolstadt");
strcpy(germany.state.city.shop.shopname, "Westpark");
When you write struct Y in this context
struct X {
struct Y {
int z;
} y;
} x;
you do two things:
Define struct Y, and
Add field y of type struct Y inside struct X.
The four structs that you define are independent of each other. Each of your structs defines a single shop, because there are no collections inside your struct country.
Here is how you can define your shop using the structures that you defined:
// This is what the structure dictates, probably not what you want
struct country westpark;
strcpy(westpark.countryname, "Germany");
strcpy(westpark.state.statename, "Bavaria");
strcpy(westpark.state.city.cityname, "Ingolstadt");
strcpy(westpark.state.city.shop.shopname, "Westpark");
This does not look like anything that you may want, though. I think you were looking for something like this:
struct country {
char countryname[100];
struct state {
char statename[100];
struct city {
char cityname[100];
int postal;
struct shop {
char shopname[100];
} shop[MAX_SHOP]; // maybe 128
int shopCount;
} city[MAX_CITY]; // Around 256
int cityCount;
} state[MAX_STATE]; // Probably 16
int stateCount;
} country;
The idea here is to construct a country as an array of states, a state as an array of cities, and a city as an array of shops. Each level of this hierarchy also stores a count of items in its level, i.e. stateCount counts how many elements of the state[] array have been filled, cityCount in each state[] stores the number of city[] elements that have been filled, and so on.
The size of this struct is going to be about 50MB, so do not make it an automatic local variable: it should be either an outer scope-static or a function-scope static, because 50 MB is too much of a stack space on most systems. Here is how you would add your shop to this struct:
strcpy(country.countryname, "Germany");
country.stateCount = 1; // For Bavaria
strcpy(country.state[0].statename, "Bavaria");
country.state[0].cityCount = 1; // For Ingolstadt
strcpy(country.state[0].city[0].cityname, "Ingolstadt");
country.state[0].city[0].shopCount = 1; // for Westpark
strcpy(country.state[0].city[0].shop[0].shopname, "Westpark");
Note that this is extremely inefficient, because it pre-allocates everything at the max. Hence the elements of the state[] array representing Bremen and Bavaria would end up with the same number of pre-allocated city[] elements, even though Bavaria is a lot larger, and probably needs more city entries. To deal with this in a resource-efficient way you would need to use dynamic memory allocation.
The variables bavaria, ingolstadt, and westpark are separate items, not members of the country struct.
strcpy(germany.state.city.shop.shopname, "Westpark");
might work (but perhaps not do what you intend).
Based on how your struct is currently defined, you would need to do this:
strcpy(germany.countryname, "Germany");
strcpy(germany.state.statename, "Bavaria");
strcpy(germany.state.city.cityname, "ingolstadt");
strcpy(germany.state.city.shop.shopname, "Westpark");
A better way to define the struct would be like this:
struct shop {
char countryname[100];
char statename[100];
char cityname[100];
int postal;
char shopname[100];
};
Then you could do this:
struct shop myshop;
strcpy(myshop.countryname, "Germany");
strcpy(myshop.statename, "Bavaria");
strcpy(myshop.cityname, "ingolstadt");
strcpy(myshop.shopname, "Westpark");
You have defined four independent structs. They are not linked with each other.
You now can do
strcpy(germany.state.city.shop, "Westpark");
or
strcpy(westpark, "Westpark");
In general, struct member names are compile time things. They are resolved to address offsets by the compiler. You city/state/shop names are runtime data. You cannot use them as struct members.
Also you apparently want to model a 1:n relation. I think you need a different data structure, like e.g. a hash.
I am a newbie in C..I am trying to make some sense of how dynamic memory allocation works in case of structures and arrays..So like for example I have a code like..
struct Person
{
int id;
char *name;
char *place;
};
struct Database
{
struct Person *data_rows;
};
I want to dynamically allocate memory for both the character arrays name and place..and the array of struct data_rows..take their size as input..So what should ideally be the order of allocations and the proper syntax for the same? Thanks.
Well, "obviously" you need to get "struct Database" filled in first:
struct Database MyDatabase;
MyDatabase.data_rows=malloc(sizeof(MyDatabase.data_rows[0])*NumberOfPeople);
Ignoring the fact that I didn't check the malloc() for failure, this will give you an array of "struct Person", all uninitialized. So, most likely, you'll want to initialize them:
int i;
for (i=0; i<NumberOfPeople; i++)
{
struct Person* MyPerson;
MyPerson=&MyDatabase.data_rows[i];
MyPerson->id=i;
MyPerson->name=malloc(...);
/* Do something to store the name in MyPerson->name */
MyPerson->place=malloc(...);
/* Do something to store the place in MyPerson->name */
}
Now, the problem here is the "..." I put on the malloc. It's easy if you use a fixed size, but then you could have just declared your struct to be something like
struct Person
{
int id;
char name[100];
char place[200];
};
Basically, I just can't tell what the length of the names should be, hence I just typed it as "...".
Also, I just guessed what the "id" might be. Using the array index is actually somewhat pointless :-)
Of course, you don't have to do it all now. You could just set the name and place pointers to NULL and fill them in later, like when you're reading the data from a file, or whatever you're planning to do. Or you could just not initialize it here at all, if you're confident that your code always "knows" which fields are initialized and which ones are not.
I would highly recommend to write a functions person_new and person_free that would take care of structure memory management:
struct Person* person_new(char *name, char* place) {
struct Person* person = malloc(sizeof(struct Person));
person->name = strdup(name);
person->place = strdup(place);
return person;
}
void person_free(struct Person* person) {
free(person->name);
free(person->place);
free(person);
}
The best thing would be to convert your structs to classes, the following works also for structs...
You define a constructor and destructor in Database and in Person as following:
struct Person
{
Person(){
name = new char[256];
place = new char[256];
};
~Person(){
delete name;
delete place;
}
int id;
char *name;
char *place;
};
struct Database
{
Database(int nPersons){
data_rows = new Person[nPersons];
};
~Database(){
delete data_rows;
};
struct Person *data_rows;
};
or you can do this without a constructor and destructor and allocate all the stuff sequentially in your code, which is a very ugly way to do this!
as:
Database myData;
myData.data_rows = new Persons[40];
for(int i=0; i < 40; i++){
myData.data_rows[i].name = new char[256];
myData.data_rows[i].place = new char[256];
}
Note that data_rows[i] is nothing more than -> *(data_rows + i) which shifts the address of the pointer i times and then dereferences it!
I've been reading "Learn C the Hard Way" and I ran across an interesting problem that I was hoping someone could explain in detail. The basic exercise was to use a struct involving an example Person struct. In the first case, I had a constructor-ish method (I don't exactly get why the tutorial did it this way if someone wouldn't mind explaining on the side :D) along with the struct like this:
struct Person {
char *name;
int age;
int height;
int weight;
};
struct Person *Person_create(char *name, int age, int height, int weight)
{
struct Person *who = malloc(sizeof(struct Person));
assert(who != NULL);
who->name = strdup(name);
who->age = age;
who->height = height;
who->weight = weight;
}
Along with rest of the code, this runs just fine, but when I print the memory location of the pointers to these structs like:
int main(int argc, char* argv[]) {
struct Person *joe = Person_create("joe alex", 12, 80, 100);
struct Person *joe = Person_create("frank blank", 20, 72, 140);
}
The difference in their memory values are always exactly 40. In comparison, an implementation of the struct constructor like:
struct Person{//is the same as above};
struct Person Person_create (char* name, int age, int height, int weight) {
struct Person newPerson;
newPerson.name = name; //and so on
return newPerson
}
When I print out the memory locations of joe and frank, initialized with the same values as above, with the above implementation, the difference in their memory location appears to be always 20.
I studied a bit of assembly and I am aware that the compiler assigns blocks of memory according to the data types of the struct so I was thinking.. in either implementations, a char array has so many chars so n characters * 1 = char space, and then I have 3 ints so 3*4 = 12; 12 + 9 (Joe Alex\0 right?) = 21.. I probably got the \0 wrong so it's equal to 20 or something, but regardless of the specific memory size of my structs, I'm more interested in why the two different implementations result in a different size in memory (to my understanding, DOUBLE the memory cost is quite a significant amount).
In the first case 4 dynamic allocations are made: two name strings with strdup, and 2 Person structs with malloc. The difference between the struct addresses tells you roughly how much memory was allocated including the first struct, and before the second one[*]
In the second case, no dynamic allocations are made, but I imagine you've created two Person objects on the stack:
struct Person joe = Person_create("joe alex", 12, 80, 100);
struct Person frank = Person_create("frank blank", 20, 72, 140);
The difference between their addresses tells you roughly how much memory the first one occupies[*].
Since you haven't copied the strings, you're pretty much required to either use a string literal as the name, or else to manage its memory separately from the Person struct. The string data is not part of the struct Person -- never will be. newPerson.name = name just stores the pointer, not the string data.
This becomes a nuisance as soon as you start reading the names from a file or the terminal: you'll have to dynamically allocate them anyway, so you won't save any memory, but you'll have to write more code. The exercise probably includes a Person_Destroy function that frees the name, so that the user of struct Person doesn't have to worry about that separately.
[*] Except that the implementation isn't required to allocate these things one after the other, so your method doesn't work in general. It just happens to be giving results on this occasion consistent with the theory that the allocations are placed in the order you made them.
The two methods vary greatly in the way they need to be used:
Define:
struct Person *Person_create(char *name, int age, int height, int weight)
Use:
struct Person *p = Person_create(...);
The Person_create function allocates the structure. The location where this structure will be depends on the function's implementation. The caller only needs to define a pointer to this memory, not a whole person structure.
Define:
struct Person Person_create (char* name, int age, int height, int weight)
Use:
struct Person p = Person_create(...);
Here, the caller allocated a whole person structure, not just a pointer. When the function is called, the data it returns will be copied into the caller's person structure. So the location of the structure depends on the caller.