How to generically assign a pointer passed into a function in C - c

I am new to C and wondering how to do some pointer stuff. Specifically here I am wondering how you can pass a pointer into a function and "get a value out of the function". Sort of like this (semi-pseudocode):
assign_value_to_pointer(void* pointer) {
if (cond1) {
pointer = 10;
} else if (cond2) {
pointer = "foo";
} else if (cond3) {
pointer = true;
} else if (cond4) {
pointer = somestruct;
} else if (cond5) {
pointer = NULL;
} else if (cond6) {
// unknown type!
pointer = flexiblearraymember.items[index];
}
}
main() {
void* pointer = NULL;
assign_value_to_pointer(&pointer);
if (cond1) {
assert(pointer == 10);
} else if (cond2) {
assert(pointer == "foo");
} else if (cond3) {
assert(pointer == true);
} else if (cond4) {
assert(pointer == somestruct);
} else if (cond5) {
assert(pointer == NULL);
}
}
Put another way:
p = new Pointer()
assign_a_value(p)
assert(p.value == 10) // or whatever
Basically it is passing the pointer into the function, the function is assigning a value to the pointer, and then you can use that value outside of the function when it returns. You may not know what kind of value you are getting from the function (but that can be handled by extending this to use structs and such), hence the void pointer. The main goal though is just passing a pointer into some function and having it absorb some value.
Wondering how to do this properly in C with a quick example implementation. Doesn't have to cover every case just enough to get started.
I would like to use this to implement stuff like passing in a NULL error object to a function, and if there is an error, it sets the pointer of the error to some error code, etc.
I don't think this should be a broad question, but if it is, it would be helpful to know where to look for a more thorough explanation or examples in source code.

First, I'll answer your question directly, hopefully you understand why you need to be reaaally careful. This can be a useful technique for implementing queues, or communication stacks - but you need to be CERTAIN that you can regain track of what types are being stored or your program logic will totally break. I'll then try to briefly cover some of the use cases and some methods of making it safe(r).
Simple example doing exactly what you said
#include <stdio.h>
#include <stdlib.h>
//Some basic error type for reporting failures
typedef enum my_error
{
ERROR_NONE = 0,
ERROR_FAIL = 1,
} my_error;
struct my_struct
{
int age;
char *name;
int order_count;
};
int someCond = 1;
//Let's start with a simple case, where we know the type of the pointer being passed (an int)
//If int_out is NULL, then this function will invoke undefined behavior (probably a
//runtime crash, but don't rely on it).
my_error assign_int(int *int_out)
{
if(someCond)
*int_out = 5;
else
*int_out = 38;
return ERROR_NONE;
}
//Need to use a 'double pointer', so that this function is actually changing the pointer
//that exists in the parent scope
my_error dynamically_assign_value_to_pointer(void **pointer)
{
//A pointer internal to this function just to simplify syntax
void *working_ptr = NULL;
if(someCond)
{
//Allocate a region of memory, and store its location in working_ptr
working_ptr = malloc(sizeof(int));
//store the value 12 at the location that working_ptr points to (using '*' to dereference)
*((int *) working_ptr) = 12;
}
else
{
//Allocate a region of memory, and store its location in working_ptr
working_ptr = malloc(sizeof(struct my_struct));
//Fill the struct with data by casting (You can't dereference a void pointer,
//as the compiler doesn't know what it is.)
((struct my_struct *) working_ptr)->age = 22;
((struct my_struct *) working_ptr)->name = "Peter";
((struct my_struct *) working_ptr)->order_count = 6;
}
//Set the pointer passed as an argument to point to this data, by setting the
//once-dereferenced value
*pointer = working_ptr;
return ERROR_NONE;
}
int main (int argc, char *argv[])
{
int an_int;
void *some_data;
assign_int(&an_int);
//an_int is now either 5 or 38
dynamically_assign_value_to_pointer(&some_data);
//some_data now points to either an integer OR a my_struct instance. You will need
//some way to track this, otherwise the data is useless.
//If you get this wrong, the data will be interpreted as the wrong type, and the
//severity of the issue depends what you do with it.
//For instance, if you KNOW FOR SURE that the pointer contains the int, you could
//print it by:
printf("%d", *((int *) some_data));
//And because it is dynamically allocated, you MUST free it.
free(some_data);
return 0;
}
In practice, this is useful for queues, for instance, so you can write a generic queue function and then have different queues for different data types. This is partial code, so won't compile and is a bad idea in this limited case, when a type-safe alternative would be trivial to design, but hopefully you get the idea:
extern my_queue_type myIntQueue;
extern my_queue_type myStructQueue;
my_error get_from_queue(void *data_out, my_queue_type queue_in);
int main (int argc, char *argv[])
{
//...
int current_int;
struct my_struct current_struct;
get_from_queue(&current_int, myIntQueue);
get_from_queue(&current_struct, myStructQueue);
//...
}
Or if you really want to store lots of different types together, you should at least track the type along with the pointer in a struct, so you can use a 'switch' in order to cast and handle logic appropriately when necessary. Again, partial example so won't compile.
enum my_types
{
MY_INTEGER, MY_DOUBLE, MY_STRUCT
};
struct my_typed_void
{
void *data;
enum my_types datatype;
};
my_error get_dynamic_from_global_queue(struct my_typed_void *data_out)
{
//...
data_out->data = malloc(sizeof int);
*((int *)(data_out->data)) = 33;
data_out->datatype = MY_INTEGER;
//...
}
int main (int argc, char *argv[])
{
struct my_typed_void current;
if(get_dynamic_from_global_queue(&current) == ERROR_NONE)
{
switch(current.datatype)
{
//...
case MY_INTEGER:
printf("%d", *((int *) current.data));
break;
//...
}
free(current.data);
}
return 0;
}

Either return the pointer or pass a pointer to pointer (the function then will change the pointer):
void* f1(void* p)
{
p = whatever(p, conditions);
return p;
}
void f2(void** p)
{
*p = whatever(*p, conditions);
}

void assign_value_to_pointer(int** pointer) {
**pointer = 20;
}
void main() {
void* pointer = NULL;
pointer=malloc(sizeof(int));
*(int *)pointer=10;
assign_value_to_pointer(&pointer);
}

