How to initialize already defined flexible length array in C? - arrays

Consider the code:
#include <stdio.h>
int a[] = { 1, 2, 3 };
int b[];
int main() {
b = { 4, 5, 6 };
return 0;
}
This of course is illegal.
main.c:7:9: error: expected expression before '{' token
7 | b = { 4, 5, 6 };
| ^
I need to initialize array b in a function. How to do that?
I know one way, but it's... IDK, really?
#include <stdio.h>
int a[] = { 1, 2, 3 };
int b[3];
int main() {
b[0] = 4;
b[1] = 5;
b[2] = 6;
return 0;
}
Is it the only way of doing that?
EDIT:
It's very hard to explain my intent.
Let's say I define items in code. Right? Is that clear? In code, means - it's static, not dynamic. Not runtime. Not "variable length". Let's say it will be 5 items, right? So why don't I just say 5 and set the fixed length to 5?
The reason for this is, I don't have to write:
int a[5] = { 1, 2, 3, 4, 5 };
```c
but instead I can write
```c
int a[] = { 1, 2, 3, 4, 5 };
That saves me the redundant step of counting my items manually, because the compiler counts the items for me. It also allocates the memory on stack for them for me. No need to call malloc.
And here goes the hard to explain part:
Imagine instead of 1, 2, 3, 4 I have structures. They are not numbered, they contain various data types.
Imagine, that later in time I add an additional item to my array, because it will become necessary at a certain point of the project development. To be absolutely clear: this is not by any means dynamic. I will never need a single item more during the runtime. It will be added to the code and committed to Git. And it will stay there, maybe to the end of the program's life.
Imagine I add the item, but I forget to update the items count. It's a super common bug.
The whole point for me is to learn, whether a syntax in C exists allowing to omit the item count by initializing array inside a function. Now I suspect - it is not possible. I can either make such initialization when defining a variable, but not when assigning to the variable, even if it's the only assignment made to that variable.
I'd avoid to allocate more bytes than necessary, also performing more operations than necessary because it's for embedded and I really aim to cut that kind of costs. I also learn how to do the things the correct way, even if I technically could waste some resources.
Additional problem with my real code is some data for the items is not available before a function is called.
So my temporary solution is just to specify the array length. And then remember to update it when I add or remove items DURING DEVELOPMENT. That should work. If it's the correct way of doing that, than it's fine and I'm done. If not, I'd be happy to learn how to do it a better way.

The proper term is variable length array. This is an array whose size is determined by a non-constant expression. Its size is set at execution time when program execution reaches the definition of the array. (“Flexible” is used in the term flexible array member, which is an array that is the last member of a structure and that adapts to the memory allocated for the structure.)
The size of a variable length array must be given where the array is defined, as with int b[n];. You cannot leave the size incomplete, as with int b[];, and specify it later.
C has no grammar for assigning directly to an array. You can assign values to individual elements, and a method for specifying values in aggregate is to use memcpy to copy them from another array, which can be a compound literal:
#include <stdio.h>
#include <string.h>
int main(void)
{
int n = 3;
int b[n];
memcpy(b, (int []) { 4, 5, 6 }, sizeof b);
for (int i = 0; i < 3; ++i)
printf("b[%d] = %d.\n", i, b[i]);
}

The first thing that's wrong is
int b[];
This makes no sense. gcc treats this as the following
int b[1];
This is most definitely wrong. You want
int *b;
Cloning a would be done as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
size_t size = sizeof( a );
b = malloc( size );
if ( !b ) {
perror( "malloc" );
exit( 1 );
}
memcpy( b, a, size );
Don't forget to free( b );.

Imagine I add the item, but I forget to update the items count.
I think what you're getting at is that you need the size of the array, but you don't want to hardcode it.
No problem. Use this:
int a[] = { 5, 6, 7 };
size_t n = sizeof( a ) / sizeof( *a );
Then you can do stuff like this:
for ( size_t i = 0; i < n ; ++i )
do_this( a[i] );
or
do_that( a, n );
At no point was 3 mentioned, so the code keep working even if you change the initialization of a to the following:
int a[] = { 5, 6, 7, 8 };
The whole point for me is to learn, whether a syntax in C exists allowing to omit the item count by initializing array inside a function
There's nothing special about arrays in functions. Just like outside of functions, you will need to provide a size (int b[...];) or an initializer (int b[] = ...;). Without this, the program wouldn't know how much space to allocate.
But while you say this is the point, it's obviously not. You appear to want to ensure that two arrays are the same size, as you make clear in your following paragraph.
I'd avoid to allocate more bytes than necessary, also performing more operations than necessary because it's for embedded and I really aim to cut that kind of costs. I also learn how to do the things the correct way, even if I technically could waste some resources.
If the array fits on the stack, you can use the following to allocate it on the stack instead of using malloc.
void do_that( int *a, size_t n ) {
int b[n];
...
}
These are called variable length arrays, and it was an addition to C99. (They are variable-length in the sense that every instance of an array created by this code can have a different length. But the created arrays are fixed in size like every C array.)

