"initializer element is not constant" while creating an Init function - c

Right now I am trying to implement an Init function for Pre-configured staff. However as in the following code when I try to implement certain function I receive an error initializer element is not constant. I have read many questions with same error however I couldn't relate one to my case.
The code is as follows:
#define CURR_CONFIG_X 4
#define CURR_CONFIG_Y 4
#define CURR_CONFIG_Z 4
typedef struct {
bool *tblX;
bool *tblY;
bool *tblZ;
} indicesInUse_t;
typedef struct {
tblPreCfgs_t *tblPreCfgs;
indicesInUse_t *tblEntryIndicesInUse;
} tblMgmt_t;
indicesInUse_t cfgIndicesInUse(indicesInUse_t *currIndicesInUse); //error takes place in this line
static indicesInUse_t currTblIndicesInUse = cfgIndicesInUse(&currTblIndicesInUse);
static tblMgmt_t flowTbleMgmt = {
.tblEntryIndicesInUse = &currTblEntryIndicesInUse,
};
indicesInUse_t cfgIndicesInUse(indicesInUse_t *currIndicesInUse) {
for (uint16_t index = 0; index < CURR_CONFIG_X; index++) {
currIndicesInUse->tblX[index] = true;
}
for (uint16_t index = 0; index < CURR_CONFIG_Y; index++) {
currIndicesInUse->tblYindex] = true;
}
for (uint16_t index = 0; index < CURR_CONFIG_Z; index++) {
currIndicesInUse->tblZ[index] = true;
}
return *currIndicesInUse;
}

Here's an instance of where you will get the error:
static indicesInUse_t currTblIndicesInUse = cfgIndicesInUse(&currTblIndicesInUse);
Here currTblIndicesInUse is a static variable, so its initializer must be a constant expression. That means it cannot contain dynamically executed code, such as a function call.
There are two ways this can be solved. One is to change the initializer so that it's a constant expression. The other is to remove the initializer, and instead initialize the variable with an assignment statement (inside a function). You would then call that function to initialize it.
For example, the simplest constant initializer would be something like:
static indicesInUse_t currTblIndicesInUse = {NULL, NULL, NULL};
The NULL values could also be the addresses of static bool variables, or bool arrays.
To initialize it dynamically, you'd simply call a function, passing it the address of the struct. The function would then simply set the fields of the structure, e.g.
s_ptr->tblX = ptr_x;
s_ptr->tblY = ptr_y;
s_ptr->tblZ = ptr_z;
You would need to fill in the specifics yourself, depending on what you want to achieve.
Note that in the original posted code, even if the dynamic initializer were allowed, it still wouldn't work because space is never allocated
for the pointer variables. It might be helpful to read a tutorial on how pointers work.

Related

Declare dynamically sized array in global scope

