Change values of 2D array in function - c

The following code works perfectly well if I put the function content into the main block, but the function completely fails here. I currently get a 'subscripted value is neither array nor pointer nor vector' error. I also get 'passing argument 1 and 4 of 'accumulate' from incompatible pointer type' errors.
void accumulate( double sum[], int ypos[], int xpos[], int vals[], int numvals )
{
for(int i=0 ; i<numvals ; i++) /// start looping over indices
{
sum[ypos[i]][xpos[i]] += vals[i];
}
}
int main()
{
int xpos[2] = {0,1};
int ypos[2] = {0,1};
double vals[2] = {1.01,7};
int numvals = 2;
int size = 6;
double sum[size][size];
for(int i=0; i<size ;i++)
{
for(int j=0; j<size ; j++)
{
sum[i][j] = 0; // make zeros
}
}
accumulate(sum,ypos,xpos,vals,numvals); // doesn't work
for(int i=0; i<size ;i++)
{
for(int j=0; j<size ; j++)
{
printf("%f ", sum[i][j]);
}
printf("\n");
}
}

2d array when passed to function that decays into T (*)[COLS]. Or alternatively you can write
void func( int col, int arr[][col]);
So you would write
void accumulate( double sum[][size], int ypos[], int xpos[], int vals[], int numvals )
{
...
}
Also you should be aware the ypos[i] and xpos[i] should be within the limit of the array size so that you don't run into undefined behavior.

Related

Function for printing 2D arrays of uknown size in C

I'm new to C programming and I've run into a problem when creating 2D array printing function. When I try to execute the code below I get:
points.c:13: error: unknown array element size
As I've checked there are very similar codes online, which are supposed to work. I've tried to initialize function as
int print2DArray( int arrayLen, int elementLen, int array[arrayLen][elementLen])
but it raises:
points.c:3: error: 'arrayLen' undeclared
Could somebody tell me what's wrong with this code and how to fix it? I also don't understand why very similar function for 1D arrays works just fine. It has to be in pure C.
#include <stdio.h>
//supposed to print 2D array:
int print2DArray(int array[][], int arrayLen, int elementLen)
{
int i;
int j;
for (i = 0; i < arrayLen; i++)
{
for (j=0; j < elementLen; j++)
{
printf("%5d", array[i][j]);
}
printf("\n");
}
}
//prints 1D array:
int printArray( int array[], int arrayLen)
{
int i;
for (i = 0; i < arrayLen; i++)
{
printf("%d", array[i]);
}
}
--- edit ---
I undestand most of you pointed out that the function has to be called like that:
#include <stdio.h>
int print2DArray( int arrayLen, int elementLen, int array[arrayLen][elementLen])
{
int i;
int j;
for (i = 0; i < arrayLen; i++)
{
for (j=0; j < elementLen; j++)
{
printf("%5d", array[i][j]);
}
printf("\n");
}
}
This raises an error:
points.c:3: error: 'arrayLen' undeclared
I'm using tcc for windows and according to documentation it is supposed to support C99 VLA.
It appears OP's compiler (or the mode it is used) does not support variable length array (VLA) as a function parameter.
Below is a non-VLA approach.
void print2DArrayX(int arrayLen, int elementLen, const int *array) {
int i;
int j;
for (i = 0; i < arrayLen; i++) {
for (j = 0; j < elementLen; j++) {
printf("%5d", array[i*elementLen + j]);
}
printf("\n");
}
}
Call with address of first int, not the 2D array
#define ARRAY_LEN 3
#define ELEMENT_LEN 4
int array[ARRAY_LEN][ELEMENT_LEN] = { 0 };
...
print2DArrayX(ARRAY_LEN, ELEMENT_LEN, array[0]);
Ok, so thanks for all the answers - they were very helpful. I've just tried to use gcc in linux and as you've pointed out this approach works fine:
int print2DArray( int arrayLen, int elementLen, int array[arrayLen][elementLen])
I guess tcc (tiny c compiler, windows version 0.9.27) doesn't support VLA after all. A bit strange since documentation says it does.
How about you try this solution.
#include <stdio.h>
int print2DArray(int* array, int arrayLen, int elementLen)
{
int i;
int j;
for (i = 0; i < arrayLen; i++)
{
for (j=0; j < elementLen; j++)
{
printf("%5d ", *(array+j+elementLen*i));
}
printf("\n");
}
}
int main(){
int arr[2][6] = { {9,258,9,96,-8,5},
{1,1212,-3,45,27,-6}
};
print2DArray(*arr,2,6);
return 0;
}
Unless you are using a C99 compiler,
int print2DArray( int arrayLen, int elementLen, int array[arrayLen][elementLen])
is not possible.
Even if you are using C99 compiler, your code has a problem. You need to pass one of the dimension first.
int print2DArray(int arrayLen, int elementLen, int arr[][elementLen]);
So,
int print2DArray(int arrayLen, int elementLen, int arr[][elementLen])
{
// Your code
int i;
int j;
for (i = 0; i < arrayLen; i++)
{
for (j=0; j < elementLen; j++)
{
printf("%5d", array[i][j]);
}
printf("\n");
}
return 0;
}
This can be used as
int main(void)
{
int i32Array[3][3] = {{-15, 4, 36}, {45, 55, 12}, {-89, 568, -44568}};
int m = 3, n = 3;
// I am not sure why 'print2DArray' would return an int
// (or anything at all for that matter).
// If you can establish a case for it,
// modify the function and the value it is supposed to return,
// And catch it below.
print2DArray(m, n, i32Array);
return 0;
}
I am not sure how you are calling print2DArray function. Unless you post that piece of code, it is difficult to resolve your problem. Confirm that you are calling the function correctly as shown above.

