Can I access type int (*)[] with [][]? - c

coming from this question "What does (int (*)[])var1 stand for?" I tried to access the result of the cast like a multidimensional array. But I get following error: "assignment from incompatible pointer type" followed by a segmentation fault. I tried also some other variations, but none of them worked. How can I access the elements in var1 in the function example directly?
Thank you!
#include <stdlib.h>
int i(int n,int m,int var1[n][m]) {
var1[0][0]=5;
return var1[0][0];
}
int example() {
int *var1 = malloc(100);
// works
int var2;
var2 = i(10,10,(int (*)[])var1);
printf("var2=%i",var2);
//doesn't work I
int *var3;
var3=(int (*)[])var1; //"assignment from incompatible pointer type"
printf("var3[0][0]=%i",var3[0][0]);
//doesn't work II
int *var4;
var4=var1;
printf("var4[0][0]=%i",var4[0][0]); //" error: subscripted value is neither array nor pointer"
//doesn't work III
int **var5;
var5=var1;
printf("var5[0][0]=%i",var5[0][0]); // assignment from incompatible pointer type
return(1);
}
int main(){
int a;
a=example();
return(1);
}

int *var3;
var3 = (int (*)[])var1;
You are casting var1 which is already int* to int(*)[] (pointer to array of int) and assigning it to var3 which again is int*.
Just do
var3 = var1

Give this a shot. The following compiled with no warnings and ran under C99 (gcc -std=c99 -pedantic -Wall):
#include <stdio.h>
#include <stdlib.h>
int i(int n, int m, int (*var1)[m]) // C89 requires constant expression for
{ // array size
int j, k;
for (j = 0; j < n; j++)
for (k = 0; k < m; k++)
var1[j][k] = j*m+k;
return var1[0][0];
}
int example(void)
{
int *var1 = malloc(100 * sizeof *var1); // Thanks, Joseph!
int var2 = i(10, 10, (int (*)[10]) var1); // note the cast of var1 includes
// the array size
int (*var3)[10] = (int (*)[10]) var1; // note the type of var3
int j, k;
for (j = 0; j < 100; j++)
printf("var1[%2d] = %d\n", j, var1[j]);
for (j = 0; j < 10; j++)
for (k = 0; k < 10; k++)
printf("var3[%2d][%2d] = %d\n", j, k, var3[j][k]);
free(var1);
return var2;
}
int main(void)
{
int x = example();
printf("x = %d\n", x);
return 0;
}
First of all, note the types and the casts (most importantly, note how they match up). Note that I am specifying the size of the array dimension in the pointer-to-array casts. Also note that I declare var3 as a pointer to an array, not a simple pointer.

int example() {
int *var1 = malloc(100);
...
int *var3;
var3=var1;
printf("var3[0][0]=%i",var3[0][0]); //" error: subscripted value is neither array nor pointer"
return(1);
}
Here, var1 and var3 are both of type int*, which is roughly analogous to int[]. You've created a one-dimensional array and are trying to access them as a two-dimensional array. Change their type to int**, allocate the necessary memory, and that should fix your problem.

var3 needs to be a int** instead of an int*.
Edit
You're trying to use 2D array syntax where the actual data that you've created is actually a 1D array. You can use your i() function to give you the semantics you want but the data access needs to be converted to 1D indexing inside the function. Just make your function look like this:
int i(int n,int m,int* var1, int maxM) {
return var1[(maxM * n) + m];
}

Perhaps what you are looking for is:
int (*var1)[10][10] = malloc(sizeof *var1); // 400 bytes
i(10, 10, *var1);
printf("var1[0][0]=%i\n", (*var1)[0][0]);
Added: A complete code fragment for gcc might be:
#include <stdio.h>
#include <stdlib.h>
void i(int n, int m, int var1[][m]) { // n not needed
var1[0][0] = 5;
var1[1][2] = 6;
}
int main(void) {
int n = 10, m = 10;
int (*var1)[n][m] = malloc(sizeof *var1); // 400 bytes
i(n, m, *var1);
printf("var1[0][0]=%i\n",(*var1)[0][0]);
printf("var1[1][2]=%i\n",(*var1)[1][2]);
return 0;
}
For msvc, you'll need to make n and m constants, as in:
enum {n = 10, m = 10};
void i(int var1[][m]) {
var1[0][0] = 5;
var1[1][2] = 6;
}
int main(void) {
int (*var1)[n][m] = malloc(sizeof *var1);
i(*var1);
// ...
}