Imagine I add the item, but I forget to update the items count. It's a super common bug.
The crux of this problem is that you should not code the items count as some constant. Instead use code to calculate to items count value or simply use the size of b[].
#include <assert.h>
#include <string.h>
// Array b exist _someplace_ of some size
void assign_b() {
// Form the initialization list.
same_type_as_b_element b_values[] = { 8, 6, 7, 5, 3, 0, 9 };
// Same size?
static_assert(sizeof b == sizeof b_values), "Mis-matched sizes in b[]");
// Copy to b
memcpy(b, b_values, sizeof b);
}

Related

Error: expected an expression in C with initializing 1d array

I need to initialize array of
array[921600] = {229407, 229407, 229407,...,226851};
elements, I allocated array for 921600 elements and initialized array in function:
setArray(array);
and function looks like this:
Void setArray(Uint8 *array){
array[921600] = {229407, 229407, 229407,...,226851}; //shorten
}
and then I get error in compiler: error: expected an expression.
When I initialize elements one by one it works like this:
Void setArray(Uint8 *array)
{
*(array + 0) = (3);
*(array + 1) = (2);
*(array + 2) = (2);
}
In C, you can initialize an array as you declare it [^1]
For example:
int digits[] = { 3, 1, 4, 1, 5, 9, 2, 6 }; // Initialize an array of 8 numbers
However, after an array is created, you cannot use the same syntax to assign it. Initialization and Assignment are two different operations with different rules.
The closest thing to a bulk assignment I know of is an ugly memcpy using a compound-literal.
memcpy(digits, (int[]){3,1,4,1,5,9,2,6}, sizeof(digits));
Example Code:
#include <stdio.h>
#include <string.h>
int main(void) {
int digits[8];
memcpy(digits, (int[]){3,1,4,1,5,9,2,6}, sizeof(digits));
for(int i=0; i<8; ++i)
{
printf("%d", digits[i]);
}
return 0;
}
But that technique would be extremely difficult (and wasteful) to do on an array of 921600 elements. For a very big array, the data should likely be loaded from a compiled resource or a text file or a similar external source.
[^1]: Except for VLAs. VLAs cannot be initialized this way.
First of all, this:
array[921600] = {229407, 229407, 229407,...,226851} //shorten
doesn't assign the entire array - it's attempting to assign a brace-enclosed list to a single array element (which is a syntax error), and that element is one past the end of the array (if there are 921600 elements in the array, then they are indexed from 0 to 921599).
You cannot assign an entire array's contents using the = operator - if you want to set all elements to the same value you can use memset, otherwise you'll have to assign elements individually.
Your compiler should also be yakking on Void and Uint8 - are you sure you don't mean void (C is case-sensitive) and uint8_t? And if you mean for the elements to be 8 bits unsigned, then they won't be able to represent values like 229407 or 226851.
This doesn't work:
array[921600] = {229407, 229407, 229407,...,226851};
Because you're actually attempting to assign (not initialize) a single value in array, and the {...} syntax is only valid for an initialization.
If you have some fixed set of values you're going to use to set your array, you can place them in another array and copy them in:
void setArray(uint8 *array)
{
static const int src[921600] = {229407, 229407, 229407,...,226851};
memcpy(array, src, sizeof src);
}
By making the source array static, you avoid having a large temporary array that could potentially blow up the stack.

Passing an array to a function then print that array in main function

