2

I have been working on this problem for a while now: basically I need to put the for loop in a function so I can call for it, but I don't how to to make a function return a 2D array, I want to solve this by creating a 1D array, but the problem is that my task is to compute the sum of numbers under the diagonal of a matrix, so I need it to be 2D first, then it can only become 1D. Does anyone have a solution?

Maybe my thought process is just wrong and somebody could just recommend how to put the for loops in functions? If it was without the if clause inside then I might have an idea, but now I really don't.

#include <math.h>
#include <stdio.h>
#include <stdlib.h> // libraries added from example
#include <time.h>

//(*) For a square matrix calculate the sum of elements under the main diagonal excluding it.
#define A -10
#define B 10

int main() {
    void enter(int *x, int *y);
    int get_random(int lbound, int ubound); // telling the programs that functions are declared
    int r;
    int c;
    int row, col, sum = 0;
    enter(&r, &c); // calling the function
    srand48(time(NULL)); //Call srand48 with current time reported by `time` casted to a long integer.
    // srand48 is used to reinitialize the most recent 48-bit value in this storage
    int array[r][c]; // we decided its gonna be r rows and c columns
    int line[r * c]; // turning 2d into 1d array
    for (row = 0; row < r; ++row) // we cycle numeration of rows of matrix
    {
        for (col = 0; col < c; col++) // we cycle numeration of columns of matrix
        {
            array[row][col] = get_random(B, A);// filling array with random numbers, taken from example
            printf("%d ", array[row][col]);
            if (row > col) { //since we want the sum numbers below the diagonal row>col must be true
                sum = sum + array[row][col];// if row>col then we add the number to our sum;
            };
        }
        printf("\n"); // this is to break line after row 1,2 col 3, so it looks nicer
    }
    for (row = 0; row < r; ++row) // we cycle numeration of rows of matrix
    {
        for (col = 0; col < c; col++) // we cycle numeration of columns of matrix
        {
            line[row * r + col] = array[row][col];
        }
    }
    printf("the array in 1D: ");
    for (row = 0; row < r * c; row++) {
        printf("%d ", line[row]);
    }
    printf("\n");
    printf("sum of array below the diagonal: %d\n", sum);

    return 0;
}

void enter(int *x, int *y) { // we have to use pointers if we want more then one return from a function

    printf("How man rows in array?  "); // just like the last lab we decide how big the matrix will be
    scanf("%d", x); // we use x instead of &x because we need the address of the number not the value
    printf("How man columns in array? ");
    scanf("%d", y); // we use y instead of &y because we need the address of the number not the value
}

int get_random(int lbound, int ubound) {
    return mrand48() % (ubound - lbound + 1) + lbound; // function for generating random numbers
}

Conditions have to be met:

  1. the user decides size of square matrix

  2. the matrix has to be filled with random numbers

  3. the array is called by the function has to be 1D using i*N+j, 2D array can't be passed

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
clubmix
  • 31
  • 5
  • 1
    Instead of creating the array as an local/automatic variable you can allocate it using malloc which will give you a pointer. This pointer can be returned by your function. However, you have to consider that if the caller doesn't know the size of the array it becomes impossible for the caller to interpret in any useful way. Perhaps it's better for the caller to provide the size instead. Choices... – Martin Liversage Jan 31 '23 at 12:34
  • 1
    Functions in C cannot return arrays, they can however return pointers (arrays are essentially syntactic sugar for pointers in C). So if you want your function to return an array or matrix for that matter, you will have to allocate memory (using calloc) in your function and return that pointer, obviously at some point you will have to free that, alternatively, you can create a matrix as you did, then pass that as an argument to some function such that that matrix can be manipulated within that function. – Plegeus Jan 31 '23 at 13:49

2 Answers2

3

Let's consider your assignment

Conditions have to be met:

  1. the user decides size of square matrix

  2. the matrix has to be filled with random numbers

  3. the array is called by the function has to be 1D using i*N+j, 2D array can't be passed

Firstly the matrix must be square.

So this your function

void enter(int *x, int *y) { // we have to use pointers if we want more then one return from a function

    printf("How man rows in array?  "); // just like the last lab we decide how big the matrix will be
    scanf("%d", x); // we use x instead of &x because we need the address of the number not the value
    printf("How man columns in array? ");
    scanf("%d", y); // we use y instead of &y because we need the address of the number not the value
}

does not make sense. The user can enter different values for the numbers of rows and columns of the matrix. You need to enter only one positive value.

Secondly as we are speaking about a matrix then it means that you have to define a two-dimensional array.

Also you need to write a function that will calculate the sum of elements under the main diagonal of a matrix. The function is declared such a way that it can accept only a one-dimensional array. This means that you need to pass your matrix to the function casting it to a pointer of the type int *. There is no need to create an auxiliary one-dimensional array,

