I would like to save a struct into a db file (or .txt that doesn matter still!) but I ve got the following problem. I ve wanted to create structs inside structs like the following code.
typedef struct classes cl;
typedef struct attribute a;
struct classes{ \\where "a" is a type of struct
a hunter;
a channeler;
a warrior;
a rogue; };
struct human{ \\where "cl" is type of struct classes (
cl Borderlands;
cl Shienear;
cl Arafel;
cl Illian;
cl Tear;
cl Tarabon;
cl Andor;
cl TwoRivers;
cl Amandor;
cl Mayene;
cl Murandy;
};
The question is if i have a variable
struct human data
do i have to save all the branches of the tree(as i think that it is a tree that i have created), or by just saving the root, do I save the whole struct?
P.S. please excuse my way of writting, i am not that experienced in programming
You should make save method for every structure like this:
void save_h(human * h, FILE * stream)
{
save_cl(h->Borderlands,stream);
save_cl(h->Shienear,stream);
save_cl(h->Arafel,stream);
save_cl(h->Illian,stream);
save_cl(h->Tear,stream);
save_cl(h->Tarabon,stream);
...
}
void save_cl(classes * cl, FILE * stream)
{
save_a(cl->hunter,stream);
save_a(cl->channeler,stream);
save_a(cl->warrior,stream);
save_a(cl->rogueon,stream);
...
}
void save_a(attribute * a, FILE * stream)
{
...
}
If you have simple structs with no pointers, fixed size field types and are not planning to move this data onto other machines, you can just simply write entire structure to a binary file since it has linear representation in memory. And read it back the same way. Otherwise, read about marshaling and unmarshaling data. If you don't understand this concept none of the code is actually very helpful.
Here is how I would do it:
#define STRUCTFLAG 565719 // some random number
// NOTE: This is based on the idea that sizeof(int) == sizeof(int *).
// If this is wrong, then make the type of variables such that
// sizeof(typeof variable) = sizeof(int *).
struct basestruct {
int flag; // when initialized, this has the value of STRUCTFLAG, so that we know it's a struct
int size; // total size of the struct, in bytes. set when struct is created.
// all other variables in the struct are either pointers to other structs or of the primitive type of the size 'int *'.
}
struct mystruct {
int flag;
int size;
struct mystruct2 *variable1;
struct mystruct3 *variable2;
}
int isStruct(const void *structAddr)
{
int *casted = (int *) structAddr;
return casted[0] == STRUCTFLAG;
}
void saveStruct(FILE *file, const void *structaddr)
{
// make sure it's a struct
if (isStruct(structaddr))
{
int *casted = (int *) structaddr;
fprintf(file, "%i\n", casted[0]); // print flag
casted++; // skip 'flag';
fprintf(file, "%i\n", casted[0]); // print size
int numVariables = ((casted[0] / sizeof(int)) - 2);
casted++;
for (int i = 0; i < numVariables; i++)
{
if (isStruct(casted + i))
{
saveStruct(file, casted + i);
}
else
{
fprintf(file, "%i\n", casted[i]);
}
}
}
else
{
// report error
}
}
Good luck reading it back in though. You only asked how to save it!
Related
This is my very first post on stackoverflow. I am a CS student learning C, and I am having some issues with the problem I'm working on. Additionally, I should mention that I know very little, so if anything I put here comes off as foolish or ignorant, it is absolutely not my intention
I am aware that there are other posts similar to this one, however so far I feel that I have tried making a lot of amendments that all end with the same result.
I am given a text file in which each line contains studentName(tab)gpa. The total size of the file is unknown, this I must use dynamic memory allocation.
Example of text file format
Jordan 4.0
Bhupesh 2.51
General steps for program
Many details will be left out to save myself from embarrassment, however I will give a high-level overview of the process I am struggling with:
1.) Create dynamic memory array to hold struct for each line
2.) Start looping through file
3.) check the current size of the array to see if reallocation is necessary
4.) Create dynamic array to hold name
5.) Place name and gpa into struct
6.) rinse & repeat
Finally, one last thing. The error occurs when my initial allocated memory limit is reached and the program attempts to reallocate more memory from the heap.
Screenshot of error being thrown in clion debugger
My code is shown below:
#define EXIT_CODE_FAIL 1
#define ROW_COUNT 10
#define BUFFER_SIZE 255
#define VALID_ARG_COUNT 2
struct Student {
float gpa;
char * name;
};
// read the file, pack contents into struct array
struct Student * readFileContents(char *filename, int *rowCounter) {
// setup for loop
int maxDataSize = ROW_COUNT;
float currentStudentGpa = 0;
char studentNameBuffer[BUFFER_SIZE];
// initial structArray pre-loop
struct Student * structArray = calloc(maxDataSize, sizeof(*structArray));
FILE *pFile = fopen(filename, "r");
validateOpenFile(pFile);
// loop through, get contents, of eaach line, place them in struct
while (fscanf(pFile, "%s\t%f", studentNameBuffer, ¤tStudentGpa) > 0) {
structArray = checkArraySizeIncrease(*rowCounter, &maxDataSize, &structArray);
structArray->name = trimStringFromBuffer(studentNameBuffer);
structArray->gpa = currentStudentGpa;
(*rowCounter)++, structArray++;
}
fclose(pFile);
return structArray;
}
// resize array if needed
struct Student * checkArraySizeIncrease(int rowCount, int * maxDataSize, struct Student ** structArray) {
if (rowCount == *maxDataSize) {
*maxDataSize += ROW_COUNT;
**// line below is where the error occurs**
struct Student * newStructArray = realloc(*structArray, *maxDataSize * sizeof(*newStructArray));
validateMalloc(newStructArray);
return newStructArray;
}
return *structArray;
}
// resize string from initial data buffer
char *trimStringFromBuffer(char *dataBuffer) {
char *string = (char *) calloc(strlen(dataBuffer), sizeof(char));
validateMalloc(string);
strcpy(string, dataBuffer);
return string;
}
Once again, I apologize if similar questions have been asked, but please know I have tried most of the recommendations that I have found on stack overflow with no success (of which I'm well aware is the result of my poor programming skill level in C).
I will now promptly prepare myself for my obligatory "first post on stackoverflow" roasting. Cheers!
You are reusing structArray as both the base of the array and a pointer to the current element. This won't work. We need two variables.
There are a number of "loose" variables related to the dynamic array. It's cleaner to define a struct (e.g. dynarr_t below) to contain them and pass just the struct pointer around.
When you're duplicating the string, you must allocate strlen + 1 [not just strlen]. But, the entire function does what strdup already does.
I tried to save as much as possible, but I've had to refactor the code a fair bit to incorporate all the necessary changes.
By passing sizeof(*structArray) to the arrnew function, this allows the struct to be used for arbitrary size array elements.
Anyway, here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define sysfault(_fmt...) \
do { \
printf(_fmt); \
exit(1); \
} while (0)
#define EXIT_CODE_FAIL 1
#define ROW_COUNT 10
#define BUFFER_SIZE 255
#define VALID_ARG_COUNT 2
struct Student {
float gpa;
char *name;
};
// general dynamic array control
typedef struct {
void *base; // base address
size_t size; // bytes in array element
size_t count; // current number of used entries
size_t max; // maximum number of entries
size_t grow; // number of entries to grow
} dynarr_t;
// arrfind -- return pointer to array element
void *
arrfind(dynarr_t *arr,size_t idx)
{
void *ptr;
ptr = arr->base;
idx *= arr->size;
ptr += idx;
return ptr;
}
// arrnew -- create new array control
dynarr_t *
arrnew(size_t siz,size_t grow)
// siz -- sizeof of array element
// grow -- number of elements to grow
{
dynarr_t *arr;
arr = calloc(1,sizeof(*arr));
if (arr == NULL)
sysfault("arrnew: calloc fail -- %s\n",strerror(errno));
arr->size = siz;
arr->grow = grow;
return arr;
}
// arrgrow -- grow array [if necessary]
// RETURNS: pointer to element to fill
void *
arrgrow(dynarr_t *arr)
{
void *ptr;
// grow array if necessary
// NOTE: use of a separate "max" from "count" reduces the number of realloc
// calls
if (arr->count >= arr->max) {
arr->max += arr->grow;
arr->base = realloc(arr->base,arr->size * arr->max);
if (arr->base == NULL)
sysfault("arrgrow: realloc failure -- %s\n",strerror(errno));
}
// point to current element
ptr = arrfind(arr,arr->count);
// advance count of elements
++arr->count;
return ptr;
}
// arrtrim -- trim array to actual number of elements used
void
arrtrim(dynarr_t *arr)
{
arr->base = realloc(arr->base,arr->size * arr->count);
if (arr->base == NULL)
sysfault("arrtrim: realloc failure -- %s\n",strerror(errno));
arr->max = arr->count;
}
void
validateMalloc(void *ptr)
{
if (ptr == NULL) {
perror("validateMalloc");
exit(1);
}
}
void
validateOpenFile(FILE *ptr)
{
if (ptr == NULL) {
perror("validateOpenFile");
exit(1);
}
}
// resize string from initial data buffer
char *
trimStringFromBuffer(char *dataBuffer)
{
#if 0
#if 0
char *string = calloc(1,strlen(dataBuffer));
#else
char *string = calloc(1,strlen(dataBuffer) + 1);
#endif
validateMalloc(string);
strcpy(string, dataBuffer);
#else
char *string = strdup(dataBuffer);
validateMalloc(string);
#endif
return string;
}
// read the file, pack contents into struct array
dynarr_t *
readFileContents(char *filename)
{
dynarr_t *arr;
// setup for loop
float currentStudentGpa = 0;
char studentNameBuffer[BUFFER_SIZE];
struct Student *structArray;
arr = arrnew(sizeof(*structArray),10);
FILE *pFile = fopen(filename, "r");
validateOpenFile(pFile);
// loop through, get contents, of eaach line, place them in struct
while (fscanf(pFile, "%s\t%f", studentNameBuffer, ¤tStudentGpa) > 0) {
structArray = arrgrow(arr);
structArray->name = trimStringFromBuffer(studentNameBuffer);
structArray->gpa = currentStudentGpa;
}
fclose(pFile);
arrtrim(arr);
return arr;
}
I think your issue is with the calculation of the size of the realloc. Rather than using sizeof(*newStructArray), shouldn't you really be using the size of your pointer type? I would have written this as realloc(*structArray, *maxDataSize * sizeof(struct Student *))
There's a lot of other stuff in here I would never do - passing all those variables in to checkArraySizeIncrease as pointers is generally a bad idea because it can mask the fact that things are getting changed, for instance.
There is an issue in allocation of the buffer for string
char *string = (char *) calloc(strlen(dataBuffer), sizeof(char));
it should be:
char *string = (char *) calloc(1 + strlen(dataBuffer), sizeof(char));
as C-strings require extra 0-byte at the end.
Without it, the following operation:
strcpy(string, dataBuffer);
may damage data after the buffer, likely messing malloc() metadata.
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.
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;
};
I am trying to set a array of structure in a array of structure. to this i have created a function. how ever i try it i am not able to do it.
struct polygon {
struct point polygonVertexes[100];
};
struct polygon polygons[800];
int polygonCounter = 0;
int setPolygonQuardinates(struct point polygonVertexes[]) {
memcpy(polygons[polygonCounter].polygonVertexes, polygonVertexes,4);
}
int main(){
struct point polygonPoints[100] = {points[point1], points[point2], points[point3], points[point4]};
setPolygonQuardinates(polygonPoints);
drawpolygon();
}
void drawpolygon() {
for (int i = 0; polygons[i].polygonVertexes != NULL; i++) {
glBegin(GL_POLYGON);
for (int j= 0; polygons[i].polygonVertexes[j].x != NULL; j++) {
struct point pointToDraw = {polygons[i].polygonVertexes[j].x, polygons[i].polygonVertexes[j].y};
glVertex2i(pointToDraw.x, pointToDraw.y);
}
glEnd();
}
}
when i run this i get the following error
Segmentation fault; core dumped; real time
You cannot use strcpy here; that is for null-terminated strings. A struct is not a null-terminated string :) To copy objects around, use memcpy.
To pass arrays around in C, a second parameter stating the number of objects in the array is usually passed as well. Alternatively, the array and length are put into a struct, and that struct is passed around.
EDIT: An example of how to do this:
void setPolygonQuardinates(struct point* polygonVertexes, size_t polygonVertexesSize) {
memcpy(polygons[polygonCounter].polygonVertexes, polygonVertexes, sizeof(point) * polygonVertexesSize);
}
int main(){
struct point polygonPoints[100] = {points[point1], points[point2], points[point3], points[point4]};
/* ^---------v make sure they match */
setPolygonQuardinates(polygonPoints, 100);
drawpolygon();
}
If you need this explained, please ask. I think it is idiomatic C code.
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()).