I have a structure, say foo that looks like this,
struct foo {
size_t n;
size_t **point;
};
There are other members in the structure they are not important to the question. Now, I want to static initialize the structure.
int main(void)
{
struct foo *bar = &(struct foo){
.n=4,
/* ERROR HERE */ .point=(size_t[][n]){ {1, 2, 3, 4}, {5, 6, 7, 8}}
};
return 0;
}
There are two problem in the line indicated. First, understandably the compiler doesn't recognise n and is there any way I can do something similar without creating a variable before? Secondly, and most importantly, I realized that I have no idea how to create a 2D array and assign it to a pointer to pointers statically. Please help. I tried the following variations but nothing worked.
/* Variation 1 */ .point=(size_t[][4]){ {1, 2, 3, 4}, {5, 6, 7, 8}}
/* Variation 2 */ .point=(size_t**)(size_t[][4]){ {1, 2, 3, 4}, {5, 6, 7, 8}}
/* Variation 3 */ .point=&(size_t[][4]){ {1, 2, 3, 4}, {5, 6, 7, 8}}
Note that this isn't technically 2D array, but a pointer-to-pointer array. But since compound literals cannot have variable length array type, and it doesn't seem that you want to use hardcoded dimensions, this may be the only way to go.
You'll need to split your arrays to 1D arrays of unknown size and use separate compound literals for them:
struct foo * bar = &(struct foo){
.n = 4,
.point = (size_t*[]){
(size_t[]){1, 2, 3, 4},
(size_t[]){5, 6, 7, 8}
}
};
First of all size_t **point only makes sense if you intend to point at an array of size_t*. That doesn't seem to be the case here, so you need to change the type to a 2D array, or an array pointer.
Next problem is that C is rather cumbersome here - bluntly put, you can't have a "static dynamic" array, it must be either. You can either have this:
#define N 4
struct foo {
size_t n;
size_t (*point)[N]; // pointer to first array of an array of size_t[4]
};
struct foo bar =
{
.n=N,
.point= (size_t[][N]){ {1, 2, 3, 4}, {5, 6, 7, 8} }
};
...
bar.point[x][y] = ...; // access element of the 2D array
or alternatively perhaps a flexible array member in the form of an array of pointers, like this:
struct foo {
size_t n;
size_t* point[];
};
const size_t n = 4;
struct foo* bar = malloc ( sizeof(*bar) + sizeof (size_t*[n]) );
bar->n = n;
bar->point[0] = (size_t []) { 1, 2, ... /* any number of elements*/ };
bar->point[1] = ...
...
bar->point[0][0] = 0; // access element in the lookup-table
...
free(bar);
None of these are particularly good alternatives, the syntax is messy and error prone. The language is simply severely lacking here.
In order to initialize a pointer statically, the entities you are pointing to need to have been declared. Only in rare cases, like maybe an embedded system where you know the address of something at compile time, would you know the actual value of the pointer to be initialized statically.
I see a couple problems with what you're doing:
1) The compiler can't resolve what the value of n is at the time you are trying to use it to declare the size of your array. Arrays need to have a size supplied in their declaration, unlike C#.
2) The "point" member of the struct is a pointer to pointers, but you're trying to initialize it with an array of arrays. If you want to point to an array of arrays, you only need the address of the [0][0] element, so *point not **point. From there you can use array notation to access the elements.
You need to do something like this:
struct foo
{
size_t n;
size_t *point;
};
size_t values[2][4] = {{1,2,3,4}, {5,6,7,8}};
struct foo bar =
{
4,
&values
}
Then you can access the array by:
size_t kk;
kk = bar.point[ii][jj];
If you truly need pointers to pointers, then the initialization values will have to either be address references (&name) or values that are being cast as pointers, but I don't suggest doing that.
If you truly need a variable size for your array, then you'll need to allocate memory dynamically and then initialize the pointer in the struct with the address returned from that.
Related
Can someone plz explain me what is the diffrence between those tow lines
and when we will want to use each one of then
int array[] = { 1, 2, 3 }; // init a regular array
int *numList = {1, 2, 3}; // init an array of pointers?
I am expecting that there are probably seenarios we will want to use the second over the first,
But when?
Thank You in Advance
You're conflating some concepts. As #ikegami noted, your second line:
int *numList = {1, 2, 3};
Gets treated as:
int *numList = 1;
Which not an array, nor a valid pointer.
If you want to create an array of pointers, you use the same syntax as normal arrays, with the type being a pointer:
int* numList[] = {
&array[0],
&array[1],
&array[2]
};
Will create an array of 3 int pointers, pointing to your original array's elements.
Struct initializes can be used after initialization by casting it. Eg.
struct EST {
int a;
float b;
}est;
int main() {
est = (struct EST){23, 45.4}; //This works nicely and est gets the values
printf("a: %d\nb: %f\n", est.a, est.b);
}
But the same can't be done for arrays:
int arr[6];
arr = (int []){1, 2, 3, 4, 5};
This gives
error: assignment to expression with array type
What's more head breaking is that if there is an array in the struct, it still works.
struct Weird {
int arr[6];
}w;
int main() {
w = (struct Weird){{1, 2, 3, 4, 5}}; /* It works. The member arr gets all its elements
filled
*/
}
There seems to be something about the = operator not being valid with arrays after initializing. That is my theory.
Why is this and how can arrays be assigned after initializing?
initialization means initializing of a variable at declaration time. The following is correct and is supported by 'c':
int arr[6] = {1,2,3,4,5,6};
Assignment means assigning a value to a variable somwhere in the program after initialization. 'C' does not support assignment to a whole array. Arrays are very special members in 'c' and are treated in a special way which does not allow assignments.
However, you can always copy one array into another either by using a for loop or my using something like memcpy. Here is an example:
int arr[6], brr[6] = {1,2,3,4,5,6};
memcpy(arr,(int[6]){1,2,3,4,5},sizeof(int[6]));
BTW, the cast-like object from your example (int[]){1,2,3,4,5} is called 'compound literal' and is also allowed in c. Here it is used to initialize the parameter of the memcpy function.
I have already understood that one can't assign arrays to arrays in c. A statement like:
int array1[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int array2[10];
int * array3 = array;
Is valid, but a consecutive statement:
array2 = array1;
Is not, because arrays do decay to pointers. I find this not satisfying, since in case I have a function that creates an array:
int * arrcreate() {
static int funcarray[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
return funcarray
}
And I call it in my main routine, I'd like to handle an array, not a pointer.
Of course I could in my main program create an array and fill it by hand:
int main() {
int array[10];
int i;
int * p = arrcreate();
for(i = 0; i<10, i++) {
array[i] = p[i];
}
}
But since I KNOW that when initializing an array it is possible to do kind of an assignment:
int array1[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
I wanted to ask if it is possible to assign an array with the pointer to an array as well.
An equivalent question would be: Given a pointer to an array, and knowing the size of the array the pointer is pointing to, is it possible to create and initialize on the fly a new array, which is in every matter a copy of the old one?
As Bathsheba said, an array cannot be on the left hand side of an assignment like the one you put in your question. But if you will always know both the pointer to the array you would like to copy, as well as the array size, you could write a function along the lines of:
void copy_array(const int *a, const int arraySize, int **b) {
*b = malloc(arraySize * sizeof(*a));
for (int indx = 0; indx < arraySize; indx++) {
(*b)[indx] = a[indx];
}
}
int main() {
int array1[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int *array2;
copy_array(array1, &array2);
// do stuff
free(array2);
}
Is that an option?
Unfortunately the answer is not. The draft n1570 for C11 says in 6.7.9 Initialization:
...16 Otherwise, the initializer for an object that has aggregate or union type shall be a brace enclosed
list of initializers for the elements or named members.
(the previous items concern struct, union or character type array)
That means that an int array can only be initialized with a brace enclosed list of integer values. And a pointer to an array does not follow that definition.
Informally speaking, an array cannot be an lvalue. This means that an array cannot be on the left hand side of an assignment.
Note secondly that int array1[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; is not an assignment but is array initialisation.
If you're careless regarding terminology, the two sentences appear to be in contradiction. But they are not; furthermore you can see that it is not possible to initialise an array using the values pointed at by a particular pointer. You need to use something on the lines of memcpy.
int array[2] = {1, 1};
int (*pointer_array)[2] = {NULL, NULL};
The first line can be correctly compiled but not the second one? Why?
GCC compiler will pop up a warning, excess elements in scalar initializer.
How to initialize a pointer array in C?
EDITED
I declared a pointer array in a wrong way.
It should be like this:
int *pointer_array[2] = {NULL, NULL};
It should be
int (*pointer_array)[2]=(int[]){1,2};
This is pointer to array of int .I don't know you want pointer to array of int or array of pointers.
To declare as array of pointer you need to do this -
int *pointer_array[2];
Suppose you have an array of int of length 5 e.g.
int x[5];
Then you can do a = &x;
int x[5] = {1};
int (*a)[5] = &x;
To access elements of array you: (*a)[i] (== (*(&x))[i]== (*&x)[i] == x[i]) parenthesis needed because precedence of [] operator is higher then *. (one common mistake can be doing *a[i] to access elements of array).
Understand what you asked in question is a compilation time error:
int (*a)[3] = {11, 2, 3, 5, 6};
It is not correct and a type mismatch too, because {11,2,3,5,6} can be assigned to int a[5]; and you are assigning to int (*a)[3].
Additionally,
You can do something like for one dimensional:
int *why = (int[2]) {1,2};
Similarly, for two dimensional try this(thanks #caf):
int (*a)[5] = (int [][5]){ { 1, 2, 3, 4, 5 } , { 6, 7, 8, 9, 10 } };
I am a complete noob at C (<1 week) and I'm trying to get a grasp how to work on it, although I'm familiar with programming in other languages. As a first goal, I wanted to write a function to do Gauss reduction on a matrix. I have no problem with the algorithm, but it turned out I do not know how to represent a matrix. For simplicity, let me assume that we work with float entries.
The first naif way would be to use an array of arrays like
float naifMatrix[3][3] = {
{2, 1, 3},
{0, -1, 4},
{1, 3, 0}
};
The problem is that you cannot pass such an object as an argument without knowing the dimensions a priori (of course I want to be able to use matrices of arbitrary size, which is not known at compilation time). One does not see this problem when working with vectors and representing them as arrays. If I do
float vector[3] = {1, 2, 3};
norm(vector);
it will work, provided I declare norm like
norm(float * vector);
When vector is passed, it is converted to &vector[0], and not much information is lost (basically one has to keep track of the length). But I cannot just call
gaussReduction(naifMatrix);
and declare gaussReduction with
gaussReduction(float ** naifMatrix);
because naifMatrix is converted (and rightly so) to a pointer to an array of floats, not in a pointer to a pointer. Since I do not know how big this array will be, I do not see a way to declare gaussReduction.
Of course I could cheat by passing a pointer to a void, but before dereferencing it, I would need to cast it to the right type (float[3] *), which, again, I do not know a priori. Moreover it seems to me that by abusing of void * one defeats one of the purposes of using C over other languages, which is a strict type checking.
The best solution I have found so far is to use a struct. A matrix is basically given by the list of its entries and the two dimensions. So I can do
struct matrix {
float * begin;
int rows, columns;
};
and use it as
struct matrix matrix = {&naifMatrix[0], 3, 3};
The problem is that this is still annoying. First it is akward to get a struct matrix from a double array, and second one has to give the dimensions explicitly. I would be happy with wrapping this with a sort of "constructor" function, like
struct matrix matrix = Matrix(naifMatrix);
but I cannot do this for two reasons. First, I have the same problem as above in passing naifMatrix as argument to a function. Second, even if I could pass it, I would get a pointer, and thus I would not be able to get information on the dimensions (in this case, that both are 3).
Is there a more sensible way to pass around and manipulate the datum of a matrix?
C99 added variable-length arrays to the language:
_Bool gaussReduction(size_t rows, size_t cols, float matrix[rows][cols]);
If you have the definition
float naifMatrix[3][3] = {
{2, 1, 3},
{0, -1, 4},
{1, 3, 0}
};
you can get at the dimensions via
size_t rows = sizeof naifMatrix / sizeof *naifMatrix;
size_t cols = sizeof *naifMatrix / sizeof **naifMatrix;
You can use macros to minimize repetition. Using
#define rowsof(MATRIX) (sizeof (MATRIX) / sizeof *(MATRIX))
#define colsof(MATRIX) (sizeof *(MATRIX) / sizeof **(MATRIX))
#define matrixarg(MATRIX) rowsof(MATRIX), colsof(MATRIX), (MATRIX)
you'd end up with
gaussReduction(matrixarg(naifMatrix));
or, using a compound literal instead of a variable, with
gaussReduction(matrixarg(((float [3][3]){
{2, 1, 3},
{0, -1, 4},
{1, 3, 0}
})));
Using a variable-length array has the same performance characteristics as the equivalent C90 code - the only thing you'll gain is nicer syntax:
// C99:
_Bool gaussReduction(size_t rows, size_t cols, float matrix[rows][cols])
{
// size_t i = ..., j = ...
float x = matrix[i][j];
/* C90: */
int gaussReduction(size_t rows, size_t cols, float *matrix)
{
/* size_t i = ..., j = ... */
float x = matrix[i * cols + j];
If you define thus:
float naifMatrix[][] = {
{2, 1, 3},
{0, -1, 4},
{1, 3, 0}
};
You should have a pointer to an array of pointers. Then you can use
gaussReduction(float ** naifMatrix);
My C is rusty, though.