Not using C that often, I came across a possibly simple problem. I have several functions, that need access to a global array-variable g. But the actual size of this variable has to be defined in an init()-function. The size depends on some other stuff, so g has to be declared somehow with a dynamic size. I read about malloc and other functions, but I am not sure how to use them properly.
Example:
double g[dynamic]; // size is not known yet
int n;
void init()
{
// calculate "n" for array size
n = ...
// declare and initialze g with a size "n"
}
void dostuff()
{
for (int i = 0; i < n; i++)
work(g[i]);
}
How should I solve this?
You cannot use an array. You must use a pointer.
double *global_array; // size is not known yet
size_t nglobal_array; // may be helpful to have the size
void init(void)
{
// calculate "nglobal_array" for array size
nglobal_array = 42;
// declare and initialze global_array with a size "nglobal_array"
global_array = malloc(nglobal_array * sizeof *global_array);
if (global_array == NULL) {
fprintf(stderr, "Error allocating resources.\nProgram aborted.\n");
exit(EXIT_FAILURE);
}
}
void dostuff()
{
for (int i = 0; i < nglobal_array; i++)
work(global_array[i]);
}
Don't forget to free(global_array) when you no longer need it.
Complete usage would then be something like this
#include <stdlib.h>
// includes
// declarations & definitions as above
int main(void) {
init();
dostuff();
free(global_array);
}
What you want to achieve is not possible in C.
A global array must have a fixed size at compile, or at least at link time.
You can declare the array without a specified size:
extern double g[];
But it must be defined somewhere with an actual size, computed from a constant expression at the definition place, and the size cannot be determined from the above declaration, so it must be passed some other way to the functions that will use the array: either implicitly, with a special value signifying the end of the array (like '\0' for char strings) or explicitly via a separate variable as you posted. Note however that n and g are very poor name choices for global variables as they are likely to clash with local variable names and convey no meaning to the reader.
If the size is not known until run time, you should define a pointer instead of an array and also define a separate variable with the length of the array that will be allocated by the initialization function.
double *g;
size_t g_length;
No. C doesn't do that. Arrays declared in global scope have fixed space allocated for them in your binary(.EXE files on Windows and ELF executables on Linux). If you want an array of dynamic size, you need to dynamically allocate it.
Example is here:
#include <stdlib.h>
#define ARRAY_SIZE 100
typedef char T; //your type here
T* array;
void init() {
array = malloc(sizeof(T) * ARRAY_SIZE); //array filled with garbage values
//array = calloc(ARRAY_SIZE, sizeof(T)); //array filled with 0x00
}
void finish() {
free(array); // DO NOT ACCESS ARRAY AFTER THIS CALL!
}
int main() {
init();
array[6] = 63; //access array as normal
finish();
//array[41] = 23; //will most likely crash due to a segmentation fault, also called an access violation on Windoez
}

Invalid Initializer inside function

I don't know why the below code give invalid Initializer error. Is there something wrong?
void ssd_write(uint8_t data){
uint8_t txBuffer[1] = data; <--- error
i2cTransaction.slaveAddress = 0x78;
i2cTransaction.writeBuf = txBuffer;
i2cTransaction.writeCount = 1;
i2cTransaction.readBuf = NULL;
i2cTransaction.readCount = 0;
I2C_transfer(i2c, &i2cTransaction);
I2C_close(i2c);
}
It should be
uint8_t txBuffer[1] = {data};
Yoou are declaring an array of 1 element and initializing it. You should be aware that in this case you are assigning to writeBuf the decayed pointer pointing to the array's first element.
Otherwise you are simply doing an invalid operation by trying to assign the variable to the declared array.
Or more simply you might wanted (Because it is illogical to have an array to store just a single value - you can but that's hardly the thing we do)
uint8_t txBuffer = data;
After you do this, you might want to do i2cTransaction.writeBuf = &txBuffer; if it expects a uint8_t*.

Run-Time Check Failure #2 - Stack around the variable 'obj' was corrupted

I am getting Run-Time Check Failure #2 - Stack around the variable 'obj' was corrupted error when I run the following code. I know this is failing because of overwriting the bounds of 'obj' causing corrupting the stack. So how to prevent buffer overrun here.
typedef struct _INFO {
int Count;
} Info, *InfoPtr;
#define MAX_COUNT 10
//void fn(Info(*obj)[MAX_COUNT])
void fn(Info (*obj)[MAX_COUNT])
{
for (int i = 0; i < 2; i++)
{
obj[i]->Count = i;
}
}
int main()
{
Info obj[MAX_COUNT];
fn(&obj);
return 1;
}
With Info (*obj)[MAX_COUNT] you say that obj is a pointer to an array of MAX_COUNT objects of type Info.
But then you use it like obj[i]->Count = i which treats obj as an array of pointers to Info objects. I.e. Info *obj][]. Not the same thing. And that leads to undefined behavior.
The solution is quite simple, don't pass a pointer to the array as argument, and treat it as an array of objects and not pointers to objects.
I.e.
typedef struct Info {
int Count;
} Info;
#define MAX_COUNT 10
void fn(Info *obj, const size_t elems)
{
for (size_t i = 0; i < elems; i++)
{
obj[i].Count = i;
}
}
int main()
{
Info obj[MAX_COUNT];
fn(obj, MAX_COUNT);
}
The changes are most notably the fn function declaration, which takes a pointer to Info. That is because arrays naturally decays to pointers to their first element. I also added an argument to hold the number of elements in the array, so the function knows it. That makes the function more general and you can pass it different arrays of different sizes.
I also changed to main function to not return anything at all. Since the C99 standard a main function without an explicit return will implicitly get a return 0 by the compiler. And returning 0 from the main function is usually seen as "okay" or "no failure". Returning a non-zero value is considered as a failure or error.
I also changed the name of your structure. Names (C or preprocessor) with a leading underscore followed by an upper-case letter is reserved in all scopes by the compiler and the standard C library. Also, structure tag names live in a separate namespace, so you can have the same name of the structure as a type-name (type-alias, as defined by typedef). I also removed the InfoPtr type-name, using such pointers as type-names obfuscates the code and makes it less readable and maintainable.