C pointer dereference error

Suppose I have the following code (example):
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
void Ex(void *ret, int ret_len, int choice){
if(choice==1){
int *ret = ret;
for(int i=0; i<ret_len; i++){
*(ret+i) = i;
}
} else {
int **ret = ret;
for(int i=0; i<ret_len; i++){
for(int j=0; j<ret_len; j++){
*(*(ret+i)+j) = i*j;
}
}
}
}
int main()
{
int m[10];
Ex(m,10,1);
printf("%i",m[3]);
return 0;
}
The goal of the function is to take a pointer to preallocated memory of a one or two dimensional array.
When compiled and executed the code works when choice==1, otherwise, if I run
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
void Ex(void *ret, int ret_len, int choice){
if(choice==1){
int *ret = ret;
for(int i=0; i<ret_len; i++){
*(ret+i) = i;
}
} else {
int **ret = ret;
for(int i=0; i<ret_len; i++){
for(int j=0; j<ret_len; j++){
*(*(ret+i)+j) = i*j;
}
}
}
}
int main()
{
int m[100];
Ex(m,10,2);
printf("%i", m[3][5]);
return 0;
}
no output is ever produced and the code seems to run forever (note choice is now not 1 and m is the proper size)
I am under the impression that the casting in Ex should change the shape of the array and allow main to index into it as if it were 2d but neither indexing into it as if it were 1d nor 2d work.
Having looked at the comments on the question and some answers this is what I have gathered for your requirements.
You need a generic function that takes an array of choice dimensions and initializes it with some values.
This can suit your purpose.
void Ex(void *_ret, int ret_len, int choice){
if(choice==1){
int *ret = _ret;
int i;
for(i=0; i<ret_len; i++){
ret[i] = i;
}
} else {
int (*ret)[ret_len] = _ret;
int i, j;
for(i=0; i<ret_len; i++){
for(j=0; j<ret_len; j++){
ret[i][j] = i*j;
}
}
}
}
Now this is how you can call it
int main(void) {
int first[10];
Ex(first, 10, 1);
int second[20][20];
Ex(second, 20, 2);
printf("first[4] = %d\n", first[4]);
printf("second[3][4] = %d\n", second[3][4]);
}
You can see the Demo here
because ret if of type int *, but the else part is:
for(int i=0; i<ret_len; i++){
for(int j=0; j<ret_len; j++){
*(*(ret+i)+j)=i*j;
}
}
which needs ret of type int **. and this causes the error.
The way to resolve the problem is to use void *. that is one way to use generics in C.
Take a look at qsort in C.
void Ex(void *_ret, int ret_len, int choice){
if(choice==1){
int *ret = (int *)_ret; // <---- type conversion
for(int i=0; i<ret_len; i++){
*(ret+i) = i;
}
} else {
int **ret = (int **)_ret; // <---- type conversion
for(int i=0; i<ret_len; i++){
for(int j=0; j<ret_len; j++){
*(*(ret+i)+j) = i*j;
}
}
}
}
The closest thing with least change of your existing code I came up with is:
#include <stdio.h>
void Ex(int * ret, int ret_len, int choice){
if(choice==1){
for(int i=0; i<ret_len; i++){
*(ret+i)=i;
}
}else{
for(int i=0; i<ret_len; i++){
for(int j=0; j<ret_len; j++){
*(ret + i*ret_len + j) = i*j;
}
}
}
}
int main() {
int anint[10][10];
Ex(anint, 10, 2);
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {printf("%d\n", anint[i][j]);}
}
}
Basically, I mannually manipulate the offset within the Ex function. and I take the assumption that the length of the two dimensions are always the same.
A more "conventioal way" would be a true 2-dimentional array in which each element is malloc independently. Thus, the element of the first level array can be casted by force to a pointer and be dereferenced in the second level. But I am reluctant to call malloc too many times.
I hope this can solved your problem.