Write a dice rolling game. The game should allow a user to toss up to six dice at a time. Each toss of a
die will be stored in a six‐element integer array. The array will be created in the main() function, but passed
to a new function called tossDie(). The tossDie() function will take care of generating random numbers
from one to six and assigning them to the appropriate array element number. After the dice are tossed,
the main() function should display the generated values of the dice.
The above is my problem.
I use an array in the tossDie function but when the array in tossDie function is printed. The elements in that array are more than six and I cannot control and the elements are not random numbers between 1 and 6.
This is my approach:
#include <iostream>
#include <time.h>
#include <stdlib.h>
int tossDie(int [], int);
int main() {
srand(time(0));
int a[6]= {'\0'};
int size = 6;
tossDie(a, size);
// printf("The dice results: \n%d", a);
}
int tossDie(int dice[6], int size){
srand(time(0));
int i =0;
for (i =0; i<=6 ; i++){
dice[i] = 1 + rand()%(6);
printf(" %d", dice);
}
return 0;
}
MAIN DECLARATION:
Your code could benefit from an overall critique, so let's start with the main declaration.
The standard clearly states that:
It [main] shall be defined with a return type of int and with no parameters.
There is a difference between
int main()
and
int main(void)
The first one takes an arbitrary amount of arguments, the second one doesn't.
MAGIC NUMBERS:
You have used the magic number 6, 5 times in the code. Consider using a define preprocessor instead:
#define MAX 6
It's easier to change and maintain. You wouldn't like changing 6 at a dozen places instead of just one.
NULL BYTE:
Replace the null byte '\0' with 0.
SIZE:
A common idiom in C to determine the size of an array is to use:
size_t size = sizeof (a) / sizeof (a[0]);
where sizeof(a) is the total number of bytes, and sizeof(a[0]) is the size of one element.
Though, you won't need to compute the size when you already have defined the size as a define statement?
RANDOM-NUMBER-GENERATOR:
The seed should only be set once. The answers to this question srand() — why call it only once?
explain it in detail.
ACCESSING ILLEGAL MEMORY
for (i = 0; i <= 6; i++)
You're accessing memory outside of the bounds of the array, which is illegal. The memory not allocated should not be read.
Array-indexing starts at 0 instead of 1.
So the sixth element of the array is at index position 5.
ORIGINAL PROBLEM:
You can use a for loop in the main function to print all the values of the array when you're done with all errors.
Consider changing the return type of the function to void as you do not need to return the array back to main when modifying it. The array decays to a pointer in the function parameter, so it's more of an alias. They both are pointing to the same memory, if you modify the memory through one or the other, the memory would be modified for both.
P.S: You may ask for clarifications if you found something unclear.

Remapping C pointer to a 3D array

I am trying to get a pointer to an array integers to be temporarily remapped in a function later on to save myself pointer math. I've tried to see if any other questions answered it, but I've been unable to reproduce the methods described here, here, and here.
Fundamentally, I just want to temporally treat an integer group and a 3D array to be sure that I don't mess up the pointer math. (I'm looking at this currently because the previous code had made inconsistent assignments to the memory).
#include <stdlib.h>
#define GROUPCOUNT 16
#define SENSORCOUNT 6
#define SENSORDIM 3
int main()
{
int *groupdata = (int *)calloc(GROUPCOUNT * SENSORCOUNT * SENSORDIM,sizeof(int));
int sensordata[SENSORCOUNT*SENSORDIM];
sensordata[7] = 42; //assign some data
int (*group3d)[GROUPCOUNT][SENSORCOUNT][SENSORDIM] = groupdata; //<---Here is the problem
group3d[1][5][1] = sensordata[7]; //I want to do this
free(groupdata);
}
In the example above, I want to handle groupdata as group3d temporarily for assignments, and I just cannot seem to wrap myself around the casting. I currently have macros that do the pointer math to enforce the correct structure, but if it was all just in the code, it would be even better when I pass it off. Any suggestions would be greatly appreciated.
note: The 3D cast is to be used in a function way in the bowels of the program. The example is just a minimally viable program for me to try to sort out the code.
When group3d is defined with int (*group3d)[GROUPCOUNT][SENSORCOUNT][SENSORDIM], then *group3d is a three-dimensional array. That would let you use it with (*group3d)[1][5][1].
To use it with group3d[1][5][1], you need group3d to be a pointer to a two-dimensional array:
int (*group3d)[SENSORCOUNT][SENSORDIM] = (int (*)[SENSORCOUNT][SENSORDIM]) groupdata;
(There are some technical concerns about C semantics in aliasing an array of int as an array of array of array of int, but this is not a problem in common compilers with default settings. However, it would be preferable to always use the memory as an array of array of array of int, not as an array of int.)
int l = 5, w = 10, h = 15;
int Data = 45;
int *k = malloc(l * w * h * sizeof *k);
// not use this k[a][b][c] = Data;
//use this is right
k[a*l*w + b*l + c] = Data;
In the example above, I want to handle groupdata as group3d
temporarily for assignments, and I just cannot seem to wrap myself
around the casting.
One possible solution is to create a multidimensional array dynamically like this. This way you won't have to cast things or worry about the dimensions.
int (*group3d)[GROUPCOUNT][SENSORCOUNT][SENSORDIM] = calloc(1, sizeof(int [GROUPCOUNT][SENSORCOUNT][SENSORDIM]));
(*group3d)[1][5][1] = sensordata[7]; //I want to do this
/* Then you can print it like */
printf("%d\r\n", (*group3d)[1][5][1]);