Related

how can i return an array from a function

How can I return an array from a function, I am trying to perform (3*3)*(3*1) matrix multiplication using this translation function and how can i get an array out of it.
#include <stdio.h>
#include <math.h>
int* translation(int x, int y, int tx, int ty) {
static int res[3][1] = {0}, xy[3][1] = {{x},{y},{1}};
int tm[3][3] = {{1,0, tx}, {0,1,ty}, {0,0,1}};
for (int i = 0; i<3; i++) {
for (int j = 0; j<3; j++) {
res[i][0] += tm[i][j]*xy[j][0];
}
}
return res;
}
int main()
{
int *arr[3][1];
arr = translation(5, 5);
printf("%d %d %d", arr[0][0], arr[0][1], arr[0][2]);
return 0;
}
"How can I return an array from a function"
You can't.
The language has no such concept.
You'll have to return something including the length to give the user of the function the information. In C the idiomatic approach is to supply a pointer to the function and to get a value (via that pointer) in return:
size_t no_idea;
void function(void *data, &no_idea);
As a user of this function you'd have to read no_idea before judging.
you question is missing a lot of information like what you want to do with your code, the variable named xy isn't defined anywhere in your code, and so on...
but for clarification, if your result matrix is of unknown size, you can wrap your array into a struct, if you don't know what is the struct, you can refer to this small tutorial about struct in c, so your struct maybe look like something like this:
typedef struct Array_t{
size_t arrSize_x;
size_t arrSize_y;
int **arr;
}Array_t;
where arr is your matrix of unknown size which will be created dynamically and arrSize_x, arrSize_y are your matrix dimensions.
so in order to create a matrix of unknow size at compile time , you should create it dynamically in the heap memory using functions like calloc or malloc, although in C99, it allowed created arrays statically of unknown size during compile time but it's not the case with struct as the struct once defined, your array is created and you cannot do something like this:
typedef struct Array_t{
size_t arrSize_x;
size_t arrSize_y;
int arr[arrSize_x][arrSize_y];
}Array_t;
but if the size of the array is known you can do something like this:
typedef struct Array_t{
int arr[3][1];
}Array_t;
to create a dynamic array, you will find in the next example code something like this:
// rows are stored in heap memory and initiated with zeros
res.arr = (int**) calloc(res.arrSize_x, sizeof(int));
// columns are also stored in heap memory and initiated with zeros
for (int i = 0; i < res.arrSize_x; ++i) {
res.arr[i] = (int *) calloc(res.arrSize_y, sizeof(int));
}
where res.arr is a pointer pointing to an array of pointers and the next diagram may simplify my explanation where the next graph expresses the created matrix in heap memory for arr of size 3 x 1:
while if the size is known, so the explanation diagram may look like this:
and when you return, you can either return by value or by reference, but if you are going to return a struct by reference then you should declare it as static.
so you can do something like this (for clarification purposes, size of matrix is unknown):
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct Array_t{
size_t arrSize_x;
size_t arrSize_y;
int **arr;
}Array_t;
Array_t translation(int x, int y, int tx, int ty) {
// create a struct holding the array
Array_t res;
res.arrSize_x = 3;
res.arrSize_y = 1;
// rows are stored in heap memory and initiated with zeros
res.arr = (int**) calloc(res.arrSize_x, sizeof(int));
// columns are also stored in heap memory and initiated with zeros
for (int i = 0; i < res.arrSize_x; ++i) {
res.arr[i] = (int *) calloc(res.arrSize_y, sizeof(int));
}
res.arr[0][0] = 1;
res.arr[1][0] = 2;
res.arr[2][0] = 3;
return res;
}
int main()
{
Array_t array;
// 1, 2, 3, 4 are dummy parameters
array = translation(1, 2, 3, 4);
printf("elements are :\n");
for (int i = 0; i < array.arrSize_x; ++i) {
for (int j = 0; j < array.arrSize_y; ++j) {
printf("%d\t", array.arr[i][j]);
}
printf("\n");
}
return 0;
}
and this is the output:
elements are :
1
2
3
but if size of matrix is known then you can do something like this (for clarification purposes, size of matrix is known):
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef struct Array_t{
int arr[3][1];
}Array_t;
Array_t translation(int x, int y, int tx, int ty) {
// create a struct holding the array
Array_t res;
res.arr[0][0] = 1;
res.arr[1][0] = 2;
res.arr[2][0] = 3;
return res;
}
int main()
{
Array_t array;
// 1, 2, 3, 4 are dummy parameters
array = translation(1, 2, 3, 4);
printf("elements are :\n");
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 1; ++j) {
printf("%d\t", array.arr[i][j]);
}
printf("\n");
}
return 0;
}
and this is the ouput:
elements are :
1
2
3