Creating a matrix in a structure

I am trying to create a structure that will have two integer values, an array, and two 2-D matrices using my code below. I can initialize the structure with the integers and array just fine, and my 'Gen' function will create the random values I want for the array.
However, when I try adding in the matrix components, I run into a problem. My compiler gives me a warning: "initialization from incompatible pointer type". If I understand what I have read so far, this is because the structure needs to be pointed to an array of pointers that represent each row in the matrix. I don't know the syntax for that.
A quick note: the other topics I've seen that are related to this issue all initialize the structure in a function other than the main() function, so I haven't found those solutions helpful.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <string.h>
// Define structure
typedef struct {
int row;
int col;
int *arr;
int **mat1;
int **mat2;
}container;
// Function headers
void Gen(container Thing);
int main() {
int row = 5;
int col = 6;
int A[row];
int M1[row][col];
int M2[row][col+1];
// Initialize structure
container Object = {row, col, A, M1, M2};
// Run "Gen" function
Gen(Object);
int i, j; // Index variables
// Display the array
for(i = 0; i < row; i++)
{
printf("%i ", Object.arr[i]);
}
printf("\n\n");
// Display the numbers from the matrices
for(j = 0; j < Object.row; j++)
{
for(i = 0; i < Object.col; i++)
{
printf("%i ", Object.mat1[j][i]);
}
printf("\n");
}
printf("\n");
for(j = 0; j < Object.row; j++)
{
for(i = 0; i < Object.col; i++)
{
printf("%i ", Object.mat2[j][i]);
}
printf("\n");
}
return (EXIT_SUCCESS);
}
// Function to generate random values in the array & matrices
void Gen(container Thing)
{
int i, j;
srand(time(NULL));
// Generate random values for the array
for(i = 0; i < Thing.row; i++)
{
Thing.arr[i] = rand() % 5;
}
// Generate random values for the matrix
for(j = 0; j < Thing.row; j++)
{
for(i = 0; i < Thing.col; i++)
{
Thing.mat1[j][i] = rand() % 5;
Thing.mat2[j][i] = rand() % 5;
}
}
} // End of "Gen" function
container Object = {row, col, A, M1, M2};
is wrong since the type of M1 is int[row][col], which can decay to int (*)[col] but not to int**. You have the same problem with M2.
You'll need to rethink your strategy for generating a container.
For example:
int main() {
int row = 5;
int col = 6;
int A[row];
int* M1[row];
int* M2[row];
for ( int i = 0; i < row; ++i )
{
M1[i] = malloc(sizeof(M1[i][0])*col);
M2[i] = malloc(sizeof(M1[i][0])*(col+1));
}
// Initialize structure
container Object = {row, col, A, M1, M2};
...
for ( int i = 0; i < row; ++i )
{
free(M1[i]);
free(M2[i]);
}
return (EXIT_SUCCESS);
}

Transpose matrix function in C, with function receiving and returning a 2D array