Here is a demonstration program that shows how the function can be declared and defined and how the matrix can be passed to the function.

#include <stdio.h>

long long int sum_under_dioganal( const int a[], size_t n )
{
    long long int sum = 0;

    for (size_t i = 1; i < n; i++)
    {
        for (size_t j = 0; j < i; j++)
        {
            sum += a[i * n + j];
        }
    }

    return sum;
}

int main( void )
{
    enum { N = 5 };
    int a[N][N] =
    {
        {  0,  0,  0,  0,  0 },
        {  1,  0,  0,  0,  0 },
        {  2,  3,  0,  0,  0 },
        {  4,  5,  6,  0,  0 },
        {  7,  8,  9, 10,  0 }
    };

    printf( "sum of elements under the main diagonal = %lld\n",
        sum_under_dioganal( ( int * )a, N ) );
}

The program output is

sum of elements under the main diagonal = 55

Another approach to define the function and call it is the following

#include <stdio.h>

long long int sum_under_dioganal( const int a[], size_t n )
{
    long long int sum = 0;

    size_t m = 0;

    while (m * m < n) ++m;

    if (m * m == n)
    {
        for (size_t i = 1; i < m; i++)
        {
            for (size_t j = 0; j < i; j++)
            {
                sum += a[i * m + j];
            }
        }
    }

    return sum;
}

int main( void )
{
    enum { N = 5 };
    int a[N][N] =
    {
        {  0,  0,  0,  0,  0 },
        {  1,  0,  0,  0,  0 },
        {  2,  3,  0,  0,  0 },
        {  4,  5,  6,  0,  0 },
        {  7,  8,  9, 10,  0 }
    };

    printf( "sum of elements under the main diagonal = %lld\n",
        sum_under_dioganal( ( int * )a, N * N ) );
}

The program output is the same as shown above.

sum of elements under the main diagonal = 55
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
1

2d arrays don't really exist. The compiler just allows you to write a[i][j] so that you can believe in them. Here's some simple code to demonstrate a few methods:

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

void *
make_array(size_t size)
{
        int *a = malloc(sizeof *a * size * size);
        int *t = a;
        if( a == NULL ){
                perror("malloc");
                exit(1);
        }
        for( int row = 0; row < size; row += 1 ){
                for( int col = 0; col < size; col += 1 ){
                        *t++ = rand() % 32 - 16;
                }
        }
        return a;
}

int
trace(void *v, size_t s)
{
        int *a = v;
        int sum = 0;
        for( size_t i = 0; i < s; i += 1 ){
                sum += *a;
                a += s + 1;
        }
        return sum;
}


int
main(int argc, char **argv)
{
        srand(time(NULL));
        size_t s = argc > 1 ? strtol(argv[1], NULL, 0) : 5;
        void *v = make_array(s);

        /* a, b, c, and d will demonstrate different access techniques */
        int *a = v;       /* a is the conventional "1-d array" (1)*/
        int (*b)[s] = v;  /* b is a "two-d" array */
        int *c = v;       /* c iterates through each element */
        int *d = v;       /* d treats each row as a 1-d array */

        for( int i = 0; i < s; i += 1 ){
                for( int j = 0; j < s; j += 1 ){
                        printf("%3d  ", b[i][j]);
                        assert( a[i * s + j] == b[i][j] );
                        assert(     *c       == b[i][j] );
                        assert(    d[j]      == b[i][j] );
                        c += 1;
                }
                d += s;
                putchar('\n');


         }
         printf("trace: %d\n", trace(v, s));
    }

   
/* (1) These comments are not strictly accurate.  `a` is *not* an
 * array, and `b` is *not* a 2-d array.  `a` is a pointer, and `b` is
 * an array of pointers.  Arrays are not pointers, and pointers are
 * not arrays.
 */
William Pursell
  • 204,365
  • 48
  • 270
  • 300
  • 1
    Stupid question - how in the world is `a[i * s + j]` more readable and easier-to-understand-while-skimming-over-the-code than `a[i][j]` ? – Shark Jan 31 '23 at 15:40
  • @Shark I don't think `a[i * s + j]` is more readable that `a[i][j]`, and typically would not write it that way. That version is only included since it was explicitly mentioned in the question. I will re-write the code to demonstrate 2 other techniques that are more readable. – William Pursell Feb 01 '23 at 12:03
  • Arrays of arrays definitely exist according to C semantics. The `a[i][j]` syntax is the correct and logically consistent way to express an element of an element of one. The in-memory representation an array of arrays is analogous to that of a multidimensional array in other languages, such as Fortran, that have multidimensional arrays in the fullest sense. YMMV, but I don't think it's helpful to claim that 2D arrays *don't really exist* on the basis (I guess) that the things we in fact do call by that name should really be called something else instead. – John Bollinger Feb 01 '23 at 13:49