I have an ArrayList struct and Department struct that go as follows:
typedef struct ArrayList {
void** elements;
int size;
int length;
} ArrayList;
typedef struct Department {
char* name;
ArrayList* courses;
} Department;
To print my list, I'm using these two methods:
void* get(ArrayList* arraylist, int i) {
if (i < 0 || i >= arraylist -> size) {
return (void*) NULL;
}
return arraylist -> elements[i];
}
void printAL(ArrayList* arraylist) {
for (int i = 0; i < arraylist -> size; i++) {
printf("%s\n", (char*) get(arraylist, i));
}
}
The issue I'm facing, however, is that when I add a Department to my ArrayList, the line 'return arraylist -> elements[i];' returns the address of that struct. I'm trying to get it to print the name of the struct using 'return arraylist -> elements[i] -> name' but I keep getting a warning that I'm dereferencing a void* pointer, followed by an error that says 'request for member ‘name’ in something not a structure'. This obviously means that 'arraylist -> elements[i]' isn't a struct but rather an address. How can I reference the name of the struct at that address then? I'm quite confused because of the double pointer in the ArrayList struct.
TIA!
You need different printing functions for each different type of data element that could be in the ArrayList. You need one function to print departments; you need a different function to print courses. You pass the function pointer to the printing function — printAL() — along with a pointer to other data (which in this case is probably just a FILE *, but could be a more general structure).
This is analogous to the qsort() function in standard C. It can sort any data type; you just need to pass it a different comparator function for different data types.
Like this:
#include <stdio.h>
#include <stdlib.h>
typedef struct ArrayList
{
void **elements;
int size; /* Allocated size */
int length; /* Space in use */
} ArrayList;
typedef struct Department
{
char *name;
ArrayList *courses;
} Department;
static void *get(ArrayList *arraylist, int i)
{
if (i < 0 || i >= arraylist->size)
return NULL;
return arraylist->elements[i];
}
static void printAL(ArrayList *arraylist, void (*function)(const void *data, void *thunk), void *thunk)
{
for (int i = 0; i < arraylist->length; i++)
{
(*function)(get(arraylist, i), thunk);
}
}
static void put(ArrayList *al, void *data)
{
if (al->length >= al->size)
{
size_t new_size = (al->size + 2) * 2;
void *new_data = realloc(al->elements, new_size * sizeof(void *));
if (new_data == 0)
{
fprintf(stderr, "Failed to allocate %zu bytes memory\n", new_size * sizeof(void *));
exit(1);
}
al->elements = new_data;
al->size = new_size;
}
al->elements[al->length++] = data;
}
/*
typedef struct Course
{
const char *name;
const char *code;
// ...
} Course;
static void print_courseinfo(const void *data, void *thunk)
{
FILE *fp = thunk;
const Course *cp = data;
fprintf(fp, " - %s (%s)\n", cp->name, cp->code);
}
*/
static void print_deptname(const void *data, void *thunk)
{
FILE *fp = thunk;
const Department *dp = data;
fprintf(fp, "Name: %s\n", dp->name);
/*
if (dp->courses != 0)
printAL(dp->courses, print_courseinfo, thunk);
*/
}
int main(void)
{
ArrayList al = { 0, 0, 0 };
Department dl[] =
{
{ "Engineering", 0 },
{ "Physics", 0 },
{ "Mathematics", 0 },
{ "Chemistry", 0 },
{ "Biology", 0 },
{ "English", 0 },
{ "Computational Astronomy and Universe-Scale Data Modelling", 0 },
{ "Economics", 0 },
};
enum { DL_SIZE = sizeof(dl) / sizeof(dl[0]) };
for (size_t i = 0; i < DL_SIZE; i++)
put(&al, &dl[i]);
printAL(&al, print_deptname, stdout);
return 0;
}
Sample output:
Name: Engineering
Name: Physics
Name: Mathematics
Name: Chemistry
Name: Biology
Name: English
Name: Computational Astronomy and Universe-Scale Data Modelling
Name: Economics
You didn't document what the length and size members of the ArrayList represent. I've annotated what I've assumed, but I had to change the printAL() function to iterate over length elements instead of size elements, so I may have inverted the meaning you intended. It's easy to reverse them. I tend to use names like max_elements and num_elements for the job; it is more obvious what they're for, perhaps, since length and size are ambiguous or even equivalent in many contexts.
There's skeletal code in there to show how to handle the ArrayList of courses offered by each department. I couldn't be bothered to write code to initialize a separate ArrayList for each department, though it wouldn't be particularly hard to do.
I still prefer the pre-standard notation (*funcptr)(arg1, arg2) notation for invoking a function designated by a function pointer — it was necessary when I learned C, and I still find it clearer than the alternative. You're excused if you prefer funcptr(arg1, arg2) instead, though that can leave me wondering where funcptr is defined.
You can also find some code closely related to what you're doing in my SOQ (Stack Overflow Questions) repository on GitHub as files aomcopy.c, aomcopy.h, aommngd.c, aommngd.h, aomptr.c, aomptr.h, aoscopy.c, aoscopy.h, aosptr.c and aosptr.h in the src/libsoq sub-directory.
aomcopy.c, aomcopy.h: array of memory blocks, copied.
aommngd.c, aommngd.h: array of memory blocks, managed.
aomptr.c, aomptr.h: array of memory blocks, 'raw'.
aoscopy.c, aoscopy.h: array of strings, copied.
aosptr.c. aosptr.h: array of strings, 'raw'.
The 'raw' versions simply take the pointer passed and store it. The onus is on the user to ensure the data pointed at remains valid while the array lasts. The 'copied' versions allocate a simple copy of the data passed to it; it doesn't matter if the data passed is reused to store the next value. The 'managed' version calls user-defined functions to create copies of the data structures. This would be necessary if you have a complex structure (like a department) where you need a 'deep copy' of the data.
Related
I wrote a program in linux kernel, which should allocate memory for 5 simple structures each of with unique id, so i used static int in a constructor and increment it and in the end i just print messages to the buffer. When i saw the buffer i got a strange result because the ids had values like 0, 64, 128, 192, 256 i was surprised because i thought that i will see the values like 0, 1, 2, 3, 4. Why did i get result like this it is something wrong?
Output:
[ 2653.505140] Example struct id: 0
[ 2653.505143] Example string field content: Test
[ 2653.526565] Example struct id: 64
[ 2653.526568] Example string field content: Test
[ 2653.526623] Example struct id: 128
[ 2653.526625] Example string field content: Test
[ 2653.550439] Example struct id: 192
[ 2653.550443] Example string field content: Test
[ 2653.550513] Example struct id: 256
[ 2653.550514] Example string field content: Test
There is my code:
#include<linux/module.h>
#include<linux/slab.h>
#include<linux/string.h>
static struct example_struct {
unsigned int id;
char example_string[10];
} *example_struct_pointer[5];
static struct kmem_cache *example_cachep[5];
static void example_constructor(void *argument)
{
static unsigned int id;
static char test_string[] = "Test";
struct example_struct *example = (struct example_struct *)argument;
example->id = id;
strcpy(example->example_string,test_string);
id++;
}
void print_example_struct(struct example_struct *example)
{
pr_notice("Example struct id: %d\n",example->id);
pr_notice("Example string field content: %s\n",example->example_string);
}
static int __init zad1_init(void)
{
int i;
for(i = 0; i < 5; i++){
example_cachep[i] = kmem_cache_create("example cache", sizeof(struct example_struct),0, SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, example_constructor);
if(IS_ERR(example_cachep[i])) {
pr_alert("Error creating cache: %ld\n",PTR_ERR(example_cachep[i]));
return -ENOMEM;
}
}
for(i = 0; i < 5; i++){
example_struct_pointer[i] = (struct example_struct *) kmem_cache_alloc(example_cachep[i],GFP_KERNEL);
if(IS_ERR(example_struct_pointer[i])) {
pr_alert("Error allocating form cache: %ld\n", PTR_ERR(example_struct_pointer[i]));
kmem_cache_destroy(example_cachep[i]);
return -ENOMEM;
}
}
return 0;
}
static void __exit zad1_exit(void)
{
int i;
for(i = 0; i < 5; i++){
if(example_cachep[i]) {
if(example_struct_pointer[i]) {
print_example_struct(example_struct_pointer[i]);
kmem_cache_free(example_cachep[i],example_struct_pointer[i]);
}
kmem_cache_destroy(example_cachep[i]);
}
}
}
module_init(zad1_init);
module_exit(zad1_exit);
MODULE_LICENSE("GPL");
ctor parameter for kmem_cache_create function is not a constructor in the common sense.
There is no guarantee that given function will be called only once and only when the object is requested from the cache. The guarantee is actually the opposite (mm/slab_common.c:389):
* The #ctor is run when new pages are allocated by the cache.
So, it could be much more calls to ctor than the number of objects requested from the cache.
If you simply want to allocate and initialize several objects, then just define corresponding constructor:
// Single cache can be used for allocate multiple object.
// No needs to define a cache-per-object.
static struct kmem_cache* example_cachep;
// Constructor for the object of type 'example_struct'.
static struct example_struct* create_example_object(void)
{
static unsigned int id;
struct example_struct *example = kmem_cache_alloc(example_cachep, GFP_KERNEL);
if (example != NULL)
{
example->id = id;
strcpy(example->example_string, "Test");
id++;
}
return example;
}
static int __init zad1_init(void)
{
// ...
// Create the cache.
example_cachep = kmem_cache_create("example cache", sizeof(struct example_struct),0, SLAB_HWCACHE_ALIGN|SLAB_POISON|SLAB_RED_ZONE, example_constructor);
// create several 'example' objects.
for(i = 0; i < 5; i++){
example_struct_pointer[i] = create_example_object();
if(example_struct_pointer[i] == NULL)
{
// ... Somehow process the allocation failure.
}
}
return 0;
}
ctor parameter is useful to initialize only some fields of the object. Such initialization could save a bit time (slightly improve performance), but only when both following conditions applies:
You actively create (allocate + initialize) and destroy (deallocate) objects from the cache.
The fields you are going to initialize have exactly the same values in just initialized objects and in the object which is going to be deallocated.
For example, you could have a usage_count field in your object, and this field is equal to 0 both when an object is just initialized and when an object is going to be deallocated.
The usefulness of ctor for such fields is that ctor may be NOT called for an allocated object which was previously deallocated from the same cache. That is, you could save a time by not initializing a field which already has a desired value.
Because not initializing a single (or several) values could save only a little time, but ctor could be called more times than it is needed, then you should carefully measure whether you actually gain a performance instead of loosing it.
I have implemented naive Bayes but I did it in static memory allocation.
I wanted to convert into dynamic but my small brain is not able to do that.
#define COLS 4 //including class label
#define BINS 100
#define CLASS_COL 0
#define CLASS 2
The idea is to fetch above value from a configuration file and then set it.
struct each_col //Probability for each feature based on classes
{
double col_PB[BINS][CLASS];
};
struct NB_Class_Map
{
char label[250];
unsigned int label_value;
double class_PB;
};
struct NB //Proabability for entire feature
{
struct NB_Class_Map classes[CLASS];
struct each_col cols[COLS];
};
NB nb = {0}; //gloabal value
The function to train NB:
long strhash(const char *str)
{
long hash = 5381;
int c;
printf("IN: %s ",str);
while (c = *str++)
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
printf("OUT: %ld ||",hash);
return hash;
}
int setup_train_NB(vector<vector<string> > &data)
{
//Finding the feature count
static int class_label = -1;
for(unsigned int i=0;i<data.size();i++)
{
unsigned int Class;
printf("\n===========New ROW==============\n");
int k;
for(k=0;k<CLASS;k++)
{
if(strcmp(data[i][CLASS_COL].c_str(), nb.classes[k].label) == 0)
{
printf("MATCHED\n");
Class = nb.classes[k].label_value;
break;
}
}
if(k==CLASS)
{
printf("NOT MATCHED\n");
class_label++;
nb.classes[class_label].label_value = class_label;
strcpy( nb.classes[class_label].label, data[i][CLASS_COL].c_str());
Class = nb.classes[class_label].label_value;
}
printf("Class: %d ||\n", Class);
for(unsigned j=0;j<data[0].size();j++)
{
printf("\n===========New COLUMN==============\n");
if(j == CLASS_COL)
{
nb.classes[Class].class_PB++;
continue;
}
unsigned int bin = strhash((data[i][j].c_str()))%BINS;
printf("Bin: %d ||", bin);
printf("Class: %d ||\n", Class);
nb.cols[j].col_PB[bin][Class]++; //[feature][BINS][CLASS]
}
}
//Finding the feature PB
for(unsigned int i=0;i<COLS;i++)
{
if(i==CLASS_COL)
continue;
for(unsigned j=0;j<BINS;j++)
{
for(unsigned k=0;k<CLASS;k++)
{
// nb.cols[i].col_PB[j][k] /= nb.classes[k].class_PB; //without laplacian smoothing
nb.cols[i].col_PB[j][k] = (nb.cols[i].col_PB[j][k] + 1) / (nb.classes[k].class_PB + COLS - 1); //with laplace smoothing
}
}
}
int k = 0;
int sum = 0;
while(k<CLASS)
{
sum += nb.classes[k].class_PB;
k++;
}
//Finding the class PB
k = 0;
while(k<CLASS)
{
nb.classes[k].class_PB /= sum;
k++;
}
return 0;
}
The program is supposed to be written in C but for the moment, I use vector to fetched the data from a CSV file. Please ignore that for the moment. The actual question is how I can remove those hardcoded define value and still declare my structs.
Although it does not matter but the CSV file look like this and it may change in terms of no of cols and labels. The first line is ignored and not put into data.
Person,height,weight,foot
male,654,180,12
female,5,100,6
female,55,150,8
female,542,130,7
female,575,150,9
What actually I am doing is, for each value is put into a bin, then for each of those value, I am finding proabability for the CLASS/label i.e male = 0, female = 1
Basically:
Define variables instead of preprocessor macro constants: size_t cols; size_t bins; etc.
Replace your 1-dimensional fixed-size arrays with pointers (initialized to NULL!) and length variables. Alternatively, you could use a struct mytype_span { size_t length; mytype* data; }
Replace your 2-dimensional fixes-size arrays with "1-dimensional" pointers (also initialized to NULL of course) and pairs off dimension variables. Again, you could use a struct.
Replace your 2-d array accesses a[x][y] with a "linearized" access, i.e. a[x * row_length_of_a + y] (or you could do this in an inline function which takes the relevant arguments, or a struct mytype_span)
When you've read your configuration values from, um, wherever - set the relevant length variables (see above).
use the malloc() library function to allocate the correct amount of space; remember to check the malloc() return value to make sure it's not null, before using the pointer values!
Your use of struct, is probably wrong, except for struct NB_Class_Map. You shouldn't use struct in the goal of puting big arrays in the same variable. Instead of this, you should define of variable for each array, not putting it inside a struct, and instead of using array, replace it by a pointer. Then you can allocate memory to your pointer. e.g. :
struct mydata {
type1 field1;
type2 field2;
etc...
} *myarray;
myarray = calloc(number_of_record_you_need, sizeof(struct mydata));
// here, error checking code, etc.
Now, having done that, if you really want, you may put your different pointers into a global structure, but each of your table should be allocated separately.
Edit (about your variables) :
NB has no real interest as a structure. It's just 2 variables you glued together:
struct NB_Class_Map classes[CLASS];
struct each_col cols[COLS];
NB.Cols is not really a structure. It's just a three dimensional array
double cols[COLS][BINS][CLASS];
The only real structure is
struct NB_Class_Map
{
char label[250];
unsigned int label_value;
double class_PB;
};
So you just have to replace
struct NB_Class_Map classes[CLASS];
with
struct NB_Class_Map *classes;
and
double cols[COLS][BINS][CLASS];
with
double *cols[BINS][CLASS];
Or if you want a type name :
typedef double each_col[BINS][CLASS];
each_cols *cols;
and allocate memory space for classes and colls with calloc.
Now, if you really want this struct NB :
typedef double each_col[BINS][CLASS];
struct NB
{
struct NB_Class_Map *classes;
each_col *cols;
};
As already written at issue#2217, I want to design a function which return a list of oid in the first out param.
Should I:
Return the list of oids as a pointer to pointer?
int git_commit_tree_last_commit_id(git_oid **out, git_repository *repo, const git_commit *commit, char *path)
Or return the list of oids as a pointer to a custom struct?
int git_commit_tree_last_commit_id(git_oid_xx_struct *out, git_repository *repo, const git_commit *commit, char *path)
What is your advice?
The question is, how do you know how many OIDs are in the returned array, and who allocates the underlying memory.
For the first part there are several possibilities,
Return the number in a separate return parameter,
Use a sentinel value to terminate the list.
Return a new struct type, like git_strarray that contains the count and the
raw data.
For the second part, either
the caller can allocate the underlying memory
The function can allocate the memory
the new struct type can manage the memory.
Which path you go down depends upon what you want the code to look like, how much you expect it to be reused, how critical performance is etc.
To start with I'd go with the simplest, which IMO is function returns count and allocates memory.
That means my function would have to look like this:
int get_some_oids_in_an_array(OID** array, int * count, ... ) {
...
*count = number_of_oids;
*array = (OID*)malloc( sizeof(OID)*number_of_oids);
for(i=0; i<number_of_oids; ++i) {
*array[i]=...;
}
...
return 0;
}
/* Example of usage */
void use_get_oids() {
OID* oids;
int n_oids;
int ok = get_some_oids_in_an_array(&oids, &n_oids, ...);
for(i=0; i<n_oids; ++i ) {
... use oids[i] ...
}
free(oids);
}
Note: I'm returning an array of OID, rather than an array of OID*, either is a valid option, and which will work best for you will vary.
If it turned out I was using this kind of pattern often, then would consider switching to the struct route.
int get_some_oids( oidarray * oids, ... ) {
int i;
oidarray_ensure_size(number_of_oids);
for(i=0; i<number_of_oids; ++i) {
oidarray_set_value(i, ...);
}
return 0;
}
typedef struct oidarray {
size_t count;
OID* oids;
};
/* Example of usage */
void use_get_oids() {
oid_array oids = {0};
get_some_oids(&oids);
for(i=0; i<oids.count; ++i) {
... use oids.oids[i] ...
}
oidarray_release(&oids);
}
How do you specify a dynamic array of static arrays in C?
I want to make a struct holding two dynamic arrays of static arrays.
struct indexed_face_set {
double * [3] vertices;
int * [3] faces;
};
This should hold a dynamic list of vertices, which are each 3 doubles, and a dynamic list of faces, which are each 3 ints.
The syntax is, well, C's approach to declarations is not the cleanest and C++ inherited that...
double (*vertices)[3];
That declaration means that vertices is a pointer to double [3] objects. Note that the parenthesis are needed, otherwise (as in double *vertices[3]) it would mean an array of 3 double*.
After some time you end up getting use to the inverted way of parenthesis on expressions...
For the specific case of a structure containing two arrays each of dimension 3, it would be simpler to make the arrays a part of the structure, rather than dynamically allocating them separately:
struct indexed_face_set
{
double vertices[3];
int faces[3];
};
However, there certainly could be cases where it makes sense to handle dynamic array allocation. In that case, you need a pointer to an array in the structure (and not an array of pointers). So, you would need to write:
struct indexed_face_set
{
double (*vertices)[3];
int (*faces)[3];
};
To allocate a complete struct indexed_face_set, you need to use something like new_indexed_face_set() and to free one you need to use something like destroy_indexed_face_set():
struct indexed_face_set *new_indexed_face_set(void)
{
struct indexed_face_set *new_ifs = malloc(sizeof(*new_ifs));
if (new_ifs != 0)
{
double (*v)[3] = malloc(sizeof(*v));
int (*f)[3] = malloc(sizeof(*f));
if (v == 0 || f == 0)
{
free(v);
free(f);
free(new_ifs);
new_ifs = 0;
}
else
{
new_ifs->vertices = v;
new_ifs->faces = f;
}
}
return(new_ifs);
}
void destroy_indexed_face_set(struct indexed_face_set *ifs)
{
if (ifs != 0)
{
free(ifs->vertices);
free(ifs->faces);
free(ifs);
}
}
Then you can use it like this:
void play_with_ifs(void)
{
struct indexed_face_set *ifs = new_indexed_face_set();
if (ifs != 0)
{
(*ifs->vertices)[0] = 3.14159;
(*ifs->vertices)[1] = 2.71813;
(*ifs->vertices)[2] = 1.61803;
(*ifs->faces)[0] = 31;
(*ifs->faces)[1] = 30;
(*ifs->faces)[2] = 29;
do_something_fancy(ifs);
destroy_indexed_face_set(ifs);
}
}
Note that the notation using pointers to arrays is moderately messy; one reason why people do not often use them.
You could use this fragment as the body of a header:
#ifndef DASS_H_INCLUDED
#define DASS_H_INCLUDED
struct indexed_face_set;
extern void play_with_ifs(void);
extern void do_something_fancy(struct indexed_face_set *ifs);
extern void destroy_indexed_face_set(struct indexed_face_set *ifs);
extern struct indexed_face_set *new_indexed_face_set(void);
#endif /* DASS_H_INCLUDED */
It doesn't need any extra headers included; it does not need the details of the structure definition for these functions. You'd wrap it in suitable header guards.
Because the code above is a bit messy when it comes to using the arrays, most people would use a simpler notation. The header above can be left unchanged, but the code could be changed to:
struct indexed_face_set
{
double *vertices;
int *faces;
};
struct indexed_face_set *new_indexed_face_set(void)
{
struct indexed_face_set *new_ifs = malloc(sizeof(*new_ifs));
if (new_ifs != 0)
{
double *v = malloc(3 * sizeof(*v));
int *f = malloc(3 * sizeof(*f));
if (v == 0 || f == 0)
{
free(v);
free(f);
free(new_ifs);
new_ifs = 0;
}
else
{
new_ifs->vertices = v;
new_ifs->faces = f;
}
}
return(new_ifs);
}
void destroy_indexed_face_set(struct indexed_face_set *ifs)
{
if (ifs != 0)
{
free(ifs->vertices);
free(ifs->faces);
free(ifs);
}
}
void play_with_ifs(void)
{
struct indexed_face_set *ifs = new_indexed_face_set();
if (ifs != 0)
{
ifs->vertices[0] = 3.14159;
ifs->vertices[1] = 2.71813;
ifs->vertices[2] = 1.61803;
ifs->faces[0] = 31;
ifs->faces[1] = 30;
ifs->faces[2] = 29;
do_something_fancy(ifs);
destroy_indexed_face_set(ifs);
}
}
This is much simpler to understand and use and would generally be regarded as more idiomatic C.
Since the size of each array is fixed, there's no particular need to record the size in the structure. If the sizes varied at runtime, and especially if some indexed face sets had, say, 8 vertices and 6 faces (cuboid?), then you might well want to record the sizes of the arrays in the structure. You'd also specify the number of vertices and number of faces in the call to new_indexed_face_set().
I'm having some very strange bug in my ANSI C program.
I'm using debugger and I've observed that 'size' variable is corrupted in function 'doSthing.' Outside of 'doSthing' 'size' got a proper value, but inside 'doSthing' I've got a value nothing similar to what it should be, possibly some random data. This would be not be such a mystery but...
In 'doAnotherThing' which is called from 'doSthing' I get the proper value again. I suppose if it passes the correct value, it is not corrupted anyway, am I wrong? But then why does it have a different value?
The pointer in struct does not change inside the functions.
Memory is allocated for both oTV and oTV->oT.
I really don't see what's happening here...
typedef struct{
ownType *oT[] /* array of pointers */
int size;
} ownTypeVector;
void doSthing(ownTypeVector* oTV);
void doAnotherThing(ownTypeVector* oTV);
void doSthing(ownTypeVector* oTV)
{
...
doAnotherThing(oTV);
...
}
Thanks for your comments, I collected all the code that contains control logic and data structures so that it compiles. It runs on in an embedded systems, that can receive characters from multiple sources, builds strings from it by given rules and after the strings are ready, calls a function that needs that string. This can also be a list of functions. This is why I have function pointers - I can use the same logic for a bunch of things simply by choosing functions outside the 'activityFromCharacters' function.
Here I build a data structre with them by adding A-s, B-s and C-s to the AVector.
Of course every one of these separate sources has their own static strings so that they do not bother each other.
The problem again in the more detailed version of the code:
'aV->size' has got a proper value everywhere, except 'handleCaGivenWay.' Before it gets calles, 'aV->size' is ok, in 'addA' 'aV->size' is ok, too. After leaving 'handleCaGivenWay' it is ok again.
#define NUMBER_OF_AS 1
#define NUMBER_OF_BS 5
#define NUMBER_OF_CS 10
typedef struct{
char name[81];
} C;
typedef struct{
C *c[NUMBER_OF_CS]; /* array of pointers */
int size;
int index;
} B;
typedef struct{
B *b[NUMBER_OF_BS]; /* array of pointers */
char name[81];
int size;
} A;
typedef struct{
A *a[NUMBER_OF_AS]; /* array of pointers */
int size;
} AVector;
typedef struct {
char *string1;
char *string2;
} stringBundle;
typedef struct{
void (*getCharacter)(char *buffer);
void (*doSthingwithC)(stringBundle* strings,AVector* aV);
AVector* aV;
} functionBundle;
void getCharFromaGivenPort(char *buffer)
{
//...
}
void addA(AVector * aV, stringBundle* strings)
{
aV->a[aV->size]->size = 0;
++aV->size;
int i = 0;
if(strlen(strings->string2) < 81)
{
for(i;i<81;++i)
{
aV->a[aV->size-1]->name[i] = strings->string2[i];
}
}
else {report("Too long name for A:");
report(strings->string2);}
}
void handleCaGivenWay(stringBundle* strings,AVector* aV)
{
A* a;
a = NULL;
if(aV->size) { a = aV->a[aV->size-1]; }
switch(1)
{
case 1: addA(aV,strings); break;
case 2: //addB()...
default: if (a && aV->size)
{ //addC(a->thr[a->size-1],c);
}
else report("A or B or C invalid");
break;
}
//handleCaGivenWay
}
void activityFromCharacters(stringBundle* strings,functionBundle* funcbundle)
{
/* some logic making strings from characters by */
/* looking at certain tokens */
(* funcbundle->doSthingwithC)(strings,funcbundle->aV);
}
//activityFromCharacters
AVector* initializeAVector(void)
{
AVector* aV;
if (NULL == (aV = calloc(1,sizeof(AVector))))
{ report("Cannot allocate memory for aVector."); }
int i = 0;
int j = 0;
int k = 0;
for(i; i < NUMBER_OF_AS; ++i)
{
if (NULL == (aV->a[i] = calloc(1,sizeof(A))))
{ report("Cannot allocate memory for As."); }
aV->a[i]->size = 0;
aV->a[i]->name[0] = 0;
for(j; j < NUMBER_OF_BS; ++j)
{
if (NULL == (aV->a[i]->b[j] = calloc(1,sizeof(B))))
{ report("Cannot allocate memory for Bs."); }
aV->a[i]->b[j]->size = 0;
for(k; k < NUMBER_OF_CS; ++k)
{
if (NULL == (aV->a[i]->b[j]->c[k] = calloc(1,sizeof(C))))
{ report("Cannot allocate memory for Cs."); }
}
}
}
aV->size = 0;
return aV;
//initializeProgramVector
}
int main (void)
{
AVector* aV;
aV = initializeAVector();
while(1)
{
static stringBundle string;
static char str1[81];
static char str2[81];
string.string1 = str1;
string.string2 = str2;
functionBundle funcbundle;
funcbundle.getCharacter = &getCharFromaGivenPort;
funcbundle.doSthingwithC = &handleCaGivenWay;
funcbundle.aV = aV;
activityFromCharacters(&string,&funcbundle);
}
//main
}
your code shows that it hasn't any error...
But i think you are doing mistake in getting the value of size in doSthing function.
you are printing there its address. so concentrate on some pointer stuff..
Try printing the oTV->size just before the call and as the first statement in doSthing function. If you get the correct value in both print, then the problem is with the function doSthing. Problem could be better understood if you've shown the code that calls doSthing.
Searched a long time to find this. I found 2 problems, but dont know what exactly you are trying to accomplish so i cannot tell for certain that the fix'es i propose are what you intend.
typedef struct{
A *a[NUMBER_OF_AS]; /* array of pointers */
int size;
} AVector;
// and in addA():
aV->a[aV->size]->size = 0;
First: You are inlining the array of pointers in the struct. What i think what you want and need is a pointer to a pointer array so that it can grow which is what you want in addA() i think. The line from addA() aV->a[aV->size]->size = 0; does not communicate your intention very well but it looks like you are trying to change the value beyond the last entry in the array and since it is inlined in the struct it would result to the separate field size by pure coincidence on some alignments; this is a very fragile way of programming. So what i propose is this. Change the struct to contain A** a; // pointer to pointer-array, malloc it initially and re-malloc (and copy) it whenever you need it to grow (in addA()).