How to declare a jagged array in a header file? - c

To define a jagged array, I'm using this answer by #FaisalVasi. This works perfectly. To get the (i,j)-entry of a such defined array, type (*jagged[i])[j].
However, I like to put all my arrays in a separate file (my constant arrays), and then I have to declare them in the header file. And I don't manage to do that. I tried **jagged = unsigned[][] and *jagged = unsigned*[], and other attempts I don't remember. Anyway everything I've tried did not work. So how should I declare the jagged array in the header file?
I'm a novice in C and I hope the question is clear. Otherwise please ask me what could I clarify.

NOTE: Deviating from the requested array-of-pointers-to-rows syntax and pointing to the rows directly in the array, as proposed by #Someprogrammerdude, allows to obtain the same result, but with one less indirection and with a more clear access syntax.
direct array of rows solution
definition
unsigned jagged_row0[] = { 0, 1, 99 };
unsigned jagged_row1[] = { 1, 2, 3, 4, 5, 6, 99 };
unsigned *jagged[] = (unsigned *[]){ jagged_row0, jagged_row1 };
or in general:
type jagged_row0[] = { ... };
type jagged_row1[] = { ... };
...
type *jagged[] = (type *[]){ jagged_row0, jagged_row1, ... };
declaration
extern unsigned *jagged[];
or in general:
extern type *jagged[];
usage
unsigned v_i_j = jagged[i][j];
or in general:
type v_i_j = jagged[i][j];
original answer
The following solution addresses the definition given in the cited answer by #FaisalVasi, where the jagged array stores explicit pointers to the jagged rows.
definition (in some .c file)
unsigned jagged_row0[] = {0,1};
unsigned jagged_row1[] = {1,2,3};
unsigned (*jagged[])[] = { &jagged_row0, &jagged_row1 }; /* note the ampersand */
/* or alternatively, since compound literals are lvalues ... */
unsigned (*jagged[])[] = { &(int[]){0,1}, &(int[]){1,2,3} };
declaration
extern unsigned (*jagged[])[];
usage
unsigned *jagged_row;
...
jagged_row = *jagged[i];
unsigned v_i_j = jagged_row[j]; /* value at [i][j] */
or more compactly:
unsigned v_i_j = (*jagged[i])[j]; /* value at [i][j] */
explanation
A jagged row is an array of some basic type, in our case an array (of length determined by the static initialization) of unsigned (unsigned[]), which can be thought of, with some caveats, as a pointer to unsigned (unsigned *).
With the proposed definition, the jagged array is an array of pointers to jagged rows, which, with the same simplification, can be though of as an array of unsigned **.
When you index the first dimension, you are getting the pointer to the jagged row (an array), then you have to dereference this pointer to get to the array itself that is the jagged row, than you have to index this array to get to the final value.

A jagged array in C is usually a pointer to the first element of an array of pointers. Basically a pointer to a pointer. I.e. type **jagged.
To declare just about any variable in a header file use the extern keyword. As in
extern type **jagged;
[Replace type with the actual type]
There's two way to use it:
Full dynamic allocation
jagged = malloc(sizeof(*jagged) * M);
for (unsigned i = 0; i < M; ++i)
jagged[i] = calloc(N, sizeof(**jagged));
// Now jagged is a MxN jagged matrix where each element is zero
jagged[1][2] = 1; // Sets a single value to 1
Arrays of arrays
type jagged_row_0[] = { a, b, c };
type jagged_row_1[] = { x, y };
type **jagged = (type *[2]){ jagged_row_0, jagged_row_1 };
printf("jagged[1][0] = %d\n", jagged[1][0]);
Of course, you could make an actual array of array of pointers instead (much like the second case above):
extern type *jagged[];
...
type *jagged[] = { jagged_row_0, jagged_row_1 };
...
printf("jagged[1][0] = %d\n", jagged[1][0]);
Be very careful when having rows with different size though, so you don't go out of bounds.