I'm not 100% sure what you are looking for, but could it be something like this:
enum pointer_type{INTEGER, STRUCTURE_1, STRUCTURE_2, INVALID};
int assign_value_to_pointer(void ** ptr)
{
uint8_t cond = getCondition();
switch(cond)
{
case 1:
*ptr = (void*) 10;
return INTEGER;
case 2:
*ptr = (void*) someStructOfType1;
return STRUCTURE_1;
case 3:
*ptr = (void*) someStructOfType2;
return STRUCTURE_2;
default:
*ptr = NULL;
return INVALID;
};
}
void main(void)
{
void * ptr = NULL;
int ptrType = assign_value_to_pointer(&ptr);
switch(ptrType)
{
case INTEGER:
assert(ptr == (void*)10);
break;
case STRUCTURE_1:
assert( ((structType1*) ptr)->thing == something);
break;
case STRUCTURE_2:
assert( ((structType2*) ptr)->something == something);
break;
default:
assert(ptr == NULL);
}
}

You can actually type cast the pointer in main() according to the case (condition) and use. However, in my opinion, you can use a union for this purpose.
Create a union with all possible data types.
typedef union _my_union_type_ {
int intVal;
char* stringVal;
bool boolVal;
SomestructType somestruct;//Assuming you need a structure not structure pointer.
void* voidPtrType;
} my_union_type;
Now in main(), create variable of this union type and pass the address of the union to the function.
main() {
my_union_type my_union;
memset(&my_union, 0x00, sizeof(my_union));
assign_value_to_pointer(&my_union);
if (cond1) {
assert(my_union.intVal == 10);
} else if (cond2) {
assert(strcmp(my_union.stringVal, "foo")); //String comparison can not be done using '=='
} else if (cond3) {
assert(my_union.boolVal == true);
} else if (cond4) {
assert(memcmp(&my_union.somestruct, &somestruct, sizeof(somestruct)); //Assuming structure not structure pointer.
} else if (cond5) {
assert(my_union.voidPtrType == NULL);
} else if (cond5) {
//Check my_union.voidPtrType
}
}
And in assign_value_to_pointer, you can store the required value in union variable.
assign_value_to_pointer(my_union_type* my_union) {
if (cond1) {
my_union->intVal = 10;
} else if (cond2) {
my_union->stringVal = "foo";
} else if (cond3) {
my_union->boolVal = true;
} else if (cond4) {
memcpy(&(my_union->somestruct), &somestruct, sizeof(somestruct));
} else if (cond5) {
my_union->voidPtrType = NULL;
} else if (cond6) {
// unknown type!
my_union->voidPtrType = flexiblearraymember.items[index];
}
}

I would like to use this to implement stuff like passing in a NULL error object to a function, and if there is an error, it sets the pointer of the error to some error code, etc.
From the above quote and from the code in the question, it seems you are looking for a variable that can "hold" different types, i.e. sometimes you want it to be an integer, at other times a float, at other times a string and so on. This is called a variant in some languages but variants doesn't exist in C. (see this https://en.wikipedia.org/wiki/Variant_type for more about variants)
So in C you'll have to code your own variant type. There are several ways to do that. I'll give examples below.
But first a few words on pointers in C because the code in the question seem to reveal a misunderstanding as it assigns values directly to the pointer, e.g. pointer = somestruct; which is illegal.
In C is very important to understand the difference between the "value of a pointer" and the "value of the pointed to object". The first, i.e. value of a pointer, tells where the pointer is pointing, i.e. the value of a pointer is the address of the pointed to object. Assignments to a pointer changes where the pointer is pointing. To change the value of the pointed to object, the pointer must be dereferenced first. Example (pseudo code):
pointer = &some_int; // Make pointer point to some_int
*pointer = 10; // Change the value of the pointed to object, i.e. some_int
// Notice the * in front of pointer - it's the dereference
// that tells you want to operate on the "pointed to object"
pointer = 10; // Change the value of the pointer, i.e. where it points to
// In other words, pointer no longer points to some_int
Now back to the "variant" implementation. As already mentioned there are several ways to code that in C.
From your question it seems that you want to use a void-pointer. It's doable and I'll start by showing an example using void-pointer and after that an example using a union.
It's not clear in your question what cond are so in my examples I'll just assume it's a command line argument and I just added some interpretation in order to have a running example.
The common pattern for the examples is the use of a "tag". That is an extra variable that tells the current type of objects value (aka meta-data). So the general variant data type looks like:
struct my_variant
{
TagType tag; // Tells the current type of the value object
ValueType value; // The actual value. ValueType is a type that allows
// storing different object types, e.g. a void-pointer or a union
}
Example 1 : void-pointer and casts
The example below will use a void-pointer to point to the object containing the real value. A value that sometimes is an integer, sometimes a float or whatever is needed. When working with a void-pointer, it's necessary to cast the void-pointer before dereferencing the pointer (i.e. before accessing the pointed to object). The tag field tells the type of the pointed to object and thereby also how the cast shall be.
#include <stdio.h>
#include <stdlib.h>
// This is the TAG type.
// To keep the example short it only has int and float but more can
// be added using the same pattern
typedef enum
{
INT_ERROR_TYPE,
FLOAT_ERROR_TYPE,
UNKNOWN_ERROR_TYPE,
} error_type_e;
// This is the variant type
typedef struct
{
error_type_e tag; // The tag tells the type of the object pointed to by value_ptr
void* value_ptr; // void pointer to error value
} error_object_t;
// This function evaluates the error and (if needed)
// creates an error object (i.e. the variant) and
// assigns appropriate values of different types
error_object_t* get_error_object(int err)
{
if (err >= 0)
{
// No error
return NULL;
}
// Allocate the variant
error_object_t* result_ptr = malloc(sizeof *result_ptr);
// Set tag value
// Allocate value object
// Set value of value object
if (err > -100) // -99 .. -1 is INT error type
{
result_ptr->tag = INT_ERROR_TYPE;
result_ptr->value_ptr = malloc(sizeof(int));
*(int*)result_ptr->value_ptr = 42;
}
else if (err > -200) // -199 .. -100 is FLOAT error type
{
result_ptr->tag = FLOAT_ERROR_TYPE;
result_ptr->value_ptr = malloc(sizeof(float));
*(float*)result_ptr->value_ptr = 42.42;
}
else
{
result_ptr->tag = UNKNOWN_ERROR_TYPE;
result_ptr->value_ptr = NULL;
}
return result_ptr;
}
int main(int argc, char* argv[])
{
if (argc < 2) {printf("Missing arg\n"); exit(1);}
int err = atoi(argv[1]); // Convert cmd line arg to int
error_object_t* err_ptr = get_error_object(err);
if (err_ptr == NULL)
{
// No error
// ... add "normal" code here - for now just print a message
printf("No error\n");
}
else
{
// Error
// ... add error handler here - for now just print a message
switch(err_ptr->tag)
{
case INT_ERROR_TYPE:
printf("Error type INT, value %d\n", *(int*)err_ptr->value_ptr);
break;
case FLOAT_ERROR_TYPE:
printf("Error type FLOAT, value %f\n", *(float*)err_ptr->value_ptr);
break;
default:
printf("Error type UNKNOWN, no value to print\n");
break;
}
free(err_ptr->value_ptr);
free(err_ptr);
}
return 0;
}
Some examples of running this program:
> ./prog 5
No error
> ./prog -5
Error type INT, value 42
> ./prog -105
Error type FLOAT, value 42.419998
> ./prog -205
Error type UNKNOWN, no value to print
As the example above shows, you can implement a variant type using void-pointer. However, the code requires a lot of casting which makes the code hard to read. In general I'll not recommend this approach unless you have some special requirements that forces the use of void-pointer.
Example 2 : pointer to union
As explained earlier C doesn't have variants as they are known in other languages. However, C has something that is pretty close. That is unions. A union can hold different types at different times - all it misses is a tag. So instead of using a tag and a void-pointer, you can use a tag and a union. The benefit is that 1) casting will not be needed and 2) a malloc is avoided. Example:
#include <stdio.h>
#include <stdlib.h>
typedef enum
{
INT_ERROR_TYPE,
FLOAT_ERROR_TYPE,
UNKNOWN_ERROR_TYPE,
} error_type_e;
// The union that can hold an int or a float as needed
typedef union
{
int n;
float f;
} error_union_t;
typedef struct
{
error_type_e tag; // The tag tells the current union use
error_union_t value; // Union of error values
} error_object_t;
error_object_t* get_error_object(int err)
{
if (err >= 0)
{
// No error
return NULL;
}
error_object_t* result_ptr = malloc(sizeof *result_ptr);
if (err > -100) // -99 .. -1 is INT error type
{
result_ptr->tag = INT_ERROR_TYPE;
result_ptr->value.n = 42;
}
else if (err > -200) // -199 .. -100 is FLOAT error type
{
result_ptr->tag = FLOAT_ERROR_TYPE;
result_ptr->value.f = 42.42;
}
else
{
result_ptr->tag = UNKNOWN_ERROR_TYPE;
}
return result_ptr;
}
int main(int argc, char* argv[])
{
if (argc < 2) {printf("Missing arg\n"); exit(1);}
int err = atoi(argv[1]); // Convert cmd line arg to int
error_object_t* err_ptr = get_error_object(err);
if (err_ptr == NULL)
{
// No error
// ... add "normal" code here - for now just print a message
printf("No error\n");
}
else
{
// Error
// ... add error handler here - for now just print a message
switch(err_ptr->tag)
{
case INT_ERROR_TYPE:
printf("Error type INT, value %d\n", err_ptr->value.n);
break;
case FLOAT_ERROR_TYPE:
printf("Error type FLOAT, value %f\n", err_ptr->value.f);
break;
default:
printf("Error type UNKNOWN, no value to print\n");
break;
}
free(err_ptr);
}
return 0;
}
In my opinion this code is easier to read than the code using void-pointer.
Example 3 : union - no pointer - no malloc
Even if example 2 is better than example 1 there is still dynamic memory allocation in example 2. Dynamic allocation is part of most C programs but it is something that shall be used only when really needed. In other words - objects with automatic storage duration (aka local variables) shall be prefered over dynamic allocated objects when possible.
The example below shows how the dynamic allocation can be avoided.
#include <stdio.h>
#include <stdlib.h>
typedef enum
{
NO_ERROR,
INT_ERROR_TYPE,
FLOAT_ERROR_TYPE,
UNKNOWN_ERROR_TYPE,
} error_type_e;
typedef union
{
int n;
float f;
} error_union_t;
typedef struct
{
error_type_e tag; // The tag tells the current union usevalue_ptr
error_union_t value; // Union of error values
} error_object_t;
error_object_t get_error_object(int err)
{
error_object_t result_obj;
if (err >= 0)
{
// No error
result_obj.tag = NO_ERROR;
}
else if (err > -100) // -99 .. -1 is INT error type
{
result_obj.tag = INT_ERROR_TYPE;
result_obj.value.n = 42;
}
else if (err > -200) // -199 .. -100 is FLOAT error type
{
result_obj.tag = FLOAT_ERROR_TYPE;
result_obj.value.f = 42.42;
}
else
{
result_obj.tag = UNKNOWN_ERROR_TYPE;
}
return result_obj;
}
int main(int argc, char* argv[])
{
if (argc < 2) {printf("Missing arg\n"); exit(1);}
int err = atoi(argv[1]); // Convert cmd line arg to int
error_object_t err_obj = get_error_object(err);
switch(err_obj.tag)
{
case NO_ERROR:
printf("No error\n");
break;
case INT_ERROR_TYPE:
printf("Error type INT, value %d\n", err_obj.value.n);
break;
case FLOAT_ERROR_TYPE:
printf("Error type FLOAT, value %f\n", err_obj.value.f);
break;
default:
printf("Error type UNKNOWN, no value to print\n");
break;
}
return 0;
}
Summary
There are many ways of solving the problem addressed by OP. Three examples have been given in this answer. In my opinion example 3 is the best approach as it avoids dynamic memory allocation and pointers but there may be situations where example 1 or 2 is better.

You are not far from success, you just miss an asterisk to dereference the argument:
void assign_value_to_pointer(void* pointer) {
if (cond1) {
*pointer = 10; // note the asterisk
...
}
void main() {
void* pointer = NULL;
assign_value_to_pointer(&pointer);
}
In C language, arguments to functions are always passed by value. If you want the function to modify the argument, you must pass the address of the variable you want to modify. In main(), you are doing that - correct. The called function can write where its argument points to, hence modifying the original variable; to do this, you must dereference the argument.
The compiler should get angry on the assignment, because it does not know how many bytes to write (I'm keeping it simple). So, you have to say what kind of object the pointer points to, like this:
*(int *) pointer = 10;
The typecast you choose is up to you, it depends on the context.
At this point... why not declare differently the function:
void assign_value_to_pointer(int* pointer) {
if (cond1) {
*pointer = 10; // note the asterisk
}
Now the typecast is no more necessary because the compiler knows the kind of object (again I am keeping it simple - void is quite special).
******* EDIT after comments
Well, I am not a guru in C language and, besides, I wanted to keep a low profile to better help the OP.
For simple cases, the right declaration is naive. The typecast can be more flexible because the function can have several assignment statements to choose from depending on context. Lastly, if the function is passed the pointer and some other parameter, everything is possible, including using memcpy(). But this last solution opens up a world...
To reply to Lance (comment below): well, I think that there is no way to do an assignment if you don't know the type of object you are writing to. It seems a contracdition to me...

Related

Dynamically increasing C string's size

I'm currently creating a program that captures user's keypresses and stores them in a string. I wanted the string that stores the keypresses to be dynamic, but i came across a problem.
My current code looks something like this:
#include <stdio.h>
#include <stdlib.h>
typedef struct Foo {
const char* str;
int size;
} Foo;
int main(void)
{
int i;
Foo foo;
foo.str = NULL;
foo.size = 0;
for (;;) {
for (i = 8; i <= 190; i++) {
if (GetAsyncKeyState(i) == -32767) { // if key is pressed
foo.str = (char*)realloc(foo.str, (foo.size + 1) * sizeof(char)); // Access violation reading location xxx
sprintf(foo.str, "%s%c", foo.str, (char)i);
foo.size++;
}
}
}
return 0;
}
Any help would be appreciated, as I don't have any ideas anymore. :(
Should I maybe also allocate the Foo object dynamically?
First, in order to handle things nicely, you need to define
typedef struct Foo {
char* str;
int size
} Foo;
Otherwise, Foo is really annoying to mutate properly - you invoke undefined behaviour by modifying foo->str after the realloc call in any way.
The seg fault is actually caused by sprintf(foo.str, "%s%c", foo.str, (char)i);, not the call to realloc. foo.str is, in general, not null-terminated.
In fact, you're duplicating work by calling sprintf at all. realloc already copies all the characters previously in f.str, so all you have to do is add a single character via
f.str[size] = (char) i;
Edit to respond to comment:
If we wanted to append to strings (or rather, two Foos) together, we could do that as follows:
void appendFoos(Foo* const first, const Foo* const second) {
first->str = realloc(first->str, (first->size + second->size) * (sizeof(char)));
memcpy(first->str + first->size, second->str, second->size);
first->size += second->size;
}
The appendFoos function modifies first by appending second onto it.
Throughout this code, we leave Foos as non-null terminated. However, to convert to a string, you must add a final null character after reading all other characters.
const char *str - you declare the pointer to const char. You cant write to the referenced object as it invokes UB
You use sprintf just to add the char. It makes no sense.
You do not need a pointer in the structure.
You need to set compiler options to compile **as C language" not C++
I would do it a bit different way:
typedef struct Foo {
size_t size;
char str[1];
} Foo;
Foo *addCharToFoo(Foo *f, char ch);
{
if(f)
{
f = realloc(f, sizeof(*f) + f -> size);
}
else
{
f = realloc(f, sizeof(*f) + 1);
if(f) f-> size = 0
}
if(f) //check if realloc did not fail
{
f -> str[f -> size++] = ch;
f -> str[f -> size] = 0;
}
return f;
}
and in the main
int main(void)
{
int i;
Foo *foo = NULL, *tmp;
for (;;)
{
for (i = 8; i <= 190; i++)
{
if (GetAsyncKeyState(i) == -32767) { // if key is pressed
if((tmp = addCharToFoo(f, i))
{
foo = tmp;
}
else
/* do something - realloc failed*/
}
}
}
return 0;
}
sprintf(foo.str, "%s%c", foo.str, (char)i); is ill-formed: the first argument cannot be const char *. You should see a compiler error message.
After fixing this (make str be char *), then the behaviour is undefined because the source memory read by the %s overlaps with the destination.
Instead you would need to use some other method to append the character that doesn't involve overlapping read and writes (e.g. use the [ ] operator to write the character and don't forget about null termination).

Is there a way to define a "common" structure for multiple parameter numbers and types

I would like to create a common structure that I may use to pass parameters of multiple lengths and types into different functions.
As an example, consider the following structure:
typedef struct _list_t {
int ID;
char *fmt;
int nparams;
} list_t;
list_t infoList[100]; //this will be pre-populated with the operations my app offers
typedef struct _common {
int ID;
char *params;
} common;
A variable size function is used to pass in the parameters given the format is already populated:
int Vfunc(common * c, ...) {
va_list args;
va_start(args, c);
//code to search for ID in infoList and fetch its fmt
char params_buff[100]; //max params is 100
vsprintf(str_params, fmt, args);
va_end(args);
c->params = (char *)malloc(sizeof(char)*(strlen(params_buff)+1));
strncpy(c->params, params_buff, strlen(params_buff)+1);
}
int execute(common * c) {
if (c->ID == 1) { //add 2 numbers
int x, y; // i expect 2 numbers
//code to find ID in infoList and fetch its fmt
sscanf(c->params, fmt, &x, &y);
return (x + y);
}
else if (c->ID == 2) {
//do another operation, i expect an unsigned char array?
}
}
Main program will look somewhat like this:
int main()
{
common c;
c.ID = 1;
Vfunc(&c, 12, 2);
execute(&c);
return 0;
}
Now I can pass in the structure to any function, which will deal with the parameters appropriately. However I do not see a way to have unsigned char[] as one of the parameters since unsigned char arrays do not have a "format". The format of a char[] would be %s. Basically I want to pass in some raw data through this structure.
Is there a way to do this or a better implementation to fulfill the goal?
EDIT:
It seems that the questions goal is unclear. Say my application can provide arithmetic operations (like a calculator). Say a user of my application wants to add 2 numbers. All I want them to do is fill in this common structure, then pass it into lets say a function to get it executed. All the ID's of the operations will be known from lets say a manual, so the user will know how many parameters they can pass and what ID does what. As the app owner i will be filling infoList with the ID's I offer.
So this is just to give you an idea of what I mean by a "common structure". It can be implemented in other ways too, maybe you have a better way. But my goal is for the implementation to be able to pass in an unsigned char array. Can I do that?
As I understand your question, you want to save all argument values in a text string so that the values can be reconstructed later using sscanf. Further, you want to be able to handle array-of-number, e.g. an array of unsigned char.
And you ask:
Is there a way to do this
For your idea to work, it's required that sscanf can parse (aka match) the type of data that you want to use in your program. And - as you write in the question - scanf can't parse arrays-of-numbers. So the answer is:
No, it can't be done with standard functions.
So if you want to be able to handle arrays-of-number, you'll have to write your own scan-function. This includes
selection of a conversion specifier to tell the code to scan for an array (e.g. %b),
select a text-format for the array (e.g. "{1, 2, 3}")
a way to store the array-data and the size, e.g. struct {unsiged char* p; size_t nb_elements;}.
Further, you'll have the same problem with vsprintf. Again you need to write your own function.
EDIT
One alternative (that I don't really like myself) is to store pointer values. That is - instead of storing the array values in the string params you can store a pointer to the array.
The upside of that approach is that you can use the standard functions.
The downside is that the caller must ensure that the array exists until execute has been called.
In other words:
unsigned char auc[] = {1, 2, 3};
Vfunc(&c, auc);
execute(&c);
would be fine but
Vfunc(&c, (unsigned char[]){1, 2, 3});
execute(&c);
would compile but fail at run time.
And - as always with arrays in C - you may need an extra argument for the number of array elements.
Example code for this "save as pointer" approach could be:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
typedef struct _common {
int ID;
char *params;
} common;
void Vfunc(common * c, ...) {
va_list args;
va_start(args, c);
//code to search for ID in infoList and fetch its fmt
// For this example just use a fixed fmt
char fmt[] ="%p %zu";
char params_buff[100]; //max params is 100
vsprintf(params_buff, fmt, args);
va_end(args);
c->params = (char *)malloc(sizeof(char)*(strlen(params_buff)+1));
strncpy(c->params, params_buff, strlen(params_buff)+1);
}
int execute(common * c)
{
if (c->ID == 1) {
// expect pointer and number of array elements
unsigned char* a;
size_t nbe;
//code to find ID in infoList and fetch its fmt
// For this example just use a fixed fmt
char fmt[] ="%p %zu";
if (sscanf(c->params, fmt, &a, &nbe) != 2) exit(1);
// Calculate average
int sum = 0;
for (size_t i = 0; i < nbe; ++i) sum += a[i];
return sum;
}
return 0;
}
int main(void)
{
common c;
c.ID = 1;
unsigned char auc[] = {1, 2, 3, 4, 5, 6};
Vfunc(&c, auc, sizeof auc / sizeof auc[0]);
printf("The saved params is \"%s\"\n", c.params);
printf("Sum of array elements are %d\n", execute(&c));
return 0;
}
Possible Output
The saved params is "0xffffcc0a 6"
Sum of array elements are 21
Notice that it's not the array data that is saved but a pointer value.
I have read the problem once again, and find out that it's much simpler than you've described.
According to your statement, you already know about the type and order of data retrieval in execute() function. This make this problem much easier.
I must say, this problem is a bit difficult to solve in c, cause c can't resolve type at runtime or dynamically cast type at runtime. c must know all the types before hand i.e. at compile time.
Now, that said, c provides a way to handle variable length arguments. And that's a advantage.
So, what we've to do is:
cache all arguments from variable length arguments i.e. va_list.
and, provide a way to retrieve provided arguments from that cache.
At first, I am going to show you how to retrieve elements from cache if you know the type. We'll do it using a macro. I've named it sarah_next(). Well, after all, I've to write it because of you. You can name it as you want. It's definition is given below:
#define sarah_next(cache, type) \
(((cache) = (cache) + sizeof(type)), \
*((type*) (char *) ((cache) - sizeof(type))))
So, in simple words, sarah_next() retrieve the next element from cache and cast it to type.
Now, let's discuss the first problem, where we've to cache all arguments from va_list. You can do it easily by writing as follows:
void *cache = malloc(sizeof(char) * cacheSize);
// itr is an iterator, which iterates over cache
char *itr = (char *)cache;
// now, you can do
*(type *)itr = va_arg(buf, type);
// and then
itr += sizeof(type);
Another, point I would like to discuss is, I've used type hint to determine cache size. For that I've used a function getSize(). You would understand if you just look at it(also note: this gives you the ability to use your own custom type):
// getSize() is a function that returns type size based on type hint
size_t getSize(char type) {
if(type == 's') {
return sizeof(char *);
}
if(type == 'c') {
return sizeof(char);
}
if(type == 'i') {
return sizeof(int);
}
if(type == 'u') { // 'u' represents 'unsigned char'
return sizeof(unsigned char);
}
if(type == 'x') { // let's, say 'x' represents 'unsigned char *'
return sizeof(unsigned char *);
}
// you can add your own custom type here
// also note: you can easily use 'unsigned char'
// use something like 'u' to represent 'unsigned char'
// and you're done
// if type is not recognized, then
printf("error: unknown type while trying to retrieve type size\n");
exit(1);
}
Ok, I guess, the ideas are complete. Before moving on try to grasp the ideas properly.
Now, let me provide the full source code:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
// note: it is the most fundamental part of this solution
// 'sarah_next' is a macro, that
// returns *(type *)buf means a value of type "type", and also
// increments 'buf' by 'sizeof(type)', so that
// it may target next element
// 'sarah_next' is used to retrieve data from task cache
// I've named it after you, you may choose to name it as you wish
#define sarah_next(cache, type) \
(((cache) = (cache) + sizeof(type)), \
*((type*) (char *) ((cache) - sizeof(type))))
// defining pool size for task pool
#define POOL_SIZE 1024
// notice: getSize() has been updated to support unsigned char and unsigned char *
// getSize() is a function that returns type size based on type hint
size_t getSize(char type) {
if(type == 's') {
return sizeof(char *);
}
if(type == 'c') {
return sizeof(char);
}
if(type == 'i') {
return sizeof(int);
}
if(type == 'u') { // 'u' represents 'unsigned char'
return sizeof(unsigned char);
}
if(type == 'x') { // let's, say 'x' represents 'unsigned char *'
return sizeof(unsigned char *);
}
// you can add your own custom type here
// also note: you can easily use 'unsigned char'
// use something like 'u' to represent 'unsigned char'
// and you're done
// if type is not recognized, then
printf("error: unknown type while trying to retrieve type size\n");
exit(1);
}
typedef struct __task {
int id;
void *cache;
} Task;
// notice: constructTask has been updated to support unsigned char and unsigned char *
// note: here, types contains type hint
Task *constructTask(int id, char *types, ...) {
// determine the size of task cache
int cacheSize = 0;
for(int i=0; types[i]; i++) {
cacheSize += getSize(types[i]);
}
// allocate memory for task cache
void *cache = malloc(sizeof(char) * cacheSize);
va_list buf;
va_start(buf, types);
// itr is an iterator, which iterates over cache
char *itr = (char *)cache;
for(int i=0; types[i]; i++) {
if(types[i] == 's') {
*(char **)itr = va_arg(buf, char *);
} else if(types[i] == 'x') { // added support for 'unsigned char *'
*(unsigned char **)itr = va_arg(buf, unsigned char *);
} else if(types[i] == 'c') {
// notice: i used 'int' not 'char'
// cause: compiler-warning: 'char' is promoted to 'int' when passed through '...'
// also note: this promotion helps with 'unsigned char'
*(char *)itr = (char)va_arg(buf, int); // so cast it to char
} else if(types[i] == 'u') { // added support 'unsigned char'
// notice: i used 'int' not 'unsigned char'
// cause: compiler-warning: 'unsigned char' is promoted to 'int' when passed through '...'
// also note: this promotion helps with 'unsigned char'
*(unsigned char *)itr = (unsigned char)va_arg(buf, int); // so cast it to unsigned char
} else if(types[i] == 'i') {
*(int *)itr = va_arg(buf, int);
}
// it won't come to else, cause getSize() would
// caught the type error first and exit the program
itr += getSize(types[i]);
}
va_end(buf);
// now, construct task
Task *task = malloc(sizeof(Task));
task->id = id;
task->cache = cache;
// and return it
return task;
}
// destroyTask is a function that frees memory of task cache and task
void destroyTask(Task *task) {
free(task->cache);
free(task);
}
// notice: that 'task->id == 4' processing part
// it is equivalant to your 'execute()' function
int taskProcessor(Task *task) {
// define ret i.e. return value
int ret = 999; // by default it is some code value, that says error
// note: you already know, what type is required in a task
if(task->id == 1) {
// note: see usage of 'sarah_next()'
int x = sarah_next(task->cache, int);
int y = sarah_next(task->cache, int);
ret = x + y;
} else if(task->id == 2) {
char *name = sarah_next(task->cache, char *);
if(strcmp(name, "sarah") == 0) {
ret = 0; // first name
} else if (strcmp(name, "cartenz") == 0) {
ret = 1; // last name
} else {
ret = -1; // name not matched
}
} else if(task->id == 3) {
int x = sarah_next(task->cache, int);
char *name = sarah_next(task->cache, char *);
int y = sarah_next(task->cache, int);
printf("%d %s %d\n", x, name, y); // notice: we've been able to retrieve
// both string(i.e. char *) and int
// you can also see for ch and int, but i can assure you, it works
ret = x + y;
} else if(task->id == 4) { // working with 'unsigned char *'
int a = sarah_next(task->cache, int);
unsigned char *x = sarah_next(task->cache, unsigned char *); // cast to unsigned char *
// char *x = sarah_next(task->cache, char *); // this won't work, would give wrong result
int b = sarah_next(task->cache, int);
printf("working with 'unsigned char *':");
for(int i=0; x[i]; i++) {
printf(" %d", x[i]); // checking if proper value is returned, that's why using 'integer'
}
printf("\n");
ret = a + b;
} else {
printf("task id not recognized\n");
}
return ret;
}
int main() {
Task *taskPool[POOL_SIZE];
int taskCnt = 0;
taskPool[taskCnt++] = constructTask(1, "ii", 20, 30); // it would return 50
taskPool[taskCnt++] = constructTask(1, "ii", 50, 70); // it would return 120
taskPool[taskCnt++] = constructTask(2, "s", "sarah"); // it would return 0
taskPool[taskCnt++] = constructTask(2, "s", "cartenz"); // it would return 1
taskPool[taskCnt++] = constructTask(2, "s", "reyad"); // it would return -1
taskPool[taskCnt++] = constructTask(3, "isi", 40, "sarah", 60); // it would print [40 sarah 60] and return 100
// notice: I've added an exmaple to showcase the use of unsigned char *
// also notice: i'm using value greater than 127, cause
// in most compiler(those treat char as signed) char supports only upto 127
unsigned char x[] = {231, 245, 120, 255, 0}; // 0 is for passing 'NULL CHAR' at the end of string
// 'x' is used to represent 'unsigned char *'
taskPool[taskCnt++] = constructTask(4, "ixi", 33, x, 789); // it would print ['working with unsigned char *': 231 245 120 255] and return 822
// note: if you used 'char *' cast to retrieve from 'cache'(using a compiler which treats char as signed), then
// it would print [-25 -11 120 -1] instead of [231 245 120 255]
// i guess, that makes it clear that you can perfectly use 'unsigned char *'
for(int i=0; i<taskCnt; i++) {
printf("task(%d): %d\n", i+1, taskProcessor(taskPool[i]));
printf("\n");
}
// at last destroy all tasks
for(int i=0; i<taskCnt; i++) {
destroyTask(taskPool[i]);
}
return 0;
}
The output is:
// notice the updated output
task(1): 50
task(2): 120
task(3): 0
task(4): 1
task(5): -1
40 sarah 60
task(6): 100
working with 'unsigned char *': 231 245 120 255
task(7): 822
So, you may be wondering, what advantage it may create over your given solution. Well, first of all you don't have to use %s %d etc. do determine format, which is not easy to change or create for each task and you've write a lot may be(for each task, you may have to write different fmt), and you don't have use vsprintf etc... which only deals with builtin types.
And the second and great point is, you can use your own custom type. Declare a struct type of your own and you can use. And it is also easy to add new type.
update:
I've forgot to mention another advantage, you can also use unsigned char with it. see, the updated getSize() function. you can use 'u' symbol for unsigned char, and as unsigned char is promoted to int, you can just cast it to (unsigned char) and done...
update-2(support for unsigned char *):
I have updated the code to support unsigned char and unsigned char *. To support new type, the functions, those you need to update, are getSize() and constructTask(). Compare the previous code and the newly updated code...you'll understand how to add new types(you can also add custom types of your own).
Also, take a look at task->id == 4 part in taskProcessor() function. I've added this to showcase the usage of unsigned char *. Hope this clears everything.
If you've any question, then ask me in the comment...
I think what you want from your description is likely a union of structs, with the 1st member of the union being an enumerator that defines the type of the structure in use, which is how polymorphism is often accomplished in C. Look at the X11 headers for a giant example of Xevents
A trivial example:
//define our types
typedef enum {
chicken,
cow,
no_animals_defined
} animal;
typedef struct {
animal species;
int foo;
char bar[20];
} s_chicken;
typedef struct {
animal species;
double foo;
double chew;
char bar[20];
} s_cow;
typedef union {
animal species; // we need this so the receiving function can identify the type.
s_chicken chicken ;
s_cow cow ;
} s_any_species;
now, this struct may be passed to a function and take on either identity. A receiving function of a type s_any_species may do to de-reference.
void myfunc (s_any_species any_species)
{
if (any_species.species == chicken)
any_species.chicken.foo=1 ;
}
Arrays of function pointers are preferable to long if else sequences here, but either will work
I take you to be asking about conveying a sequence of objects a varying type to a function. As a special detail, you want the function to receive only one actual argument, but this is not particularly significant because it is always possible to convert a function that takes multiple arguments into another that takes only one by wrapping the multiple parameters in a corresponding structure. I furthermore take the example Vfunc() code's usage of vsprintf() to be an implementation detail, as opposed to an essential component of the required solution.
In that case, notwithstanding my grave doubts about the usefulness of what you seem to want, as a C programming exercise it does not appear to be that difficult. The basic idea you seem to be looking for is called a tagged union. It goes by other names, too, but that one matches up well with the relevant C-language concepts and keywords. The central idea is that you define a type that can hold objects of various other types, one at a time, and that carries an additional member that identifies which type each instance currently holds.
For example:
enum tag { TAG_INT, TAG_DOUBLE, TAG_CHAR_PTR };
union tagged {
struct {
enum tag tag;
// no data -- this explicitly gives generic access to the tag
} as_any;
struct {
enum tag tag;
int data;
} as_int;
struct {
enum tag tag;
double data;
} as_double;
struct {
enum tag tag;
char *data;
} as_char_ptr;
// etc.
};
You could then combine that with a simple list wrapper:
struct arg_list {
unsigned num;
union tagged *args;
};
Then, given a function such as this:
int foo(char *s, double d) {
char[16] buffer;
sprintf(buffer, "%15.7e", d);
return strcmp(s, buffer);
}
You might then wrap it like so:
union tagged foo_wrapper(struct arg_list args) {
// ... validate argument count and types ...
return (union tagged) { .as_int = {
.tag = TAG_INT, .data = foo(args[0].as_char_ptr.data, args[1].as_double.data)
} };
}
and call the wrapper like so:
void demo_foo_wrapper() {
union tagged arg_unions[2] = {
{ .as_char_ptr = { .tag = TAG_CHAR_PTR, .data = "0.0000000e+00" },
{ .as_double = { .tag = TAG_DOUBLE, .data = 0.0 }
};
union tagged result = foo_wrapper((struct arg_list) { .num = 2, .args = arg_unions});
printf("result: %d\n", result.as_int.data);
}
Update:
I suggested tagged unions because the tags correspond to the field directives in the format strings described in the question, but if they aren't useful to you in practice then they are not an essential detail of this approach. If the called functions will work on the assumption that the caller has packed arguments correctly, and you have no other use for tagging the data with their types, then you can substitute a simpler, plain union for a tagged union:
union varying {
int as_int;
double as_double;
char *as_char_ptr;
// etc.
};
struct arg_list {
unsigned num;
union varying *args;
};
union varying foo_wrapper(struct arg_list args) {
return (union vaying) { .as_int = foo(args[0].as_char_ptr, args[1].as_double) };
}
void demo_foo_wrapper() {
union varying arg_unions[2] = {
.as_char_ptr = "0.0000000e+00",
.as_double = 0.0
};
union varying result = foo_wrapper((struct arg_list) { .num = 2, .args = arg_unions});
printf("result: %d\n", result.as_int);
}

Passing pointer to pointer for reallocation in function

I'm a beginner C programmer and have issues implementing an (ordered) dynamic array of structs.
Before adding an element to the array, I want to check if it is full and double it's size in that case:
void insert_translation(dict_entry **dict, char *word, char *translation){
if( dictionary_entries == dictionary_size ){
dict_entry *temp_dict;
temp_dict = realloc(&dict, (dictionary_size *= 2) * sizeof(dict_entry) );
// printf("Increased dict size to %d\n", dictionary_size);
// if(temp_dict == NULL){
// fprintf(stderr, "Out of memory during realloc()!\n");
// /*free(dict);
// exit(EXIT_OUT_OF_MEMORY);*/
// }
//free(dict);
//*dict = temp_dict;
}
dictionary_entries++;
printf("Inserted %s into dict - %d of %d filled.\n", word, dictionary_entries, dictionary_size);
}
I call the function from the main function like this:
dictionary_size = 2; //number of initial key-value pairs (translations)
dictionary_entries = 0;
dict_entry *dictionary = malloc(dictionary_size * sizeof(dict_entry));
[...]
insert_translation(&dictionary, "bla", "blub");
In my understanding, dictionary is a pointer to a space in memory. &dictionary is a pointer to the pointer, which I pass to the function. In the function, dict is said pointer to pointer, so &dict should be the pointer to the area in memory? However, when I try to compile, I get the following error message:
pointer being realloc'd was not allocated
Edit
I expanded the code sample to show more of the code in the main function.
The problem is in this statement
temp_dict = realloc(&dict, (dictionary_size *= 2) * sizeof(dict_entry) );
The parameter dict has the type
dict_entry **dict
in the statement that reallocs the memory you have to use the value of the pointer *dic but you are uisng an expression &dict that has the type dict_entry ***.
Compare the type of the left side of the assignment
ict_entry *temp_dict
with the type of the reallocated pointer. They should be the same (except in C one of them can have the type void *)
So you need to write
temp_dict = realloc(*dict, (dictionary_size *= 2) * sizeof(dict_entry) );
^^^^^
In C arguments are passed by value. If you want to change the original value of an argument you should to pass it by reference through a pointer to the argument. In the function you need to dereference the pointer that to change the object pointed to by the pointer.
&dict -> *dict. You can simplify the code by using a return type, to avoid such bugs:
dict_entry* insert_translation(dict_entry* dict, char *word, char *translation)
{
...
if( dictionary_entries == dictionary_size )
{
dictionary_size *= 2;
dict_entry *tmp = realloc(dict, sizeof(dict_entry[dictionary_size]));
if(tmp == NULL)
{
// error handling, free(dict) etc
}
else
{
dict = tmp;
}
}
...
return dict;
}

Pass local variable of a function back to it's parameter

I'm wanting to pass a local variable within a function, back through it's pointer parameter (not returned).
My assignment uses a stack data structure, and one criteria that must be used is the Pop() function must have a pointer parameter that is used to return the top-most item on the stack. I have used this before. My program became more complex with a data struct, I started getting either segmentation faults, or the data not being saved after the function's frame popped.
// Definitions
typedef char * string;
typedef enum { SUCCESS, FAIL } result;
typedef enum { INTEGER, DOUBLE, STRING } item_tag;
// Result Check
static result RESULT;
// Item_Tag
typedef struct {
item_tag tag;
union {
int i;
double d;
string s;
} value;
} item;
// Declarations
int STACK_SIZE = 0;
const int MAX_STACK_SIZE = 1024; // Maximum stack size
item stack[1024];
// Pop
result Pop(item *ip){
item poppedItem;
item * pointerReturn = malloc(sizeof(item));
// Check stack size is not 0
if(STACK_SIZE == 0){
return FAIL;
}
// If stack size is only 1, creates a blank stack
else if(STACK_SIZE == 1){
item emptyItem;
// Initialize
emptyItem.tag = INTEGER;
emptyItem.value.i = 0;
// Check top item's tag
poppedItem = stack[0];
// Store top item data based on tag
switch(stack[0].tag){
case STRING:
poppedItem.value.s = stack[0].value.s;
case DOUBLE:
poppedItem.value.d = stack[0].value.d;
default:
poppedItem.value.i = stack[0].value.i;
}
poppedItem.tag = stack[0].tag;
// Allocate memory for parameter, and have it point to poppedItem
ip = malloc(sizeof(poppedItem));
*ip = poppedItem;
// Store empty stack to top of stack
stack[0] = emptyItem;
// Decrease stack size
STACK_SIZE--;
}
// Grab top Item from stack
else{
// Check top item's tag
poppedItem = stack[0];
// Store top item data based on tag
switch(stack[0].tag){
case STRING:
poppedItem.value.s = stack[0].value.s;
case DOUBLE:
poppedItem.value.d = stack[0].value.d;
default:
poppedItem.value.i = stack[0].value.i;
}
poppedItem.tag = stack[0].tag;
// Allocate memory for parameter, and have it point to poppedItem
ip = malloc(sizeof(poppedItem));
*ip = poppedItem;
// Reshuffle Items in Stack
for(int idx = 0; idx < STACK_SIZE; idx++){
stack[idx] = stack[idx + 1];
}
STACK_SIZE--;
}
return SUCCESS;
}
My knowledge with pointers is alright, and memory location/management. But I can't claim to be an expert by any means. I don't exactly know what happens in the background when you're using the function's own pointer parameter as a means of passing data back.
What is the correct syntax to solve this problem?
How can a parameter pass something back?
Thanks in advance!
EDIT*
Since many people are confused. I'll post some snippets. This is an assignment, so I cannot simply post all of it online as that'd be inappropriate. But I think it's okay to post the function itself and have people analyze it. I'm aware it's a bit messy atm since I've edited it several dozen times to try and figure out the solution. Sorry for the confusion. Keep in mind that not all the code is there. just the function in question, and some of the structure.
The function should receive a pointer to a valid object:
item catcher;
myFunc(&catcher); // Pass a pointer to catcher
and the function should modify the object it received a pointer to:
void myFunc(item *itemPointer)
{
itemPointer->variable = stuff;
// or
*itemPointer = someItem;
}
Update:
You're overcomplicating things immensely – there should be no mallocs when popping, and you're leaking memory all over the place.
(Your knowledge of pointers and memory management is far from "alright". It looks more like a novice's guesswork than knowledge.)
It should be something more like this:
result Pop(item *ip){
if (STACK_SIZE == 0){
return FAIL;
}
else {
*ip = stack[0];
for(int idx = 0; idx < STACK_SIZE; idx++){
stack[idx] = stack[idx + 1];
}
STACK_SIZE--;
}
return SUCCESS;
}
but it's better to push/pop at the far end of the array:
result Pop(item *ip){
if (STACK_SIZE == 0){
return FAIL;
}
else {
*ip = stack[STACK_SIZE-1];
STACK_SIZE--;
}
return SUCCESS;
}
Response to the originally posted code:
typedef struct{
variables
}item;
void myFunc(item *itemPointer){
item newItem;
newItem.variable = stuff;
}
int main(){
item * catcher;
myFunc(catcher);
printf("%s\n", catcher.variable);
}
A few issues.
Your program will not compile. variable has to have a type.
void myFunc(item *itemPointer){
item newItem;
newItem.variable = stuff;
}
stuff is not defined; item *itemPointer is not used.
item * catcher pointer has to point to allocated memory. It is not initialized.
Pass arguments via pointers and modify member of the structure like this:
void myFunc(item *itemPointer, const char *string){
itemPointer->variable = string ;
}
Solution like:
void myFunc(item *itemPointer)
{
itemPointer->variable = stuff;
// or
*itemPointer = someItem;
}
is possible, but it assumes that stuff or someItem is a global variable which is not the best programming practice IMO.
Retrieve value from pointer via -> not . operator.
#include <stdio.h>
#include <stdlib.h>
typedef struct{
char * variable;
}item;
void myFunc(item *itemPointer, const char *string){
itemPointer->variable = string ;
}
int main(){
item * catcher;
char *new_string = "new string";
catcher = malloc(sizeof(item));
myFunc(catcher, new_string);
printf("%s\n", catcher->variable);
free(catcher);
return 0;
}
OUTPUT:
new string

Struct member corrupted after passed but not after passed again

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()).

Resources