How can I get the size of the array in an 3D matrix? - c

Consider the following 3D matrix
char ShapesArray[2] = {
(char[4][4]){
{ 0, 1, 0, 0 }, //I
{ 0, 1, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 1, 0, 0 }
},
(char[3][3]){
{ 0, 1, 0 }, //J
{ 0, 1, 0 },
{ 1, 1, 0 }
}
};
by using
int i = sizeof(ShapesArray[0]));
I would expect 16 as result.
But the result in this case is: 1
What am I missing here?

char ShapesArray[2] is an array of two chars. Hence the first element's size is 1. Turn on the compiler warnings:
<source>: In function 'main':
<source>:4:2: error: initialization of 'char' from 'char (*)[4]' makes integer from pointer without a cast [-Werror=int-conversion]
4 | (char[4][4]) {
| ^
<source>:4:2: note: (near initialization for 'ShapesArray[0]')
<source>:10:2: error: initialization of 'char' from 'char (*)[3]' makes integer from pointer without a cast [-Werror=int-conversion]
10 | (char[3][3]) {
| ^
<source>:10:2: note: (near initialization for 'ShapesArray[1]')
cc1: all warnings being treated as errors
Compiler returned: 1
What the compiler is saying is that you're initializing chars with char (*)[4] and char (*)[3] which is wrong. It wouldn't even compile with a C++ compiler.

Related

Struct initialization with char array outside a function

I have following typedef struct:
typedef struct
{
E_Menus Menu; // E_Menus is a typedef enum
char *MenuStr[200];
int CurrentItem;
int ItemAmount;
int ItemGap;
int StartItemGap;
} T_Menu;
I want to initialize a struct of type T_Menu as a module variable (not local inside a function) as following:
char mBootMenuStr[] = {"some text"};
T_Menu mBootMenu = {eUI_BootMenu, mBootMenuStr, 1, 2, 1, 2};
But MenuStr makes me struggle. I get 2 warnings:
1 initialization of 'char *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
2 missing braces around initializer [-Wmissing-braces]
MenuStr should be a string with size 200 -> Means, the string has 200 chars.
When I remove MenuStr it builds without warnings.
What did I miss? Is it impossible to do this outside a function?
Reproducable example:
typedef enum
{
eUI_BootMenu,
eUI_LoginMenu,
eUI_HomeMenu,
} E_Menus;
typedef struct
{
E_Menus Menu;
char *MenuStr[200];
int CurrentItem;
int ItemAmount;
int ItemGap;
int StartItemGap;
} T_Menu;
char mBootMenuStr[] = {"some text"};
T_Menu mBootMenu = {eUI_BootMenu, mBootMenuStr, 1, 2, 1, 2};
Thanks for help in advance.
char *MenuStr[200]; is an array of 200 pointer-to-char.
The initializer in
T_Menu mBootMenu = {eUI_BootMenu, mBootMenuStr, 1, 2, 1, 2};
is treating mBootMenuStr and each expression after it as elements to initialize that array. The integer values of 1 and 2 are being used to initialize elements of type char *, hence the warning.
GCC gives a more detailed diagnostic:
ex.c:21:49: warning: initialization of ‘char *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
21 | T_Menu mBootMenu = {eUI_BootMenu, mBootMenuStr, 1, 2, 1, 2};
| ^
ex.c:21:49: note: (near initialization for ‘mBootMenu.MenuStr[1]’)
ex.c:21:52: warning: initialization of ‘char *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
21 | T_Menu mBootMenu = {eUI_BootMenu, mBootMenuStr, 1, 2, 1, 2};
| ^
ex.c:21:52: note: (near initialization for ‘mBootMenu.MenuStr[2]’)
ex.c:21:55: warning: initialization of ‘char *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
21 | T_Menu mBootMenu = {eUI_BootMenu, mBootMenuStr, 1, 2, 1, 2};
| ^
ex.c:21:55: note: (near initialization for ‘mBootMenu.MenuStr[3]’)
ex.c:21:58: warning: initialization of ‘char *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
21 | T_Menu mBootMenu = {eUI_BootMenu, mBootMenuStr, 1, 2, 1, 2};
This warning can be resolved by placing braces around mBootMenuStr, making it the sole initializing element for the MenuStr member of the structure:
T_Menu mBootMenu = {eUI_BootMenu, {mBootMenuStr}, 1, 2, 1, 2};
But it seems likely you simply wanted a string member, not an array of pointers, in the structure:
typedef struct
{
E_Menus Menu;
char MenuStr[200];
int CurrentItem;
int ItemAmount;
int ItemGap;
int StartItemGap;
} T_Menu;
T_Menu mBootMenu = {eUI_BootMenu, "some text", 1, 2, 1, 2};

How can I correct this code which let a pointer to point a greatest value by using double overlapped pointers?

In 6 integers array, I want to print the greatest value by using double overlapped pointers and one additional one function. There are three parameters (int array m, the counts of elements in m, double pointer pmax) in declared function. When I debug this code, it isn't worked. Maybe I think this problem related with the process of using parameters. Then What parts should I have to modify?
Here's the code.
#include<stdio.h>
void set_max_ptr(int m[], int size, int** pmax);
int main(void)
{
int m[6] = { 5,6,1,3,7,9 };
int* pmax;
set_max_ptr(m, 6, pmax);
printf("the greatest value is %d \n", *pmax);
return 0;
}
void set_max_ptr(int m[], int size, int** pmax)
{
*pmax = &m[0];
for (int i = 0; i < size; i++)
{
if (*(m+i) > **pmax)
**pmax = *(m+i);
}
}
compiling error
1 warning generated.
zsh: segmentation fault "/Users/cactual/"pointgreatestvalue
You need to pass the address of the pointer:
set_max_ptr(m, 6, pmax);
should be
set_max_ptr(m, 6, &pmax);
and m + i is already a pointer, do not dereference, to alter the passed pointer you want:
*pmax = m + i;
instead of
**pmax = *(m+i);
compiling error
1 warning generated. zsh: segmentation fault "/Users/cactual/"pointgreatestvalue
this is a runtime error, not a compiling error
compiling, with warnings enabled results in:
untitled.c: In function ‘main’:
untitled.c:8:19: warning: passing argument 3 of ‘set_max_ptr’ from incompatible pointer type [-Wincompatible-pointer-types]
8 | set_max_ptr(m, 6, pmax);
| ^~~~
| |
| int *
untitled.c:2:43: note: expected ‘int **’ but argument is of type ‘int *’
2 | void set_max_ptr(int m[], int size, int** pmax);
| ~~~~~~^~~~
untitled.c:8:1: warning: ‘pmax’ is used uninitialized in this function [-Wuninitialized]
8 | set_max_ptr(m, 6, pmax);
| ^~~~~~~~~~~~~~~~~~~~~~~
Please post code that cleanly compiles

warning: assignment to int ** from incompatible pointer type const int (*)[3]

I have a problem assigning the pointer of a matrix to a double pointer, which will be used next, as follow:
const int COLOR_MAP_INDIA[16][3] = {{ 140, 67, 46 },{ 0, 0, 255 },{ 255, 100, 0 },{ 0, 255, 123 },{ 164, 75, 155 },{ 101, 174, 255 },{ 118, 254, 172 },{ 60, 91, 112 },{ 255, 255, 0 },{ 255, 255, 125 },{ 255, 0, 255 },{ 100, 0, 255 },{ 0, 172, 254 },{ 0, 255, 0 },{ 171, 175, 80 },{ 101, 193, 60 }};
int main(int argc, char *argv[]){
int **COLOR_MAP;
COLOR_MAP= COLOR_MAP_INDIA;
}
the compiler says:
warning: assignment to int ** from incompatible pointer type const int
(*)[3]
What's wrong ?
warning: assignment to int ** from incompatible pointer type const int (*)[3]
Your compiler is pretty much telling you everything that is wrong. What you need to know is that a pointer to pointer (which, in your case, is COLOR_MAP) is not equal to a pointer to a one dimensional array of 3 integers (COLOR_MAP_INDIA in this case).
Essentially, you might want to think what difference does it make when both of them are pointers. BUT the difference comes when you try to access elements around that pointer with pointer arithmetic.
When you write:
COLOR_MAP_INDIA
you mean that it is a pointer to a 1D array containing 3 integers (the memory address of { 140, 67, 46 }, which, in fact, is the address of 140). So, when you do something like,
COLOR_MAP_INDIA + 1
you would now point to the very next 1D array of 3 integers (the memory address of { 0, 0, 255 }, the first 0 in this case) and NOT the second element in the first array.
Pointers are strongly typed because you can perform pointer arithmetic on them and each such arithmetic doesn't necessarily mean an addition/subtraction of 1.
There is segmentation fault when you even only read via COLOR_MAP.
It is defined as containing pointer(s) (to value(s)), not values in rows of three.
Where COLOR_MAP has the values 140, 67,, it expects the address of the first row.
The abstract type indicated by the warning can be used:
int (*COLOR_MAP)[3];
COLOR_MAP= COLOR_MAP_INDIA;
printf("%d\n", COLOR_MAP[2][1]);
The const mismatch is the same, just less dramatic.
Array-of-pointers version
An extra layer of pointers can be used to give names to these RGB triplets aka colors:
int orange[] = {140,67,46};
int blue[] = {0,0,255};
int greenblue[] = {0,255,123};
int purple[] = {200,0, 200};
int *INDIA[] = {orange, greenblue, blue, purple};
int *INDIA_2[] = {greenblue, orange, purple, blue};
int main(int argc, char *argv[]){
int **MAP;
MAP = INDIA;
printf("%d\n", MAP[1][2]); // 123
MAP = INDIA_2;
printf("%d\n", MAP[1][2]); // 46
}
Quite a different approach, but the elements are accessed in the same way, as 2D-array MAP[1][2].
COLOR_MAP is defined as a pointer to a pointer to int, whereas COLOR_MAP_INDIA is an array of 16 arrays of 3 int. These types are incompatible. You should define COLOR_MAP as a pointer to an array of 3 int:
int (*COLOR_MAP)[3] = COLOR_MAP_INDIA;
Whether this pointer fits your needs depends on what you intend to do in the unpublished part of the code.

variable-sized object may not be initialized

So this section of code generates a huge amount of errors but it works when I have InputM[3][3] = blah
Why would this be. For reference, code:
int n = 3;
printf("%ld\n", n);
double InputM[n][n] = { { 2, 0, 1 }, { 3, 1, 2 }, { 5, 2, 5} };
Generates:
prog3.c: In function 'main':
prog3.c:47: error: variable-sized object may not be initialized
prog3.c:47: warning: excess elements in array initializer
prog3.c:47: warning: (near initialization for 'InputM[0]')
prog3.c:47: warning: excess elements in array initializer
prog3.c:47: warning: (near initialization for 'InputM[0]')
prog3.c:47: warning: excess elements in array initializer
prog3.c:47: warning: (near initialization for 'InputM[0]')
prog3.c:47: warning: excess elements in array initializer
prog3.c:47: warning: (near initialization for 'InputM')
prog3.c:47: warning: excess elements in array initializer
prog3.c:47: warning: (near initialization for 'InputM[0]')
prog3.c:47: warning: excess elements in array initializer
prog3.c:47: warning: (near initialization for 'InputM[0]')
prog3.c:47: warning: excess elements in array initializer
prog3.c:47: warning: (near initialization for 'InputM[0]')
prog3.c:47: warning: excess elements in array initializer
prog3.c:47: warning: (near initialization for 'InputM')
prog3.c:47: warning: excess elements in array initializer
prog3.c:47: warning: (near initialization for 'InputM[0]')
prog3.c:47: warning: excess elements in array initializer
prog3.c:47: warning: (near initialization for 'InputM[0]')
prog3.c:47: warning: excess elements in array initializer
prog3.c:47: warning: (near initialization for 'InputM[0]')
prog3.c:47: warning: excess elements in array initializer
prog3.c:47: warning: (near initialization for 'InputM')
Compile-time, you compiler does not know how many elements are in your matrix. In C, you can dynamically allocate memory using malloc.
You could use a define to create a constant value:
#define N 3
int main()
{
double InputM[N][N] = { { 2, 0, 1 }, { 3, 1, 2 }, { 5, 2, 5} };
}
Or malloc:
int main()
{
int n = 3;
int idx;
int row;
int col;
double **inputM;
inputM = malloc(n * sizeof(double *));
for (idx = 0; idx != n; ++idx)
{
inputM[idx] = malloc(n * sizeof(double));
}
// initialise all entries on 0
for (row = 0; row != n; ++row)
{
for (row = 0; row != n; ++row)
{
inputM[row][col] = 0;
}
}
// add some entries
inputM[0][0] = 2;
inputM[1][1] = 1;
inputM[2][0] = 5;
}
In C99, variable-sized array can't be initialized, why ?
Because at the compile time, the compiler doesn't know the exact size of array, so you cannot initialize it.
n will be evaluated at runtime, then your array will be allocated on the stack-frame.

2D-Array manipulation through pointer parameter

I'm creating a set of functions that takes a pointer to a 2D-Array
and fills the array with some data
This is how I got it right now:
17 void m4identity(float *m[4][4]) {
18 *m = (float[4][4]) { { 1, 0, 0, 0 },
19 { 0, 1, 0, 0 },
20 { 0, 0, 1, 0 },
21 { 0, 0, 0, 1 } };
22 }
But unfortunately I get a compiler error:
linalg.c:18:7: error: incompatible types when assigning to type ‘float *[4]’ from type ‘float (*)[4]’
Questions:
What is the difference between (*)[4] and *[4]?
Is there a better way to do this?
I initially tried to return a pointer to the array created inside the function
but this threw another compiler error because it would be out of scope.
I also want to avoid allocating space for the array from within the function as
that would be hard to control.
What is the difference between (*)[4] and *[4]?
The [] declaration specifier has higher precedence, so float *arr[4] declares an array of 4 pointers-to-float, while float (*arr)[4] declares a pointer-to-array-of-4-float.
Is there a better way to do this?
Just let the array decay into a pointer and use assignments:
void m4identity(float m[4][4])
{
memset(m, 0, 4 * sizeof(m[0]));
for (int i = 0; i < 4; i++) {
m[i][i] = 1;
}
}

Resources