Related

array definition error: why do I have this error?

(disclaimer: just ignore mat_constr function because it's not related to this question (it's mat_constructor of another question I've posted, because I'm trying to edit the mat_transpose function on my own)).
this is a very simple exercise, yet I can't figure out how to define an array (correctly).
I have a
struct matrix {
size_t rows;
size_t cols;
double* data
};
in the main function, I have to define a variable of type "struct matrix", and then I have to define the array. As follows:
int main(void) {
struct matrix A;
mat_constr(&A, 4, 4);
A.data = { /* a number */, /* another number* /, /* etc. */ };
}
the problem is that the compiler highlighted the first "{". in the array definition, and it says: "expected an expression".
this is strange, because this is the definition style of the array, am I wrong?
Assuming that mat_constr allocates memory as a single array of double, and makes the data member point to it, then you can copy to this array.
For example using memcpy and compound literals:
memcpy(A.data, (double[16]){ 1, 2, 3, ... }, 16 * sizeof(double));
[I made an assumption that mat_constr allocates a single array of 4 * 4 elements in my example above. Please don't let us make assumptions, create a proper Minimal, Reproducible Example instead.]
You can of course copy a value to each element of the array individually instead:
A.data[0] = 1;
A.data[1] = 2;
A.data[2] = 3;
...
And if you want to set all elements to a single value you can of course use a loop:
for (unsigned i = 0; i < 16; ++i)
{
A.data[i] = 5;
}
Or if you want to set all elements to zero then either allocate with calloc:
A->data = calloc(A->rows * A->cols, sizeof(double));
Or use memset:
memset(A.data, 0, 16 * sizeof(double));
The problem is that C has no notion of array litteral. And the equal sign can be used for 2 very different operations, assignment and initialization.
The brace enclosed expression can be used to initialize an array, but cannot be used to initialize a pointer nor can it be assigned to a pointer:
double data[] = {1., 2., 3.}; // array initialization: valid
double *data = {1., 2., 3.}; // INVALID attempt to initialize a pointer
double *d2;
d2 = {1., 2., 3.}; // INVALID assignment to a pointer

How do I correctly return an array from a function?

I tried this:
int* test()
{
static int states[2]= {4,7};
return states;
}
And called it like this:
int* values = test();
But it only seems to return the first value - 4 - and not the whole array.
I tried to do it exactly as I saw in other examples so I'm confused as to why it doesn't work. I'm using the STM32cubeIDE to write and compile, if that makes a difference.
Normal arrays can't be returned from a function because their lifetime ends when the function returns, the behavior for accessing one of these local arrays outside the scope of the function is undefined.
In your particular case this is possible because your array has static storage duration.
In C a function can only return one element, so to return an array you must return a pointer which can contain the address of the first element of that array. And that's what you're doing in your code. You can access both values by correctly indexing the returned pointer i.e. values[0] and values[1].
Unfortunately this is not without its issues, the size of the array is not known by the caller and you can't safely index it because you don't know its bounds.
There are ways solve this which are not all that complicated once you get used to them. Most notably defining a global size for the array1, using a structure containing the size of the array and a pointer to the array itself2, or passing pointers to the size and/or the array as arguments of the function3.
1. Using a global variable that stores its size:
#define SIZE 2
int *test()
{
static int states[SIZE] = {4, 7};
return states; //returns a pointer to the first element of the array
}
int main()
{
int* values = test(); // values is now pointing to the array
for(size_t i = 0; i < SIZE; i++){
printf("%d ", values[i]); //indexing is similar to a local array
}
}
2. Using a struct to store both the size and a pointer to the array:
typedef struct{ //structure to hold the data
int *array;
size_t size;
} array_struct;
array_struct test()
{
static int states[2] = {4, 7};
array_struct array = {.array = states, .size = 2}; //assing pointer and size
return array; //return the structure
}
int main()
{
array_struct values = test(); //assing the structure to a local
for(size_t i = 0; i < values.size; i++){ //use the size passed
printf("%d ", values.array[i]);
}
}
Output:
4 7
Option 3 is laid out in Bathsheba's answer.
You get back a pointer to the first element of the array due to the decay of the array type to a pointer type.
You obtain the other elements by pointer arithmetic.
Unfortunately though all size information is lost so you don't know at the call site how many elements you have. One way round that would be to change the function to
void test(int** array, size_t* length)
with *array = states and *length = sizeof(states) / sizeof(states[0]) in the function body.
How do I correctly return an array from a function?
You don't because you cannot. Read the C11 standard n1570.
(since as return values, arrays are decayed to pointers)
In practice, you could use a flexible array member in your struct and return some malloc-ed pointer to that struct. You then need a documented convention about who will free that pointer.
Read about C dynamic memory allocation. For more details and example code, see this answer.

Understanding-pointer to a structure

I want to understand how the pointer to the structure is passed to the function argument and implemented. How is avrg_stpc[idx_u16].sum_f32 array is working?
typedef struct
{
const float * input_f32p;
float avg_f32;
float sum_f32;
float factor_f32;
unsigned int rs_u16;
} avgminmax_avg_t;
void avgminmax_AvgCalculate_vd(
avgminmax_avg_t * const avrg_stpc,
const unsigned int numOfEntrys_u16c)
{
unsigned int idx_u16 = 0u;
do
{
avrg_stpc[idx_u16].sum_f32 += (*avrg_stpc[idx_u16].input_f32p
- avrg_stpc[idx_u16].avg_f32);
avrg_stpc[idx_u16].avg_f32 = (avrg_stpc[idx_u16].sum_f32 *
avrg_stpc[idx_u16].factor_f32);
idx_u16++;
}while(idx_u16 < numOfEntrys_u16c);
}
A few points that could help you understand arrays and pointers and their relationship:
A pointer really only points to one "object", but that object might be the first in an array.
Arrays naturally decays to pointers to their first element.
And array indexing is equivalent to pointers arithmetic (for any pointer or array a and index i, the expression a[i] is exactly equal to *(a + i)).
As for your specific example code, perhaps it would be easier if you thought of it similar to this:
avgminmax_avg_t *temp_ptr = &avrg_stpc[idx_u16];
temp_ptr->sum_f32 += ...;
temp_ptr->avg_f32 = ...;
Or perhaps like:
avgminmax_avg_t temp_object = avrg_stpc[idx_u16];
temp_object.sum_f32 += ...;
temp_object.avg_f32 = ...;
avrg_stpc[idx_u16] = temp_obj;
Both the snippets above will lead to the same result as your existing code, but requires an extra temporary variable, and in the latter snippet copying of the structure twice.
avrg_stpc is regarded as an array (possibly, allocated on heap via .*alloc); since its bounds can't be known, hence the second argument to the function. See here: https://en.cppreference.com/w/c/language/operator_member_access

Assigning an array to a struct member in C [duplicate]

This question already has answers here:
Why can't I assign arrays as &a = &b?
(2 answers)
Closed 9 years ago.
I wrote this piece of code
#include <stdio.h>
struct foo
{
int foo1[3];
};
int main(void)
{
int a[] = {1, 2, 3};
struct foo test;
test.foo1 = a;
printf("%d\n", test.foo1[0]);
return 0;
}
It gives compile error saying that it cannot convert int * to int[3].
I know that array names will decay into pointers in expressions, but is there a way of suppressing that since I do need an array here?
As the others said, there is not direct assignment operators that will copy an array. You have to use memcpy() instead
memcpy(test.foo1, a, sizeof(a));
This is one source of errors in C because the sizeof() needs to be large enough to copy all the data but not too large so as not to overwrite data at tests.foo1. The best practice, I would imagine, is to test that both arrays are the same size before doing the memcpy().
This is one of the basics of C, arrays cannot be assigned.
In C and in C++ there is no way to assign a value to an whole array. It is also not possible to assign an array the values of an other array (even if the dimension would match).
You cannot assign arrays in C. However, you can assign objects of user-defined type, even if those contain an array. So peraps rewrite it like this:
struct foo a = { { 1, 2, 3 } };
struct foo test;
test = a;
Or of course just initialize the object correctly immediately:
struct foo test = { { 1, 2, 3 } };
Arrays are not first class objects in C. You can't copy (assign), compare, pass, or return an array. You copy an array into another array element by element. You also compare two arrays element by element. You pass a pointer to a first element of the array and similarly return a pointer to the first element of a dynamically allocated array. Therefore test.foo1 = a; is wrong. You have two choices here.
#include <stdio.h>
struct foo {
int foo1[3];
};
int main(void) {
int a[] = {1, 2, 3};
struct foo test;
int len = *(&(test.foo1) + 1) - test.foo1; // length of the array test.foo1
int i = 0;
for(i = 0; i < len; i++)
test.foo1[i] = a[i]; // copy the array element-wise
printf("%d\n", test.foo1[0]);
return 0;
}
You can also directly copy all the bytes from the array a in main to the array test.foo1 using memcpy.
memcpy(test.foo1, a, sizeof a);
This copies all the bytes of the array a into the array test.foo1. Therefore the array test.foo1 must be large enough else it will lead to undefined behaviour or even segfault.

C returning array in function

Im relatively knew to C, i am used to program in Java so i find C a little bit difficult in what concerns arrays. I still cofuse myself with this cases:
int a [];
int* a;
int *a;
In java, i would do something like this to return an array in a function:
int [] returnArr(int [] a){
... modify a ...
return a;
}
int [] a = {...};
int [] b = returnArr(a); ##
How can i do the same in C, specially the parts with ##.
EDITED:
I have this function:
float *normalizeValues(float *v, float maxY){
int size = sizeof(v) / sizeof(float);
float max = findMax(v);
float ratio = maxY / max;
int i;
for(i = 0; i < size ; ++i){
v[i] = v[i] * ratio;
}
return v;
}
And im doing the following:
float vert [] = {306, 319, 360, 357, 375, 374, 387, 391, 391, 70, 82, 94, 91, 108, 114, 125, 127, 131};
int i = 0;
float *vert2;
vert2 = normalizeValues(vert, 0.7);
for(i = 0; i < sizeof(vert2) / sizeof(float); ++i){
fprintf(stdout,": %f\n",vert2[i]);
}
And the output is only 1 element.
EDIT: To directly answer your updated question: you have to pass in the size of the array. C has no mechanism to store the size of arrays like Java does. If the compiler knows about the size of the array because the array is a global or local variable, not dynamically allocated, then you can use the sizeof() operator. Otherwise, you have to know the size separately, or use sentinel values in your array (such as a 0.0 at the end, or a NULL).
As for arrays, pointers and arguments in general, see below:
You will be returning a pointer to the array, which is indicated with the '*' syntax:
int *returnArr(int[] a) {
// modify a...
return a;
}
int a[] = { ... };
int *b;
b = returnArr(a);
A few things to note:
You can't do assignments in variable declarations that involve non-constant expressions (e.g., function calls). This might have changed in C99, though.
The brackets go after the variable name, unlike in Java where they are part of the type. Even though Java's syntax is more consistent, it doesn't quite make sense in C where you often give the array size in the brackets in the variable declaration:
int a[3] = { ... };
There's no way to specify that a function returns an array as opposed to a plain pointer. In C, array references decay to pointers (though pointers and arrays are NOT the same thing, as is commonly claimed). That means that whenever you pass an array around, C only provides a means to a pass a pointer to the array. The whole array isn't actually copied. As it happens, the name of the array is also a pointer to the first element of the array.
Please also take note of what user268396 says in their answer. If you are planning to create a new array and return it, you'll need to either allocate the array dynamically, or have a pointer to an already allocated array be passed in (which is what it seems like you are kind of doing anyway).
You can't. When the function returns the stack frame will be wiped out (typically) and your generated array will be clobbered by that. You can however edit the function prototype to accept a pointer to the array to modify. That kind of function argument is known as an "output parameter". Example:
void function func(int a, int b, int[2] to_modify)
{
to_modify[0] = a;
to_modify[1] = b;
}
int main()
{
int foo[2];
func(1, 2, foo);
printf("Result: foo[0] = %d, foo[1] = %d\n", foo[0], foo[1]);
return 0;
}
This will print "Result: foo[0] = 1, foo[1] = 2".
Hope this helps
#include<stdio.h>
void change(int *c)/*Pointer c now has the first location of the array a[]*/
{
*(c+0) = 0;/*assign values to the array by adding step-size to the first array position*/
*(c+1) = 1;
*(c+2) = 2;
*(c+3) = 3;
*(c+4) = 4;
}
main()
{
int a[5]={10,20,30,40,50}; /* Declare and Assign an array a[] of size 5.*/
int *b = a; /*Declare and assign a Pointer to the location of the array.*/
change(b); /*pass the pointer(which is now pointing to first position of array) to the change() function.*/
printf("%d,%d,%d,%d,%d,",a[0],a[1],a[2],a[3],a[4]);/*Print the changed value.*/
}
Output: 0,1,2,3,4,
From Java point of view, Pointers are simply like(not exactly) Object references.
Object O;
O = New SomeClassName();
Like Object Reference O is pointing to some Actual Object of type SomeClassName, so does pointers in C:
int *b;
b = &a;
Variable b is simply pointing to the address location to a.
Taking a deep dive into array concepts:
int a[5];
int *b = a;
Here we are just saying like Mr.*b point to the first location of group a i.e. a[0].
Now the power pointer in C is that from now on, here after:
*b means a[0]
*(b+1) means a[1]
*(b+2) means a[2]
*(b+3) means a[3]
*(b+4) means a[4]
This means you change in *(b+4), you're changing a[4].
int* returnArr(int a[]){
//modify a
return a;
}
One need mention is when you use an array in the parameter list of a function, it will be converted into a pointer. So in main(...)'s declaration, char *argv[] and char **argv are actually same. In this case, int a[] and int* a are same. But array and pointer is not the same thing.
Take the following code as an example:
int a[10];
int main(){
int *p = a;
p[5] = 4;
return p[5];
}
p is a pointer, when we access p[i], note that the address of p is not the address of a, the content of p is the address of a. Then the code will:
access the memory to get the content of p, i.e. the address of a.
compute the offset based on i and type of the pointer(int).
access the memory to get the result.
a is an array of int, if we access a[i], the address of a is just the address of a[0], the code will:
Compute the offset based on i and the type int.
Access the memory.
Pointer and array are different types. So if you declare int *p in one file and use it in that file, but define the p as an array in another file, that will cause problem.
You may also wonder about int *p = a, in ANSI, if you use an array(its name) as an expression, the compiler will convert it into a pointer, pointing to the very first element of the array.
Update based on Jim Balter's comments:
If you use an array(its name) as an expression, the compiler will not always convert it into a pointer, pointing to the very first element of the array. For instance, in sizeof(p->q->a), p->q->a is an expression but if a is an array it isn't converted into a pointer.
"Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type ‘‘array of type’’ is converted to an
expression with type ‘‘pointer to type’’ that points to the initial
element of the array object.
In C, you can only return a pointer of an array in a function.
For example, if you want to return a string(array of char) in a function, you can return a pointer to a null-ended string. If you want to return an array of some other type(int, user-defined struct, etc), you can alloc some memory to store the array, and return the pointer of the array, return the size of the array in the parameter.
example:
int *function(int *size)
{
*size = 10;
int *intP = (int *)malloc((*size)*sizeof(int));
return intP;
}

Resources