To know the size of an array in c

I am learning C language. I want to know the size of an array inside a function. This function receive a pointer pointing to the first element to the array. I don't want to send the size value like a function parameter.
My code is:
#include <stdio.h>
void ShowArray(short* a);
int main (int argc, char* argv[])
{
short vec[] = { 0, 1, 2, 3, 4 };
short* p = &vec[0];
ShowArray(p);
return 0;
}
void ShowArray(short* a)
{
short i = 0;
while( *(a + i) != NULL )
{
printf("%hd ", *(a + i) );
++i;
}
printf("\n");
}
My code doesn't show any number. How can I fix it?
Thanks.
Arrays in C are simply ways to allocate contiguous memory locations and are not "objects" as you might find in other languages. Therefore, when you allocate an array (e.g. int numbers[5];) you're specifying how much physical memory you want to reserve for your array.
However, that doesn't tell you how many valid entries you have in the (conceptual) list for which the physical array is being used at any specific point in time.
Therefore, you're required to keep the actual length of the "list" as a separate variable (e.g. size_t numbers_cnt = 0;).
I don't want to send the size value like a function parameter.
Since you don't want to do this, one alternative is to use a struct and build an array type yourself. For example:
struct int_array_t {
int *data;
size_t length;
};
This way, you could use it in a way similar to:
struct int_array_t array;
array.data = // malloc for array data here...
array.length = 0;
// ...
some_function_call(array); // send the "object", not multiple arguments
Now you don't have to write: some_other_function(data, length);, which is what you originally wanted to avoid.
To work with it, you could simply do something like this:
void display_array(struct int_array_t array)
{
size_t i;
printf("[");
for(i = 0; i < array.length; ++i)
printf("%d, ", array.data[i]);
printf("]\n");
}
I think this is a better and more reliable alternative than another suggestion of trying to fill the array with sentinel values (e.g. -1), which would be more difficult to work with in non-trivial programs (e.g. understand, maintain, debug, etc) and, AFAIK, is not considered good practice either.
For example, your current array is an array of shorts, which would mean that the proposed sentinel value of -1 can no longer be considered a valid entry within this array. You'd also need to zero out everything in the memory block, just in case some of those sentinels were already present in the allocated memory.
Lastly, as you use it, it still wouldn't tell you what the actual length of your array is. If you don't track this in a separate variable, then you'll have to calculate the length at runtime by looping over all the data in your array until you come across a sentinel value (e.g. -1), which is going to impact performance.
In other words, to find the length, you'd have to do something like:
size_t len = 0;
while(arr[len++] != -1); // this is O(N)
printf("Length is %u\n", len);
The strlen function already suffers from this performance problem, having a time-complexity of O(N), because it has to process the entire string until it finds the NULL char to return the length.
Relying on sentinel values is also unsafe and has produced countless bugs and security vulnerabilities in C and C++ programs, to the point where even Microsoft recommends banning their use as a way to help prevent more security holes.
I think there's no need to create this kind of problem. Compare the above, with simply writing:
// this is O(1), does not rely on sentinels, and makes a program safer
printf("Length is %u\n", array.length);
As you add/remove elements into array.data you can simply write array.length++ or array.length-- to keep track of the actual amount of valid entries. All of these are constant-time operations.
You should also keep the maximum size of the array (what you used in malloc) around so that you can make sure that array.length never goes beyond said limit. Otherwise you'd get a segfault.
One way, is to use a terminator that is unique from any value in the array. For example, you want to pass an array of ints. You know that you never use the value -1. So you can use that as your terminator:
#define TERM (-1)
void print(int *arr)
{
for (; *arr != TERM; ++arr)
printf("%d\n", *arr);
}
But this approach is usually not used, because the sentinel could be a valid number. So normally, you will have to pass the length.
You can't use sizeof inside of the function, because as soon as you pass the array, it decays into a pointer to the first element. Thus, sizeof arr will be the size of a pointer on your machine.
#include <stdio.h>
void ShowArray(short* a);
int main (int argc, char* argv[])
{
short vec[] = { 0, 1, 2, 3, 4 };
short* p = &vec[0];
ShowArray(p);
return 0;
}
void ShowArray(short* a)
{
short i = 0;
short j;
j = sizeof(*a) / sizeof(short);
while( i < j )
{
printf("%hd ", *(a + i) );
++i;
}
printf("\n");
}
Not sure if this will work tho give it a try (I don't have a pc at the moment)

Create a 2d character array in c

I want to create a 2d character array in C just like this one in php :
$matrix = array(
array('$','#','*','%','&','#','#','#','#','#'),
array('%','$','#','%','#','%','#','*','&','*'),
array('#','*','&','*','#','#','#','&','%','#'),
array('%','#','*','$','%','&','#','*','#','&'),
array('$','*','&','&','&','#','#','%','*','*'),
array('#','#','#','#','&','%','*','$','#','#'),
array('&','$','$','#','#','#','#','$','%','*'),
array('#','$','$','*','&','$','#','*','#','*'),
array('%','$','*','#','&','#','&','#','#','#'),
array('#','#','%','*','#','&','#','$','%','#')
);
I tried writing up this code :
int size = 10;
char matrix[size][size] = {
{'$','#','*','%','&','#','#','#','#','#'},
{'%','$','#','%','#','%','#','*','&','*'},
{'#','*','&','*','#','#','#','&','%','#'},
{'%','#','*','$','%','&','#','*','#','&'},
{'$','*','&','&','&','#','#','%','*','*'},
{'#','#','#','#','&','%','*','$','#','#'},
{'&','$','$','#','#','#','#','$','%','*'},
{'#','$','$','*','&','$','#','*','#','*'},
{'%','$','*','#','&','#','&','#','#','#'},
{'#','#','%','*','#','&','#','$','%','#'}
};
I am very new to c so i don't really know the concept of 2d arrays in c. But for some reason the above code is giving error. Please help.
This is because C compiler thinks that you are trying to initialize an array of length determined at runtime, even though you supply the size 10 at compile time.
Replacing int size= 10 with #define SIZE 10 will fix this problem:
#define SIZE 10
...
char matrix[SIZE][SIZE] = {
{'$','#','*','%','&','#','#','#','#','#'},
{'%','$','#','%','#','%','#','*','&','*'},
{'#','*','&','*','#','#','#','&','%','#'},
{'%','#','*','$','%','&','#','*','#','&'},
{'$','*','&','&','&','#','#','%','*','*'},
{'#','#','#','#','&','%','*','$','#','#'},
{'&','$','$','#','#','#','#','$','%','*'},
{'#','$','$','*','&','$','#','*','#','*'},
{'%','$','*','#','&','#','&','#','#','#'},
{'#','#','%','*','#','&','#','$','%','#'}
};
Demo.
In C99 there is a variable length array, so you can do that, but not all compilers support vla and C99 standard (#Jonathan Leffler but still can not initialize array).
So the solution is to give computer information about size of array before compilation. So you can define size with macros
#define size 10
Or to create array dynamically on heap using malloc (and other memory allocating functions)
Or to create array dynamically on stack using alloca and malloca
Also on some compilers I found that const variables can be used to do that, but that is rare (found on borland) and not standard.
If you initialize array, then you can omit dimensions. For example
int a[] = {1, 2, 3};
int b[][3] = { { 1, 2, 3 }, { 4, 5, 6 } };
int size = 10;
char matrix[size][size];
memcpy(&matrix[0][0],
"$#*%&#####"
"%$#%#%#*&*"
"#*&*###&%#"
"%#*$%&#*#&"
"$*&&&##%**"
"####&%*$##"
"&$$####$%*"
"#$$*&$#*#*"
"%$*#&#&###"
"##%*#&#$%#", size*size);
Assuming a 10x10 char array:
char **matrix = malloc(sizeof(char*)*10);
int i, len = 10;
for(i = 0; i < len; i++)
matrix[i] = (char *)malloc(11) // the 11th one is for the null '\0' character (you can ignore it if you like)
Now you can fill the char array locations as you like:
// for example row 1 column 1
matrix[0][0] = '$';
that should help.
After you're done, make sure you use "free" to free the memory allocated.

Resources