I have a
bool array[size][size]
and want to pass a pointer of it to a function to change its value.
void change_to_true(???, int i, int j) { // don't know what type it should be
array[i][j] = 1;
}
How do I create a pointer of the array, and how should I pass the pointer to the function so
that I can change its value? BTW it's c code.
Thanks
Edit:
I tried
static bool array[size][size];
bool (*array_t)[index] = array;
void change_to_true(bool array, int i, int j);
Compiler told me subscripted value is neither array nor pointer
I tried to change the type definition of the function parameter from bool array to bool* array, still not work.
I also tried bool (*array_t)[][size] = &array and bool (*array_t)[size][size] = &array; for the pointer, still not work.
Also since the size of the array is decided during the runtime, I can't have a enum or a global array defined that way.
This should work:
void change_to_true(bool** array, int i, int j)
Simple solution — but no pointer to 2D array
The function should be simply:
#include <stdbool.h>
enum { size = 24 };
extern void change_to_true(bool array[][size], int i, int j);
void change_to_true(bool array[][size], int i, int j)
{
array[i][j] = true;
}
int main(void)
{
bool array[size][size];
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
array[i][j] = false;
change_to_true(array, i, j);
}
}
}
I'm assuming, of course, that you have a C99 or C2011 compiler. If you're stuck with C89, then you'll have to provide definitions for bool and true; the rest does not need to change. I'm not convinced the function call is worth it, compared with the assignment of false.
Solution using pointer to 2D array
Note that the code above does not, strictly, create a pointer to a 2D array. If you are really, really sure that's what you want, then the notation changes:
#include <stdbool.h>
enum { size = 24 };
extern void change_to_true(bool (*array)[][size], int i, int j);
void change_to_true(bool (*array)[][size], int i, int j)
{
(*array)[i][j] = true;
}
int main(void)
{
bool array[size][size];
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
array[i][j] = false;
change_to_true(&array, i, j);
}
}
}
There's no benefit to using a formal 'pointer to array' that I can think of, though — not in this context.
Solution using C99 variable length arrays
In C99, you can also use a VLA — variable length array — like this:
#include <stdbool.h>
extern void change_to_true(int size, bool array[][size], int i, int j);
void change_to_true(int size, bool array[][size], int i, int j)
{
array[i][j] = true;
}
int main(void)
{
for (int size = 2; size < 10; size++)
{
bool array[size][size];
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
array[i][j] = false;
change_to_true(size, array, i, j);
}
}
}
}
Note that the size must precede the array declaration in the function declaration. And yes, you also write this with pointer to array notation (actually, I edited the pointer to array notation code first, then realized that I wanted the simpler version).
Which to use?
Unless you have compelling reasons not mentioned in the question, the first version is the code to use.
This should answer you question.
In short, you make a pointer to the first element and then pass it around.
[EDIT] C supports bool since C 99
Besides that, by declaring it that way, the actual array is a pointer to a memory zone with all the size^2 instances. This means that you can pass array to change it in the function, and in your header declare that you are receiving bool array[][].
That way it should work.
Related
This question already has answers here:
Why can't we use double pointer to represent two dimensional arrays?
(6 answers)
Closed 13 days ago.
I wrote this program that is supposed to sort NxN array. It gets compiled but doesn't work because the pointer type is incompatible.
I just need help with the pointers as argument. I get incompatible pointer type warning for both functions swap and dblArraySort. Any idea why is that ?
thanks in advance !
#include <stdio.h>
#include <stdlib.h>
void
swap(int **a, int **b)
{
int temp;
temp = **a;
**a = **b;
**b = temp;
}
void
dblArraySort(int **dblArray, int arrLen)
{
int chkIndex;
int i, j, k;
for (i = 0; i < arrLen; i++) {
if ((i + 1) % 2 == 0) {
for (j = 0; j < arrLen; j++) {
chkIndex = dblArray[i][j];
for (k = 1; k + j < arrLen; k++)
if (chkIndex < dblArray[i][k + j])
swap(&dblArray[i][j], &dblArray[i][k + j]);
else
continue;
}
} else {
for (j = 0; j < arrLen; j++) {
chkIndex = dblArray[i][j];
for (k = 1; k + j < arrLen; k++)
if (chkIndex >= dblArray[i][k + j])
swap(&dblArray[i][j], &dblArray[i][k + j]);
else
continue;
}
}
}
}
int
main()
{
unsigned int arrayLength;
printf("Provide array size: \n");
scanf("%d", &arrayLength);
int doubleArray[arrayLength][arrayLength];
for (int i = 0; i < arrayLength; i++) {
for (int j = 0; j < arrayLength; j++) {
scanf("%d", &doubleArray[i][j]);
}
}
dblArraySort(doubleArray, arrayLength);
for (int i = 0; i < arrayLength; i++) {
for (int j = 0; j < arrayLength; j++) {
printf("%d ", doubleArray[i][j]);
}
printf("\n");
}
return 0;
}
I tried the code mentioned above
Arrays in C can be confusing. The thing you need to worry about is element type.
The element type of int ** dblArray is int *. In other words, dblArray is an array of int *s.
However, the element type of int doubleArray[arrayLength][arrayLength] is int row_type[arrayLength]. That is not an int *, that is an array, which is a totally different thing.
Moreover, when you use an array⟶pointer conversion, as happens when you say:
dblArraySort(doubleArray, arrayLength); // doubleArray is converted to a pointer
You get a pointer to the array, which in this case is a pointer to the innermost element type, an int — which is also not an int *.
tl;dr: You are trying to pass an array of array of int to a function taking an array of pointer to int. That won’t work.
I would like to comment on your variable naming as well. When you say “double” or “dbl”, as in doubleArray and dblArray the very first thing people will think is that you are handling a linear array of type double, which is also not what the array is.
You have there a two-dimensional array. Not a “double” array. Common naming for such thing would be array2D or matrix.
To make it work you need either C11, which allows you to pass a VLA as:
void sort_array2D( size_t rows, size_t columns, int array[rows][columns] )
{
...
int value = array[i][j];
...
}
int main(void)
{
int array2D[Array_Length][Array_Length];
...
sort_array2D( Array_Length, Array_Length, array2D );
Or you need to simply assume you must compute the index manually. A little function will help:
size_t index2D( size_t rows, size_t columns, size_t r, size_t c )
{
(void)rows; // (quiet the compiler about not using this argument)
return r * columns + c;
}
Then you can write your function as:
void sort_array2D( int * array, size_t rows, size_t columns )
{
...
int value = array[index2D( rows, columns, i, j )];
...
}
int main(void)
{
int array2D[Array_Length][Array_Length];
...
sort_array2D( (int *)array2D, Array_Length, Array_Length );
I haven’t bothered to analyze your sort function. It doesn’t look right to me, but honestly, I’ve barely glanced at it. Calling a value from the array chkIndex looks fishy, since the values of the array are not indices per se, at least not in the context of sorting them.
Remember, when messing with arrays in C you need to keep strict care to not mix up the type of the elements. (Or the types of things in general, whether syntactic or conceptual.)
I'm trying to build a Boolean function to check if two unsorted arrays have the same elements. But every time I try to debug the program,I keep getting an error "Expression must have a pointer to object type". I have tried everything. Nothing seem to be working. Can anyone please let me know what I am doing wrong?
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include<stdbool.h>
bool haveSameElems(arr1, arr2, size);
void main()
{
int size;
scanf("%d", &size);
int* arr1 = (int*)calloc(size, sizeof(int));
for (int i = 0; i < size; i++)
{
scanf("%d ", &arr1[i]);
}
int* arr2 = (int*)calloc(size, sizeof(int));
for (int i = 0; i < size; i++)
{
scanf("%d ", &arr2[i]);
}
bool ans = haveSameElems(arr1, arr2, size);
printf("%s", ans ? "true" : "false");
}
bool haveSameElems(arr1, arr2, size)
{
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
if (arr1[i] == arr2[j]) // I keep getting the error here
{
return true;
}
}
}
}
Your function declaration bool haveSameElems(arr1, arr2, size) is implicitly the same as bool haveSameElems(int arr1, int arr2, int size), per Frankie_C. To use arr1 and arr2 as arrays, they must be declared as pointers: bool haveSameElems(int *arr1, int *arr2, int size). So you need to add those two asterisks in both the function declaration at the top of your code and in the function definition it corresponds to. It’s good practice always explicitly to write types and not rely on the old K&R style implicit int types Frankie_C wrote about in his comment. You can read more about it in the bottom box here and in the “subscript” section here.
You also need a return false at the end of haveSameElems, and main must return type int if you’re using an older C complier. See here.
I want foo() not to modify the array. So I declared array in foo() as const
If I compile this code, compiler is complaining:
#include <stdio.h>
void foo(const int arr[5][5])
{
int i,j;
for( i = 0; i < 5; i++)
{
for( j = 0; j < 5; j++)
{
printf("%d\n", arr[i][j]);
}
}
}
int main()
{
int val = 0;
int i,j;
int arr[5][5];
for( i = 0; i < 5; i++)
{
for( j = 0; j < 5; j++)
{
arr[i][j] = val++;
}
}
foo(arr);
}
The warning is:
allocate.c: In function 'main':
allocate.c:26:9: warning: passing argument 1 of 'foo' from incompatible pointer type
foo(arr);
^
allocate.c:3:6: note: expected 'const int (*)[5]' but argument is of type 'int (*)[5]'
void foo(const int arr[5][5])
^
How else can I declare formal parameter as constant?
I assume that you do not want foo() to be able to modify the array in the interest of encapsulation.
As you are likely aware, in C arrays are passed into functions by reference.
Because of this, any changes that foo() makes to the values array will be propagated back to the variable in main(). This is not in the interest of encapsulation.
const will not prevent foo() from modifying the array
The C keyword const means that something is not modifiable. A const pointer cannot modify the address that it points to. The value(s) at that address can still be modified.
In c, By default, you cannot assign a new pointer value to an array name. There is no need for const. Similar to a const pointer, the values in this array can still be modified. Encapsulation problem is not solved.
To encapsulate foo() from your main() function, put your array in a struct. Structs are passed by value and so foo() will receive a copy of the data. As it has a copy, foo() will not be able to alter the original data. Your functions are encapsulated.
Solution (that works!):
#include <stdio.h>
typedef struct
{
int arr[5][5];
} stct;
void foo(const stct bar)
{
int i,j;
for( i = 0; i < 5; i++)
{
for( j = 0; j < 5; j++)
{
printf("%d\n", bar.arr[i][j]);
}
}
}
int main()
{
int val = 0;
int i,j;
stct bar;
for( i = 0; i < 5; i++)
{
for( j = 0; j < 5; j++)
{
bar.arr[i][j] = val++;
}
}
foo(bar);
}
I put const in the foo() definition because you asked how you could declare the formal parameter as a constant. It works but is not needed.
void foo(stct bar)
Removing the const will not break the function.
How do I feed an array of pointers as an argument to a function?
In the code below, if I want my function f to take an array of pointers int *x[], how should I declare x in main() and feed it as argument to f?
void f(int *x[]){
int data[5] = {1,2,3,4,5};
int k;
for(k=0; k<5; k++){
x[k] = &(data[k]);
}
}
int main(){
int *(x[]), k, l=5;
f(x); // this does not work
for(k=0; k<l; k++){
printf("x[%d] = %d\n", k, *x[k]);
}
}
return 0;
}
Writing f(x) does not work, and neither does f(x[]) or f(x[5]).
In fact, the declaration int *(x[]) is already not recognized by my compiler, while I thought that one could declare an array of pointers without specifying the length of the array.
In main, change
int *(x[])
to
int *x[SIZE]; // SIZE is array size
Note that, you can't declare a zero size array in C except when it is a last member of a structure.
After all, your code will invoke undefined behavior because the variable data is an automatic local variable and will not exist after function returns.
You may want this:
void f(int *x[]){
int *data = malloc(5*sizeof(int);
int temp[5] = {1,2,3,4,5};
memcpy(data, temp, 5*sizeof(int));
int k;
for(k=0; k<5; k++){
x[k] = &(data[k]);
}
}
First of all your code has no sense because you are trying to fill an array of pointers that will point to local variables. That is after exiti8ng the function all pointers will be invalid because original objects will be already destroyed.
The code could have a sense if the array in the function would have static storage duration
void f(int *x[]){
static int data[5] = {1,2,3,4,5};
int k;
for(k=0; k<5; k++){
x[k] = &(data[k]);
}
}
In main array x should be defined at least as
int * x[5];
int main(){
int * x[5], k;
f(x);
for ( k=0; k < 5; k++ ){
printf("x[%d] = %d\n", k, *x[k]);
}
}
return 0;
}
An alternate way to declare an array of pointer as a parameter is to use a pointer of pointer
void f(int **x, int size){
//code
}
However, you'll have to pass the size as a second argument if you want to avoid an overflow.
To call the code you'll just have to do something like this :
int *a[] = { NULL, NULL, NULL};
f(a, 3);
I am trying to pass a 2D array of variable size to a function to print it. I know how it's done when one has fixed sized arrays. But how does one do this with variable sized arrays? Here is some code that'll give you an idea what I am trying to do:
void print_grid(char (*g)[9], int size) // the array subscript (9 here) be variable
{
int i, j;
for (i=0; i<size; i++)
{
for (j=0; j<size; j++)
printf("%c ", g[i][j]);
printf("\n");
}
}
I'll call this function using the following code:
char a[3][3], b[9][9];
// assign a, b
print_grid(a, 3);
print_grid(b, 9);
Is there any way to do this without allocating any dynamic memory in print_grid()?
void print_grid(int rows, int cols, char g[][cols]) { ... }
void print_grid(char *g, int size)
{
int i, j;
for( i = 0; i < size; i++)
for( j = 0; j < size; j++)
{
printf("%c ", *(g + i*size + j));
printf("\n");
}
}
print_grid(a, 3);
When you pass an array in C it is always passed by reference, i.e. through a pointer. The type of this pointer is not pointer-to-array, but pointer-to-first-element. For example, the code generator will handle void f(char[][10]) as if it where void f(char*). The array dimensions are lost. The parser, however, will complain if it sees f declared twice so.
The motivation behind C was to have a powerful and portable assembler, not a new programming language. Multidimensional arrays are logical constructs that do not exist in the machine. Arrays are a way of thinking.
To pass the dimensions of arrays to functions C programmers traditionally use structs:
typedef struct array_tag {
int count;
char data[1]; /* actually data[count] */
} ARRAY;
typedef struct grid_tag {
int rows, columns;
char grid[1][1]; /* actually grid[rows][columns] */
} GRID;
void f(ARRAY* x)
{
int i;
for (i = 0; i < x->count; ++i) {
char c = x->data[i];
}
}
void g(GRID* x)
{
int i, j;
for (i = 0; i < x->rows; ++i)
for (j = 0; j < x->columns; ++j) {
char c = x->grid[i][j];
}
}
void h()
{
{
const int len = 100;
ARRAY* x = (ARRAY*) malloc(sizeof(ARRAY) + len * sizeof(char));
x->count = len;
f(x);
}
{
const int rows = 2, cols = 3;
GRID* x = (GRID*) malloc(sizeof(GRID) + rows * cols * sizeof(char));
x->rows = rows;
x->columns = cols;
g(x);
}
}
Yes, the malloc expression in this example allocates few bytes too much. Therefore the GNU-compiler supports arrays of zero length for a long time, which are not allowed in C90.
C99 has gone one step further with flexible arrays. From ISO/IEC 9899:1999, Section 6.7.2.1, paragraph 16: "As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member." In C99 the ARRAY and GRID types can be declared as:
typedef struct array_tag {
int count;
char data[]; /* actually data[count] */
} ARRAY;
typedef struct grid_tag {
int rows, columns;
char grid[][1]; /* actually grid[rows][columns] */
} GRID;
and you can
assert(1*sizeof(int) == sizeof(ARRAY));
assert(2*sizeof(int) == sizeof(GRID));
Many people think C arrays are quirky. But they're also an elegant solution which allows the declaration of indefinitely complex arrays. It is known as the "K&R array equation". A good explanation can be found here.
Hope this helps.
This one does it, assuming a squared grid:
void print_grid(void* g, int size)
{
char* my = (char*) g;
int i, j;
for (i=0; i<size; i++)
{
for (j=0; j<size; j++)
printf("%c ", my[i+j]);
printf("\n");
}
}
If you want to use non-squared grids, replace size with a rows and columns parameter and adjust counting: i<rows and j<columns.