Why does const not work even if the variable is not changed?

I'm trying to protect the -a- array of the my_sum_array function from the changes. In the function block I do not make any changes to -a-, but I have a warning (warning: assignment to 'int *' from 'const int *' discards the qualifiers [-Wincompatible-pointer-types-discards-qualifiers]). I know I could remove const to make the program work, but I would like to understand if something is missing from me.
#include <stdio.h>
#define MAX 5
int my_sum_array(const int a[], int n);
int main(void) {
int values[5] = {4, 7, 1, 7, 8};
printf("The sum in my_sum_array is :%d\n", my_sum_array(values, MAX));
return 0;
}
int my_sum_array(const int a[], int n) {
int *p, sum = 0;
for (p = a; p < a + n; p++)
sum += *p;
return sum;
}
The warning is caused by the assignment p = a in the for loop. The variable is defined as int *p, a pointer to non-const int. The warning is correct, "assignment to int * from const int * discards the qualifiers". It's as though you've casted away the constness of the a pointer parameter.
I'd change your function to:
int my_sum_array(const int a[], int n) {
int sum = 0;
for (const int *p = a; p < a + n; p++)
sum += *p;
return sum;
}
This defines p as a pointer-to-const, just like a, and also limits its lifetime to the for loop.
Make your p pointer as:
int const * p;
i.e.
here, p is a pointer to a const integer
Change type of p to:
const int *p;
So now you end up with:
const int * p;
int sum = 0;

Why does the const clause not work if I try to use it when I want to protect the modification of a vector?

In the book I am studying it says that if I pass a vector to a function, the name of the vector is always treated as a pointer.
In fact it's so.
But I can't understand why in the first function the const clause is allowed by the compiler, while in the second function (where I use pointers to search for the maximum value between the elements) no.
In the functions I would simply like to protect against the modification of the vector.
#include <stdio.h>
int find_largest(const int a[], int n);
int find_largest_with_pointer(const int *vettore, int n);
int main(void) {
int my_number[] = {5, 7, 90, 34, 12};
int n = sizeof(my_number) / sizeof(my_number[0]);
int *pmy_number = my_number;
printf("%d\n", find_largest(my_number, n));
printf("%d\n", find_largest(pmy_number, n));
printf("%d\n", find_largest_with_pointer(my_number, n));
printf("%d\n", find_largest_with_pointer(pmy_number, n));
return 0;
}
int find_largest(const int a[], int n) {
int i, max;
max = a[0];
for(i = 0; i < n; i++)
if(a[i] > max)
max = a[i];
return max;
}
int find_largest_with_pointer(const int *vettore, int n) {
int *i, max = *vettore;
for(i = vettore; i < vettore + n; i++)
if(*i > max)
max = *i;
return max;
}
Since vettore is a pointer to const int, you must make i have the same type.
const int *i;
int max = *vettore;
for(i = vettore; i < vettore + n; i++)
Short Version: Adding a const qualifier will address the compiler warning.
int find_largest_with_pointer(const int *vettore, int n) {
// int *i, max = *vettore;
const int *i ;
int max = *vettore;
...
}
Long Version:
In the second function, you use two variables. Expanding the code a little bit
int *i ;l
it max = a[0] ;
for (
i = vettore;
i < vettore + n;
i++
) { ... }
Note the line i = vettore, which will attempt to copy the 'const int * vettoreinto non-const 'int *i. This has the potential of allowing modification to the const vector (e.g. *i = 5), and the compiler complain:
c.c:33:11: warning: assignment discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
for(i = vettore; i < vettore + n; i++)
Solution is simple: add const qualifier on const int *i. See above.