What is the purpose of an array with undefined length but only one int element?

I have a headerfile which declares these arrays:
int stVal_On[] = {2};
int stVal_Off[] ={1};
int subVal_On[]={1};
int subMss[]={1};
int subVal_Off[]={0};
The dereferenced arrays are then used in structs that are declared:
Definition of WriteData struct:
/* Write structure used in loop for Read- and Write Tests */
typedef struct WriteData {
char* name; // MMS object name
const VOID* data; // Data to write
const SINT32 localFormat; // SVI type (on server)
const SINT32 dataLength; // length of data to write/read
const SINT32 NbrofElmnts; // Number of elements to write/read
char* description; // SVI type as String (on server)
char* SVI_Name; // SVI address of the SVI mapped on server
UINT32 svi_Length; // length of SVI variable on server (used for readback)
} WriteData;
What is the purpose of this int arr[] = {1}; idiom? Why use arrays at all if only one value is assigned?
Well, one reason I can think of has to do with code organization. If you write your code in a tabular form:
struct {
char const *file_name;
uint16_t flags;
// Other data
} table [] = {
{ .file_name = "/usr/bin/foo", .flags = 0x0 },
};
for (size_t i = 0; i < sizeof(table)/sizeof(table[0]); ++i) {
// do something meaningful with a table row table[i]
}
While it's just an array of 1 now, if you need to add more cases, your code is already written well for it. You'd just need to add another "row' to the table initializer.
All the definitions create arrays with only one element, true. The actual use case may vary.
One commonly used scenario is, this variable can be passed as a function argument and it will be possible to change the content of the array (the only element value) from the called function, which in case of a non-array variable is not possible. This maybe not the very smart way, but still, it's possible and someone chose to use it.
Also, as always, array size determined by the supplied initializer leaves the room for expansion without requiring major code changes.

How can I Return an array from a function without using malloc?

I've been struggling with a simple task in C... (It's been a while.) I need to build a function that creates and resets an array of structs without using any memory allocation functions.
I originally designed it with malloc:
typedef struct {
int ..
int ..
} Branch;
Branch* createBranchList (int N)
{
Branch *List;
Branch reSet = {0}; // a zero'd Branch struct used for the resetting process
int i;
if(!(List=(Branch*)malloc(sizeof(Branch)*N))){
printf("Allocation error");
return NULL;
}
for(i=0; i<N; i++)
List[i] = reSet;
return List;
}
Now how can I do this without using memory allocation? Can I return a reference? I don't think so.
Thanks anyone for helping out.
Safe method (1):
Define a struct with an array member, then return that.
e.g.:
struct MyContainer {
Thing x[42];
};
MyContainer foo(void) {
MyContainer m;
m.x[0] = 5;
m.x[1] = 10;
...
return m;
}
Obviously, this method will not be possible if the array size is not known to the function at compile-time.
Safe method (2):
Have the caller pass in the array as an argument.
e.g.:
foo(Thing *things, int N) {
thing[0] = 5;
thing[1] = 10;
...
}
Unsafe method:
Declare a static local array, and return a pointer to that.
This "works" because a static array is not deallocated when it goes out of scope. But it's unsafe because the array will be overwritten next time you use the function (particularly bad in a multi-threaded scenario).
This method will also not be possible if the array size is not known to the function at compile-time.

Resources