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.
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.
This question already has answers here:
How to pass a 2D array by pointer in C?
(5 answers)
Closed 1 year ago.
I'm working on a pathfinding library for fun and to become more familiar with C, and I have no idea what's causing this error or how to fix it. Why are the types of bool** and bool*[4] not compatible? Is there a work around for this or is there a better way of going about this problem?
#include <stdbool.h>
#include <stdlib.h>
int * A_Star_SolveUnweighted(bool **graph) {
}
int main() {
bool graph[5][4] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
int *path = A_Star_SolveUnweighted(graph);
return 0;
}
The following are different types, with only the one relationship noted between them:
bool graph[5][4] is an array of five arrays of 4 bool. In many uses, it will be automatically converted to a pointer to an array of 4 bool.
bool (*)[4] is a pointer to an array of 4 bool. It is the result of the above conversion.
bool *[4] is an array of 4 pointers to bool. It has no relation to bool (*)[4].
bool ** is a pointer to a pointer to a bool. It is not an array or a pointer to an array.
The routine is declared to take a bool **. Passing it graph results in an argument of type bool (*)[4], due to the automatic conversion. These are not compatible types, so the compiler complains. The argument type, bool (*)[4], points to where there are 4 bool (and additional subarrays of 4 bool after it). The parameter type, bool **, requires something that points to where there is a pointer. Since 4 bool and a pointer are very different things, these types are not compatible.
To resolve the issue, you might change the declaration of A_Star_SolveUnweighted to be int *A_Star_SolveUnweighted(bool (*graph)[4]) or int *A_Star_SolveUnweighted(size_t Columns, bool (*graph)[Columns]).
bool graph[5][4] is an array of arrays. It's represented by, effectively, 20 Booleans in a row (possibly with some padding). It can be decayed into bool(*)[4], which is a pointer to some number of collections of four Booleans in a row.
On the other hand, bool** is a pointer to one or more pointers to one or more Booleans. There's an additional layer of indirection, in that the first array contains pointers to the second, as opposed to simply containing the second directly. At the top layer, it's easy to convert from T[] to T*, since that's effectively just taking an address, but if it's not the top layer of the array, then it would require iterating over the array to change all of the constituents. And that's more or less what you need; an array of pointers.
bool** graph = calloc(5, sizeof(bool*))
for (int i = 0; i < 5; i++) {
graph[i] = calloc(4, sizeof(bool));
// Initialize graph[i] here ...
}
Then you'll need to free it all at the end.
for (int i = 0; i < 5; i++) {
free(graph[i]);
}
free(graph);
Of course, if you have control over the signature of the target function, you may consider just changing it to take a bool*. Then you can work with one-dimensional arrays and just keep track of the number of "rows" and "columns", which will better align your memory and avoid issues like this.
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.
I would like to define a custom structure that contains two dynamically allocatable integer arrays a and b. In order to allocate memory for the arrays and initialise arrays with values I have written a "constructor" function initp. My approach is presented below.
A custom structure called pair:
typedef struct {
...
int l; // length of compositions
int k; // no. of elements in compositions
int *a; // composition 1
int *b; // composition 2
} pair;
A function to initialise custom structure:
int initp(..., int l, int k, int a[], int b[], pair *f) {
...
f->l = l;
f->k = k;
// allocate composition arrays
f->a = (int *) calloc(l, sizeof(int));
f->b = (int *) calloc(l, sizeof(int));
// initialise composition arrays
for (int i = 0; i < k; i++) {
f->a[i] = a[i];
f->b[i] = b[i];
}
}
A function call in the main program:
// initialise pairs
pair f1, f2;
initp(..., 10, 2, (int[]){3, 4}, (int[]){7, 6}, &f1);
initp(..., 10, 1, (int[]){4}, (int[]){9}, &f2);
I'm on a mission to write an "elegant" code. Therefore, the questions I have are:
Is it possible to avoid specifying the no. of elements in arrays a and b passed to the initp? This is the parameter k. In the above examples it is 2 and 1.
Is it possible to avoid "explicit" casting with (int[]) in the function call?
Please let me know, if you have general comments and criticism on improving the quality of the code.
Is it possible to avoid specifying the no. of elements in arrays a and b passed to the initp?
No.
Alternative: Create a macro INITP(l, a, b, f) with macro magic determines the a, b are truly arrays, their array element counts, insure their counts are equal and then calls initp().
I am not fan of this approach, but it is do-able - with limitations.
Note: for size information, consider size_t vs. int.
Is it possible to avoid "explicit" casting with (int[]) in the function call?
With (int[]){3, 4}, (int[]) is not a cast. It is simply the form of a compound literal and is required to form one.
if you have general comments and criticism on improving the quality of the code.
For working code, consider Code review for a deeper review.
I'd assign each array in turn - usually as fast or faster than interlacing.
memcpy(f->a, a, sizeof f->a[0] * k);
memcpy(f->b, b, sizeof f->b[0] * k);
Handle allocation failures.
Create a initp() companion like void uninitp(pair *f).
Improve allocation for clarity, review and maintenance.
// f->a = (int *) calloc(l, sizeof(int));
f->a = calloc(l, sizeof f->a[0]);
const, restrict considerations.
Hmmm, this is getting to be too full a review for here, so will end now.
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.