I need to create a function that takes a matrix and returns it transpose. The only requirement is that it directly returns a matrix, not just modifies it by reference. Here's what I've done so far:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define ROW 100000000
#define COL 100000000
int (*(f_MatTrans)(int mat[][COL], int r, int c))[COL];
int main(void)
{
int x[2][2]={1,2,3,4};
int (*a)[2];
a=f_MatTrans(x,2,2);
for(int i=0; i<2; i++)
{
for(int j=0; j<2; j++)
{
printf("X[%d][%d]=%d\n",i,j,x[i][j]);
printf("A[%d][%d]=%d\n",i,j,a[i][j]);
}
}
return 0;
}
int (*(f_MatTrans)(int mat[][COL], int r, int c))[COL]
{
int a[c][r];
for(int i=0; i<r; i++)
{
for(int j=0; j<c; j++)
{
a[j][i]=mat[i][j];
}
}
return a;
}
The purpose of this is to include the function on a library created by myself, just in case it is useful information.
The code in the question (when I read it) doesn't compile because the array x is not compatible with the function signature.
I'm not clear what the real constraints on your problem are. The easy way to do it in C99 or C11 is with VLA notation:
#include <stdio.h>
static void MatrixTranspose(int r, int c, int src[r][c], int dst[c][r])
{
for (int i = 0; i < r; i++)
for (int j = 0; j < c; j++)
dst[j][i] = src[i][j];
}
int main(void)
{
int x[3][2] = { { 0, 1 }, { 2, 3 }, { 4, 5 } };
int y[2][3];
MatrixTranspose(3, 2, x, y);
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 2; j++)
{
printf("X[%d][%d]=%d ", i, j, x[i][j]);
printf("Y[%d][%d]=%d\n", j, i, y[j][i]);
}
}
return 0;
}
Sample output:
X[0][0]=0 Y[0][0]=0
X[0][1]=1 Y[1][0]=1
X[1][0]=2 Y[0][1]=2
X[1][1]=3 Y[1][1]=3
X[2][0]=4 Y[0][2]=4
X[2][1]=5 Y[1][2]=5
My suspicion is that you are supposed to be doing something different (notationally more complex), but it is not yet clear what.
You cannot return a pointer to the local array, because that ceases to exist when the function returns. If you want your function to create the result array (not write to some other array that is passed into the function), you must use malloc() in these cases:
//The return type is actually `int (*)[r]`, but C doesn't like that.
int* f_MatTrans(int r, int c, int mat[][c]) {
int (*a)[r] = malloc(c*sizeof(*a));
for(int i=0; i<r; i++) {
for(int j=0; j<c; j++) {
a[j][i]=mat[i][j];
}
}
return *a;
}
Note that I changed the array types: If you declare mat as int mat[][COL], the number COL will be used to calculate the offset mat[1][0], which will be 100000000 integers after the first element in your case, while the array that you pass in only contains four integers. This is undefined behavior, and your program is allowed to format your harddrive if you do this.
Unfortunately, it is not possible for the type of the returned pointer to depend on the value of an argument to the function. That is why I changed the return type to a plain integer pointer, you must document that this is meant to be a pointer of type int (*)[r].
You would use the function above like this:
int main(void) {
int x[2][3]={1,2,3,4,5,6};
int (*a)[2] = (int (*)[2])f_MatTrans(2, 3, x);
for(int i=0; i<2; i++) {
for(int j=0; j<2; j++) {
printf("X[%d][%d]=%d\n",i,j,x[i][j]);
printf("A[%d][%d]=%d\n",i,j,a[i][j]);
}
}
free(a); //Cleanup!
return 0;
}

Returning dynamic array through void function in C

In my C program, I use a void function with the following arguments:
One 2D int array, one int pointer that will be used to create the new dynamic array and a last int pointer which will hold a number of counts that will occur inside the function.
So the dynamic array is created in the function using malloc and everything works okay, until I print its elements in main() after calling the function. What I get is rubbish instead of the numbers I should see. Here's the function code:
void availableMoves(int array[][3], int *av, int *counter)
{
int i, j;
for (i=0; i<3; i++)
{
for (j=0; j<3; j++)
{
if (array[i][j] == E)
{
printf("%d ", 3*i + j + 1);
(*counter)++;
}
}
}
av = (int *) malloc(*counter * sizeof(int));
if (av == NULL)
{
printf("ERROR!");
}
else
{
for (i=0; i<*counter; i++)
*(av + i) = 0;
int pos = 0;
for (i=0; i<3; i++)
{
for (j=0; j<3; j++)
{
if (array[i][j] == E)
{
*(av + pos++) = 3*i + j + 1;
}
}
}
}
}
In this function, av is a pointer passed by copy. So when you change the value of your pointer inside the function, the original pointer won't be modified.
There are two possibilities :
use a pointer to pointer (int **av);
return the allocated pointer (return av).
So either:
void availableMoves(int array[][3], int **av, int *counter);
Or:
int *availableMoves(int array[][3], int *av, int *counter)
And the call:
availableMoves(array, &av, &counter);
av = availableMoves(array, av, &counter);
use double pointer for your dynamic array int **av instead of int *av
void availableMoves(int array[][3], int **av, int *counter)
and into the function change av by *av

Resources