Returning array (pointer) of 2D array in C

A function dynamically creates an int array whose elements are predetermined to be int[2]. Is there any way to have a function assign values to that array and then return it to the caller.
The below code accomplishes this task but throws warning: initialization from incompatible pointer type [enabled by default]
#include <stdlib.h>
#include <stdio.h>
int *get_values()
{
int (*x)[2] = malloc(sizeof(int[2])*3);
x[0][0] = 1;
x[0][1] = 2;
x[1][0] = 11;
x[1][1] = 12;
x[2][0] = 21;
x[2][1] = 22;
return x;
}
int main()
{
int (*x)[2] = get_values();
int i;
for (i=0; i!=3; i++)
printf("x[%d] = { %d, %d }\n", i, x[i][0], x[i][1]);
}
I'm aware of the alternative where you dynamically allocate both dimensions, but this is something that I am curious about.
Rather than keep repeating the same clunky syntax it can be helpful to define a typedef in cases like this. This makes it easier to declare the correct return type for get_values:
#include <stdlib.h>
#include <stdio.h>
typedef int I2[2];
I2 * get_values(void)
{
I2 * x = malloc(sizeof(I2) * 3);
x[0][0] = 1;
x[0][1] = 2;
x[1][0] = 11;
x[1][1] = 12;
x[2][0] = 21;
x[2][1] = 22;
return x;
}
int main()
{
I2 * x = get_values();
int i;
for (i=0; i!=3; i++)
printf("x[%d] = { %d, %d }\n", i, x[i][0], x[i][1]);
free(x);
}
LIVE DEMO
Recommended reading: Don't repeat yourself (DRY).
And this is how it looks without a typedef:
int (*get_values(void))[2]
{
return NULL;
}
Pretty unreadable.
Notice in that function definition, if you replace get_values(void) with x you get: int (*x)[2], which is exactly what the pointer definition looks like.

Is "reformat" of multi-dimensional array by pointer to incomplete array type allowed in C?

Consider following declaration:
int a[M][N]; // M and N are known compile-time
Would it be legal to treat it like as it was declared as:
int a[N][M];
or even:
int a[A][B]; // where A * B = M * N
in C without breaking its rules (badly)?
I found that it can be acomplished without any cast:
#include <stdio.h>
void print_array(int a[][2], int n);
int main(void)
{
int a[2][3] = {{1, 2, 3}, {4, 5, 6}};
//int (*p1)[2] = a; // compile error
int (*ptr_temp)[] = a; // pointer to array of incomplete type
int (*p2)[2] = ptr_temp; // compiles without any warning
print_array(p2, 3);
}
void print_array(int a[][2], int n)
{
for (int i = 0; i < n; i++)
for (int j = 0; j < 2; j++)
printf("a[%d][%d] = %d\n", i, j, a[i][j]);
}
Notice that we cannot assign a to p1 pointer directly. However compiler does not complain when p2 is assigned with ptr_temp even if it seems to be potentially dangerous (it does not require any cast for that). Is it really sanitized? If so, then why it disallows the first assignmment?
The behavior you see is because of the way multidimensional arrays are handled in C.
Have a look at this question Pointer address in a C multidimensional array

Resources