Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #125940 > unrolled thread

Treating a multi-dimensional array as one-dimensional

Started byAugust Karlstrom <fusionfile@gmail.com>
First post2018-01-29 10:40 +0100
Last post2018-01-29 21:35 +0100
Articles 7 — 5 participants

Back to article view | Back to comp.lang.c


Contents

  Treating a multi-dimensional array as one-dimensional August Karlstrom <fusionfile@gmail.com> - 2018-01-29 10:40 +0100
    Re: Treating a multi-dimensional array as one-dimensional Ben Bacarisse <ben.usenet@bsb.me.uk> - 2018-01-29 11:00 +0000
      Re: Treating a multi-dimensional array as one-dimensional supercat@casperkitty.com - 2018-01-29 07:58 -0800
      Re: Treating a multi-dimensional array as one-dimensional Nick Bowler <nbowler@draconx.ca> - 2018-01-29 22:38 +0000
        Re: Treating a multi-dimensional array as one-dimensional Ben Bacarisse <ben.usenet@bsb.me.uk> - 2018-01-29 23:07 +0000
    Re: Treating a multi-dimensional array as one-dimensional Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2018-01-29 03:29 -0800
      Re: Treating a multi-dimensional array as one-dimensional August Karlstrom <fusionfile@gmail.com> - 2018-01-29 21:35 +0100

#125940 — Treating a multi-dimensional array as one-dimensional

FromAugust Karlstrom <fusionfile@gmail.com>
Date2018-01-29 10:40 +0100
SubjectTreating a multi-dimensional array as one-dimensional
Message-ID<p4mq61$1k5n$1@gioia.aioe.org>
I need to define a function which can handle two-dimensional array 
parameters of any size (both dimensions). The code below illustrates my 
current approach.

	#include <stdio.h>
	
	#define LEN(arr) (sizeof (arr) / sizeof (arr)[0])
	
	static void Print(const int *A, int m, int n)
	{
	    int i, j;
	
	    for (i = 0; i < m; i++) {
	        for (j = 0; j < n; j++) {
	            printf("%d ", A[i * n + j]);
	        }
	        putchar('\n');
	    }
	}
	
	int main(void)
	{
	    int A[2][3] = {{1, 2, 3}, {4, 5, 6}};
	
	    Print((int *) A, LEN(A), LEN(A[0]));
	    return 0;
	}

I posted this question on StackOverflow(*) and it was suggested that It 
violates the strict aliasing rule. Is there a different way to solve 
this problem?


*https://stackoverflow.com/questions/48491951/can-i-treat-a-multi-dimensional-array-as-a-one-dimensional-array


-- August

[toc] | [next] | [standalone]


#125942

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2018-01-29 11:00 +0000
Message-ID<87inblexpp.fsf@bsb.me.uk>
In reply to#125940
August Karlstrom <fusionfile@gmail.com> writes:

> I need to define a function which can handle two-dimensional array
> parameters of any size (both dimensions). The code below illustrates
> my current approach.
>
> 	#include <stdio.h>
> 	
> 	#define LEN(arr) (sizeof (arr) / sizeof (arr)[0])
> 	
> 	static void Print(const int *A, int m, int n)
> 	{
> 	    int i, j;
> 	
> 	    for (i = 0; i < m; i++) {
> 	        for (j = 0; j < n; j++) {
> 	            printf("%d ", A[i * n + j]);
> 	        }
> 	        putchar('\n');
> 	    }
> 	}
> 	
> 	int main(void)
> 	{
> 	    int A[2][3] = {{1, 2, 3}, {4, 5, 6}};
> 	
> 	    Print((int *) A, LEN(A), LEN(A[0]));
> 	    return 0;
> 	}
>
> I posted this question on StackOverflow(*) and it was suggested that
> It violates the strict aliasing rule. Is there a different way to
> solve this problem?

Yes.  If the array size (specifically the row length) is not known at
compile time you can do this as of C99:

static void Print(int m, int n, int A[m][n])
{
     int i, j;

     for (i = 0; i < m; i++) {
          for (j = 0; j < n; j++) {
               printf("%d ", A[i][j]);
          }
          putchar('\n');
     }
}

Note the parameter order and the deleted const.  The new order is needed
but the const has gone simply to avoid a problem C has with const where
there is more than one level of indirection.

If at least the row size (3 in this case) is known at compile time you
need no "new" features:  Just pass a pointer to the first array
element -- an array of 3 int:

  static void Print(int (*A)[3], int m)

but the fact that you pass both m and n suggests this won't be suitable.

As for the "strict aliasing" issue, that's a red herring.  The code that
treats a 2D array as a 1D array is technically undefined for reasons
that have nothing to do with aliasing.  I doubt, though, that you will
come across a problem if you do it that way.  There's a lot of code out
there that does that, despite the letter of the language standard.

But if you can use variably modified types (the jargon for a run-time
array size parameter) then you get simpler code as well as code that is
correct by the letter of the language standard.

