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.
Related
This code has to copy one array to another via void copy function. But I don't understand why it doesn't work.
#include <stdio.h>
void copy(int func_array_1[], int func_array_2[], int size) {
for (int i = 0; i < size; i++)
func_array_1[i] = func_array_2[i];
}
int main() {
int size = 0;
int array[10] = { 0 };
int copy_array[10] = { 0 };
printf("Input the number of elements to be stored in the array :");
scanf("%d", &size);
for (int i = 0; i < size; i++)
scanf("%d", &array[i]);
copy(array, copy_array, size);
for (int i = 0; i < size; i++)
printf("%d", copy_array[i]);
return 0;
}
It gives first defined array members which are all zero.
for (int i = 0; i < size; i++)
func_array_1[i] = func_array_2[i];
You're copying from the zero-initialized array to the one you actually want to copy to.
So just change the loop body to:
func_array_2[i] = func_array_1[i];
Using const and / or more purposeful naming could've prevented your error.
You have a typo in the function
for (int i = 0; i < size; i++)
func_array_1[i] = func_array_2[i];
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
As the function is called like
copy(array, copy_array, size);
you have to write
for (int i = 0; i < size; i++)
func_array_2[i] = func_array_1[i];
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
The reason of the typo is a bad function declaration. The function should be declared at least like
void copy( const int func_array_1[], int func_array_2[], int size);
That is the array that is not being changed within the function should be declared with the qualifier const.
Instead of the for loop you could use the standard function memcpy declared in the header <string.h> as for example
memcpy( func_array_2, func_array_1, size * sizeof( int ) );
Pay attention to that you need to check that the entered value of the variable size is not greater than 10.
Consider the following code:
int main(void) {
int *x[5];
for(int i = 0; i < 5; i++) {
x[i] = malloc(sizeof(int) * 5);
}
for(int i = 0; i < 5; i++) {
for(int j = 0; j < 5; j++) {
x[i][j] = i * j;
}
}
modify(x, 5, 5);
return 0;
}
Which of the implementations of method modify below set all elements of the matrix x to zero?
void modify(int **x, int m, int n) {
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
x[i][j] = 0;
}
}
}
void modify(int *x[], int m, int n) {
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
x[i][j] = 0;
}
}
}
void modify(int x[5][5], int m, int n) {
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
x[i][j] = 0;
}
}
}
I'm quite confused about why the third option is not correct. Is there a difference between passing an array located in stack and an array located in heap?
The compiler gives a pretty good clue:
~$ gcc mat.c
mat.c: In function ‘main’:
mat.c:22:12: warning: passing argument 1 of ‘modify’ from incompatible pointer type [-Wincompatible-pointer-types]
modify(x, 5, 5);
^
mat.c:3:17: note: expected ‘int (*)[5]’ but argument is of type ‘int **’
void modify(int x[5][5], int m, int n) {
~~~~^~~~~~~
The declaration int x[5][5] declares an array of arrays. That's something completely different from int *x[5]; which declares an array of pointers. Fun fact: Add parenthesis like this int (*x)[5] and you will instead get a pointer to an int array of size 5. Here is a good site that translates C declarations to English: https://cdecl.org/
Is there a difference between passing an array located in stack and an array located in heap?
Dynamically allocated memory usually ends up on the heap, while the rest usually goes to the stack. However, this is just an implementation detail, and nothing in the C standard requires either a heap or a stack to exist at all.
When you're passing an array to a function it will decay to a pointer to it's first element. The function will have no idea of where the data is (hmmm, well since the pointer has the actual address it does, but it does not know about heap or stack) or how it was allocated. So consider this code snippet:
void setToZero(int * arr, int size) {
for(int i=0; i<size; i++) arr[i] = 0;
}
The function will have EXACTLY the same effect for both x and y:
int x[10];
int *y = malloc(10 * sizeof *y);
setToZero(x);
setToZero(y);
It may help to recall that there are no arrays in C, only pointers and blocks of memory. The rest is compiler fakery.
Your main program allocates a block of memory for 5 *int pointers (called x) on the stack and 5 blocks of 5 ints on the heap. It calls the function with a pointer to the beginning of x, and relies on the function to perform the correct pointer arithmetic to access the other blocks correctly.
The first two functions are equivalent in this case (that's not always true), and the pointer arithmetic correctly matches the allocations. The third function incorrectly performs pointer arithmetic to address 25 ints arranged 5x5, so the first 5 stores overwrite a *int by an int and the 6th access is out of bounds (assuming int and *int are the same size).
I've explained it this way to emphasise the necessity to understand the relationship between arrays and pointer arithmetic in C. If you really understand this you won't need to ask questions like this again.
I have this function :
void foo( char tab[8][8] )
I want this function to edit the values of the tab array, so i tried theses syntax :
void foo( char *(*tab)[8][8] )
void foo( char *(tab)[8][8] )
void foo( char **tab )
And a LOT of others. I always get a fail while compiling, like this one :
error: cannot convert 'char ()[8][8]' to 'char (*)[8][8]' for argument '1' (...)
So, my quesiton is : how to create and pass to a function a pointer to a 2D array ?
Thanks.
This time try to declare your function as
void foo( char (*tab)[8] );
and call it as
foo(point);
Note that in this case you need to pass only array name as it decays to pointer when passed to a function (some exceptions are there). After decay it is of type char (*)[8].
You can do it also by declaring
void foo( char (*tab)[8][8] );
and call it as
foo(&point);
In this case notice that I passed &poinnt, i.e, address of the entire array which is of type char (*)[8][8].
Sample:
void foo(char (*tab)[8][8])
{
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 68j++)
{
scanf("%d", &(*tab)[i][j]);
}
}
}
With an array, you can always modify the data in the function because what is passed is a pointer (in the absence of const qualifiers, of course). That is, you could write:
void foo(char tab[8][8])
{
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
tab[i][j] = (x + y) % 2 : 'X' : 'O';
}
}
And call it:
void calling_func(void)
{
char board[8][8];
foo(board);
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
putchar(tab[i][j]);
putchar('\n');
}
}
You can get the error messages you were seeing if you write:
foo(&board);
That passes a pointer to an array to the function. For that to work, you have to rewrite the function as:
void foo(char (*tab)[8][8])
{
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
(*tab)[i][j] = (x + y) % 2 : 'X' : 'O';
}
}
However, this is seldom the correct way to write the code. Use the first alternative until this is forced upon you (which probably won't be this year — I don't recall having to use a pointer to an array except to answer questions on SO, but maybe it was such a ghastly experience that I have forgotten all about it).
I keep having these errors with my array. How am I supposed to return a 2d array of unknown size? I'm trying to manipulate a pbm image by converting it into an array and then doing array manipulations. Here is my code
typedef struct
{
unsigned char blackWhite;
} PBMPixel;
typedef struct
{
int x, y;
PBMPixel *data;
} PBMImage;
This is defined in my header file which hasn't given me any issues. Later on, I have this:
char * ArrayCreate(PBMImage *img, int x, int y)
{
char ManipArray[x][y];
int i = 0;
int j= 0;
for( i=0; i < x; i++)
{
for ( j=0; j < y; j++)
{
char ManipArray[i][j] = img->data[(i*(j+1)+j)].blackWhite;
j++;
}
i++;
}
return ManipArray;
}
These are the errors I keep getting back:
P-MFunctionHolder.c: In function 'ArrayCreate':
P-MFunctionHolder.c:171:4: error: variable-sized object may not be initialized
P-MFunctionHolder.c:176:2: warning: return from incompatible pointer type [enabled by default]
P-MFunctionHolder.c:176:2: warning: function returns address of local variable [enabled by default]
I'm using MinGW and Windows 8 if that helps, but I doubt that is the problem. I also didn't post the entire code because that's about 260 lines and gives a bunch of the exact same errors.
How am I supposed to return a 2d array of unknown size?
A typical solution to this problem is to allocate memory on the heap to a pointer, implicitly passing the responsibility for deallocation to the caller.
For example:
char * ArrayCreate(PBMImage *img, int x, int y)
{
char *const ManipArray = malloc(x * y * sizeof(char));
int i = 0;
int j= 0;
for( i=0; i < x; i++)
{
for ( j=0; j < y; j++)
{
ManipArray[i * y + j] = img->data[(i*(j+1)+j)].blackWhite;
j++;
}
i++;
}
return ManipArray;
}
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.