Finally, if (a) you can't use C99; (b) you want to avoid any hint of
undefined behaviour and (c) the arrays sizes are known at compile time
but the function must be general-purpose you can use an union.  I won't
post an example because this set of circumstances is unlikely.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#125953

Fromsupercat@casperkitty.com
Date2018-01-29 07:58 -0800
Message-ID<1268df2d-54e3-4514-b8df-caa406adedde@googlegroups.com>
In reply to#125942
On Monday, January 29, 2018 at 5:00:52 AM UTC-6, Ben Bacarisse wrote:
> As for the "strict aliasing" issue, that's a red herring.  The code that
> treats a 2D array as a 1D array is technically undefined for reasons
> that have nothing to do with aliasing.  I doubt, though, that you will
> come across a problem if you do it that way.  There's a lot of code out
> there that does that, despite the letter of the language standard.

It has nothing to do with type-based aliasing, but has to do instead with
the question of aliasing between elements of different rows.  A compiler
which knows that foo[r1][c1] cannot alias foo[r2][c2] if r1 != r2 etc. may
be able to reorder operations performed on different rows (which could e.g.
allow multiple rows to be processed simultaneously by different execution
units.

The Standard fails to make clear what a given an array-type lvalue which
is contained within a larger object, to produce a pointer that can be
indexed to access other parts of the containing object.  It would be
unreasonable to say that a function like:

   void output_as_hex(void *p, size_t n)
   {
     unsigned char *cp = p;
     while(n--)
       printf("%02X",*cp++);
   }

should be limited to processing one row of an array at a time.

[toc] | [prev] | [next] | [standalone]


#125967

FromNick Bowler <nbowler@draconx.ca>
Date2018-01-29 22:38 +0000
Message-ID<p4o7o7$1vh$1@dont-email.me>
In reply to#125942
On Mon, 29 Jan 2018 11:00:34 +0000, Ben Bacarisse wrote:
> Yes.  If the array size (specifically the row length) is not known at
> compile time you can do this as of C99:
> 
> static void Print(int m, int n, int A[m][n])
> {
[...]
> }
> 
> Note the parameter order and the deleted const.  The new order is needed

This order of parameters is not actually needed; other orders are
possible by using a separate prototype.  For example:

  static void Print(int (*)[*], int, int);
  static void Print(A, m, n)
    int m, n;
    int (*A)[n];
  {
    /* ... */
  }

[toc] | [prev] | [next] | [standalone]


#125970

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2018-01-29 23:07 +0000
Message-ID<87607ke02x.fsf@bsb.me.uk>
In reply to#125967
Nick Bowler <nbowler@draconx.ca> writes:

> On Mon, 29 Jan 2018 11:00:34 +0000, Ben Bacarisse wrote:
>> Yes.  If the array size (specifically the row length) is not known at
>> compile time you can do this as of C99:
>> 
>> static void Print(int m, int n, int A[m][n])
>> {
> [...]
>> }
>> 
>> Note the parameter order and the deleted const.  The new order is needed
>
> This order of parameters is not actually needed; other orders are
> possible by using a separate prototype.  For example:
>
>   static void Print(int (*)[*], int, int);
>   static void Print(A, m, n)
>     int m, n;
>     int (*A)[n];
>   {
>     /* ... */
>   }

Blimey!  A use for a pre-ANSI C function definition.  That would not
have occurred to me (obviously).  Thanks.  In a weird way that's made my
day.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#125944

FromMalcolm McLean <malcolm.arthur.mclean@gmail.com>
Date2018-01-29 03:29 -0800
Message-ID<f0e06130-3a53-466d-a813-d35ddfd4ac6a@googlegroups.com>
In reply to#125940
On Monday, January 29, 2018 at 9:40:25 AM UTC, August Karlstrom wrote:
> I need to define a function which can handle two-dimensional array 
> parameters of any size (both dimensions). The code below illustrates my 
> current approach.
> 
Generally the easiest answer is just to forget 2D arrays and dereference a
1D array with
     

     array[y*width+x];

However you've got a good answer should you decide that the clarity of
having two sets of brackets instead of one is worth it.

[toc] | [prev] | [next] | [standalone]


#125959

FromAugust Karlstrom <fusionfile@gmail.com>
Date2018-01-29 21:35 +0100
Message-ID<p4o0j7$1o4b$1@gioia.aioe.org>
In reply to#125944
On 2018-01-29 12:29, Malcolm McLean wrote:
> On Monday, January 29, 2018 at 9:40:25 AM UTC, August Karlstrom wrote:
>> I need to define a function which can handle two-dimensional array
>> parameters of any size (both dimensions). The code below illustrates my
>> current approach.
>>
> Generally the easiest answer is just to forget 2D arrays and dereference a
> 1D array with
>       
> 
>       array[y*width+x];

Yes, this seems like the best approach.


-- August

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c


csiph-web