473,324 Members | 2,541 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,324 software developers and data experts.

Casting between 1D and 2D arrays

Hello everyone,

Consider a "set" of M=N*N integers. In some parts of my program, I want
to handle this set as a 1D array of M integers. In other parts of my
program, I want to handle this set as a 2D matrix of N*N integers.

Is the following code 100% legal C89 code ?

#include <assert.h>
#define N 9
typedef int row_t[N];

void compare(int *array)
{
int i, j;
row_t *matrix = (row_t *)array;
for (i=0; i < N; ++i)
for (j=0; j < N; ++j)
{
assert( &matrix[i][j] == &array[i*N+j] );
assert( matrix[i][j] == array[i*N+j] );
}
}

int main(void)
{
int i;
int foo[N*N];
for (i=0; i < N*N; ++i) foo[i] = 7*i+11;
compare(foo);
return 0;
}

Can I be sure that the asserts will never fail ?

Regards.
Oct 14 '08 #1
13 4903
Boon <root@localhostwrites:
Consider a "set" of M=N*N integers. In some parts of my program, I
want to handle this set as a 1D array of M integers. In other parts of
my program, I want to handle this set as a 2D matrix of N*N integers.

Is the following code 100% legal C89 code ?
I think so, yes. I was hoping someone else would stick their neck out
first, but it may as well be me! Note that 100% legal != 100%
portable -- I see one possible gotcha.
#include <assert.h>
#define N 9
typedef int row_t[N];

void compare(int *array)
{
int i, j;
row_t *matrix = (row_t *)array;
The only issues seems to be to be this conversion. The standard says
very little about it except that the pointer must be properly aligned.
I think it is possible for row_t to have stricter alignment
requirements than int, but this problem would vanish if the pointer
passed were malloced rather than being converted from a declared array
in main (malloced space must be correctly aligned for any use).

An implementation that requires such an alignment would be odd indeed
since it would only apply to certain sizes of row_t, but I can't
persuade myself that the standard prohibits it.
for (i=0; i < N; ++i)
for (j=0; j < N; ++j)
{
assert( &matrix[i][j] == &array[i*N+j] );
assert( matrix[i][j] == array[i*N+j] );
}
}

int main(void)
{
int i;
int foo[N*N];
for (i=0; i < N*N; ++i) foo[i] = 7*i+11;
compare(foo);
return 0;
}

Can I be sure that the asserts will never fail ?
That alone is not enough. UB (if present) could cause the asserts to
"pass" when in fact they "fail". I think you are OK if the array is
malloced or you target implementations have no bizarre alignment
requirements for arrays of arrays.

--
Ben.
Oct 14 '08 #2
void compare(int *array)
{
int i, j;
row_t *matrix = (row_t *)array;
for (i=0; i < N; ++i)
for (j=0; j < N; ++j)
{
assert( &matrix[i][j] == &array[i*N+j] );
assert( matrix[i][j] == array[i*N+j] );
}
}
That is legal.
Can I be sure that the asserts will never fail ?
As far as I know yes.
I think it is possible for row_t to have stricter alignment
requirements than int
I don't see why, as row_t is an array of ints. And as far as I know
ints don't NEED to be aligned on most architectures, it's just faster
when they are. On any architecture where alignment is necesary
foo[N*N] will be aligned when allocated on the stack.

Oct 15 '08 #3
da*******@gmail.com writes:

[You've lost the attributions and confused the quote levels. Please
try not to do that if you post again.]
>void compare(int *array)
{
int i, j;
row_t *matrix = (row_t *)array;
for (i=0; i < N; ++i)
for (j=0; j < N; ++j)
{
assert( &matrix[i][j] == &array[i*N+j] );
assert( matrix[i][j] == array[i*N+j] );
}
}

That is legal.
>Can I be sure that the asserts will never fail ?

As far as I know yes.
>I think it is possible for row_t to have stricter alignment
requirements than int
I wrote this (but not the other stuff quoted with ">>").
I don't see why, as row_t is an array of ints. And as far as I know
ints don't NEED to be aligned on most architectures, it's just faster
when they are. On any architecture where alignment is necesary
foo[N*N] will be aligned when allocated on the stack.
Yes, but my point was about some array pointers needing more alignment
than others. I can't think why on earth this would ever be done, but
I can't show, using quotes from the standard, that it is never the
case.

--
Ben.
Oct 15 '08 #4
Boon <root@localhostwrote:
Hello everyone,

Consider a "set" of M=N*N integers. In some parts of my
program, I want to handle this set as a 1D array of M
integers. In other parts of my program, I want to handle
this set as a 2D matrix of N*N integers.
There are references to this in the FAQ.
Is the following code 100% legal C89 code ?
Whilst you are extremely unlikely to ever ancounter an
implementation where it will fail, it is not guaranteed
by the standard.
#include <assert.h>
#define N 9
typedef int row_t[N];

void compare(int *array)
{
* *int i, j;
* *row_t *matrix = (row_t *)array;
This conversion isn't as well defined as it could be.
There is no guarantee that the pointer array's first
element is suitably aligned for a pointer to an array
of 9 integers. Even if it happens to be, the only
thing you can reliably do with matrix is convert it
back to a pointer to int.
* *for (i=0; i < N; ++i)
* * *for (j=0; j < N; ++j)
* * *{
* * * *assert( &matrix[i][j] == &array[i*N+j] );
* * * *assert( *matrix[i][j] == *array[i*N+j] );
* * *}
}

int main(void)
{
* *int i;
* *int foo[N*N];
* *for (i=0; i < N*N; ++i) foo[i] = 7*i+11;
* *compare(foo);
* *return 0;
}

Can I be sure that the asserts will never fail?
Theoretically, No.

--
Peter
Oct 15 '08 #5
Ben Bacarisse <ben.use...@bsb.me.ukwrote:
danmat...@gmail.com writes:
Ben Bacarisse <ben.use...@bsb.me.ukwrote:
OP wrote:
#include <assert.h>
#define N 9
typedef int row_t[N];
void compare(int *array)
{
* int i, j;
* row_t *matrix = (row_t *)array;
* for (i=0; i < N; ++i)
* * for (j=0; j < N; ++j)
* * {
* * * assert( &matrix[i][j] == &array[i*N+j] );
* * * assert( *matrix[i][j] == *array[i*N+j] );
* * }
}
<snip>
I think it is possible for row_t to have stricter
alignment requirements than int...
I don't see why, as row_t is an array of ints. ...

...my point was about some array pointers
needing more alignment than others. *I can't think
why on earth this would ever be done, but I can't
show, using quotes from the standard, that it is
never the case.
Consider...

struct X { int a; int b; };

If it's reasonable for an implementation to assign this
2 * sizeof(int) byte alignment, especially if 2 ints fit
nicely into a machine word, then wouldn't it also be
reasonable for int[2] to have the same alignment
requirements?

[Of course, int[9] is harder to explain. ;-]

--
Peter
Oct 15 '08 #6
Peter Nilsson <ai***@acay.com.auwrites:
[...]
Consider...

struct X { int a; int b; };

If it's reasonable for an implementation to assign this
2 * sizeof(int) byte alignment, especially if 2 ints fit
nicely into a machine word, then wouldn't it also be
reasonable for int[2] to have the same alignment
requirements?
It would be reasonable to align a declared object of type int[2] on a
2*sizeof(int) boundary, but the compiler could not in general
*require* such alignment. You can treat any 2-element "slice" of an
int array as an array of type int[2]:

typedef int two_ints[2];
/* just to make the declarations less confusing */
int arr[3];
two_ints *p = (two_ints*)&arr[1];

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Oct 15 '08 #7
Keith Thompson <ks***@mib.orgwrites:
Peter Nilsson <ai***@acay.com.auwrites:
[...]
>Consider...

struct X { int a; int b; };

If it's reasonable for an implementation to assign this
2 * sizeof(int) byte alignment, especially if 2 ints fit
nicely into a machine word, then wouldn't it also be
reasonable for int[2] to have the same alignment
requirements?

It would be reasonable to align a declared object of type int[2] on a
2*sizeof(int) boundary, but the compiler could not in general
*require* such alignment. You can treat any 2-element "slice" of an
int array as an array of type int[2]:

typedef int two_ints[2];
/* just to make the declarations less confusing */
int arr[3];
two_ints *p = (two_ints*)&arr[1];
Yes. This is, in essence, what the OP's code does. The bit I am
missing is the wording that says resulting pointer *must be* properly
aligned.

--
Ben.
Oct 15 '08 #8
Ben Bacarisse wrote:
Boon wrote:
>Consider a "set" of M=N*N integers. In some parts of my program, I
want to handle this set as a 1D array of M integers. In other parts of
my program, I want to handle this set as a 2D matrix of N*N integers.

Is the following code 100% legal C89 code ?

I think so, yes. I was hoping someone else would stick their neck out
first, but it may as well be me! Note that 100% legal != 100%
portable -- I see one possible gotcha.
>#include <assert.h>
#define N 9
typedef int row_t[N];

void compare(int *array)
{
int i, j;
row_t *matrix = (row_t *)array;

The only issues seems to be to be this conversion. The standard says
very little about it except that the pointer must be properly aligned.
I think it is possible for row_t to have stricter alignment
requirements than int, but this problem would vanish if the pointer
passed were malloced rather than being converted from a declared array
in main (malloced space must be correctly aligned for any use).

An implementation that requires such an alignment would be odd indeed
since it would only apply to certain sizes of row_t, but I can't
persuade myself that the standard prohibits it.
OK. What about casting the "other way" ?

Is it 100% legal and 100% portable ? :-)

NB : I want to be able to use matrix[i][j] and array[i*N+j] interchangeably.

#include <assert.h>
#define N 9
int main(void)
{
int i, j;
int matrix[N][N];
int *array = (int *)matrix;

for (i=0; i < N; ++i)
for (j=0; j < N; ++j)
{
matrix[i][j] = i + j + 7;
assert( &matrix[i][j] == &array[i*N+j] );
assert( matrix[i][j] == array[i*N+j] );
}

return 0;
}

AFAICT, the cast is mandatory, if I want to do what I've described.
Is this a situation where a cast is acceptable ?

Regards.
Oct 15 '08 #9
Keith Thompson <ks...@mib.orgwrote:
Peter Nilsson <ai...@acay.com.auwrites:
Consider...

* struct X { int a; int b; };

If it's reasonable for an implementation to assign
this 2 * sizeof(int) byte alignment, especially if
2 ints fit nicely into a machine word, then wouldn't
it also be reasonable for int[2] to have the same
alignment requirements?

It would be reasonable to align a declared object of
type int[2] on a 2*sizeof(int) boundary, but the
compiler could not in general *require* such alignment.
You can treat any 2-element "slice" of an int array
as an array of type int[2]:
Chapter and verse please.

AFAICS, you can treat a pointer to an element as a
pointer to a sequence of elements up to the end of the
array (and one byte beyond), but I can't see that you
can impose a new effective type on that array.
* * typedef int two_ints[2];
* * /* just to make the declarations less confusing */
* * int arr[3];
* * two_ints *p = (two_ints*)&arr[1];
You're assuming that the explicit conversion holds, ergo
there's no way to enforce the alignment. I state that
the conversion needn't hold because alignment may be
enforced.

I might be missing something (again ;-), but where
does the standard give latitude for the array pointer
conversion that is not also given to the struct pointer?

--
Peter
Oct 15 '08 #10
Boon <root@localhostwrites:
Ben Bacarisse wrote:
>Boon wrote:
>>Consider a "set" of M=N*N integers. In some parts of my program, I
want to handle this set as a 1D array of M integers. In other parts of
my program, I want to handle this set as a 2D matrix of N*N integers.

Is the following code 100% legal C89 code ?

I think so, yes. I was hoping someone else would stick their neck out
first, but it may as well be me! Note that 100% legal != 100%
portable -- I see one possible gotcha.
>>#include <assert.h>
#define N 9
typedef int row_t[N];

void compare(int *array)
{
int i, j;
row_t *matrix = (row_t *)array;

The only issues seems to be to be this conversion. The standard says
very little about it except that the pointer must be properly aligned.
I think it is possible for row_t to have stricter alignment
requirements than int, but this problem would vanish if the pointer
passed were malloced rather than being converted from a declared array
in main (malloced space must be correctly aligned for any use).

An implementation that requires such an alignment would be odd indeed
since it would only apply to certain sizes of row_t, but I can't
persuade myself that the standard prohibits it.

OK. What about casting the "other way" ?

Is it 100% legal and 100% portable ? :-)

NB : I want to be able to use matrix[i][j] and array[i*N+j]
interchangeably.
I am tempted to ask "Why?" but a more important question is probably
what degree of portability risk you are prepared to take. Your
previous code has no practical problems that I can see. A quick
glance in the documentation for any given C implementation will
assure you that no bizarre alignment for arrays is enforced and you
are home and dry. Any risk (and you will see that not everyone agrees
there is a risk) is well below my radar and my radar for portability
hazards is set very much more sensitive than most.
#include <assert.h>
#define N 9
int main(void)
{
int i, j;
int matrix[N][N];
int *array = (int *)matrix;
The problem here is now not alignment but what, exactly, is the array
that 'array' points to[1]. Is it the whole of 'matrix' or only
'matrix[0]'? Does it make a difference if we write

int *array = (int *)&matrix;

or

int *array = &matrix[0][0];

? These are fun questions to ponder with respect to the standard but
I don't think it matters in practise. All reasonable compilers will
assume that a pointer into an array can be used to alias any element
and the optimiser (always your worst enemy when you contemplate
bending the language rules) will take that into account.

Anyway, it may be worth backing up and asking yourself if you can't do
what you want another way that stays entirely within the undisputed
bounds of the language.
for (i=0; i < N; ++i)
for (j=0; j < N; ++j)
{
matrix[i][j] = i + j + 7;
assert( &matrix[i][j] == &array[i*N+j] );
assert( matrix[i][j] == array[i*N+j] );
}

return 0;
}

AFAICT, the cast is mandatory, if I want to do what I've described.
It is, but see my other two examples, one of which dose not need a
cast.
Is this a situation where a cast is acceptable ?
Pass.

[1] The reason this matters is that the standard defines pointer
arithmetic entirely in terms of the arrays that pointers point into
(even when the array is a fictional 1-element array made up if a
single object).

--
Ben.
Oct 15 '08 #11
Peter Nilsson <ai***@acay.com.auwrites:
Keith Thompson <ks...@mib.orgwrote:
>Peter Nilsson <ai...@acay.com.auwrites:
Consider...

* struct X { int a; int b; };

If it's reasonable for an implementation to assign
this 2 * sizeof(int) byte alignment, especially if
2 ints fit nicely into a machine word, then wouldn't
it also be reasonable for int[2] to have the same
alignment requirements?

It would be reasonable to align a declared object of
type int[2] on a 2*sizeof(int) boundary, but the
compiler could not in general *require* such alignment.
You can treat any 2-element "slice" of an int array
as an array of type int[2]:

Chapter and verse please.
Hmm. I'm assuming the above is valid, but I can't actually cite C&V
to support my assumption.
AFAICS, you can treat a pointer to an element as a
pointer to a sequence of elements up to the end of the
array (and one byte beyond), but I can't see that you
can impose a new effective type on that array.
>* * typedef int two_ints[2];
* * /* just to make the declarations less confusing */
* * int arr[3];
* * two_ints *p = (two_ints*)&arr[1];

You're assuming that the explicit conversion holds, ergo
there's no way to enforce the alignment. I state that
the conversion needn't hold because alignment may be
enforced.

I might be missing something (again ;-), but where
does the standard give latitude for the array pointer
conversion that is not also given to the struct pointer?
Quite possibly it doesn't.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Oct 16 '08 #12
Keith Thompson <ks***@mib.orgwrites:
Peter Nilsson <ai***@acay.com.auwrites:
[...]
Consider...

struct X { int a; int b; };

If it's reasonable for an implementation to assign this
2 * sizeof(int) byte alignment, especially if 2 ints fit
nicely into a machine word, then wouldn't it also be
reasonable for int[2] to have the same alignment
requirements?

It would be reasonable to align a declared object of type int[2] on a
2*sizeof(int) boundary, but the compiler could not in general
*require* such alignment. [...]
I believe it can. We can infer that the Standard permits more
restrictive alignment requirements for arrays of length 1 than
for arrays of unknown length (and in particular of length 1) from
6.2.5 p 13

Each complex type has the same representation and alignment
requirements as an array type containing exactly two elements of
the corresponding real type; the first element is equal to the
real part, and the second element to the imaginary part, of the
complex number.

If arrays of length 2 couldn't have more restrictive alignment
requirements than other arrays, this paragraph probably would
have been worded differently.
Nov 9 '08 #13
Peter Nilsson <ai***@acay.com.auwrites:
Boon <root@localhostwrote:
Hello everyone,

Consider a "set" of M=N*N integers. In some parts of my
program, I want to handle this set as a 1D array of M
integers. In other parts of my program, I want to handle
this set as a 2D matrix of N*N integers.

There are references to this in the FAQ.
Is the following code 100% legal C89 code ?

Whilst you are extremely unlikely to ever ancounter an
implementation where it will fail, it is not guaranteed
by the standard.
#include <assert.h>
#define N 9
typedef int row_t[N];

void compare(int *array)
{
int i, j;
row_t *matrix = (row_t *)array;

This conversion isn't as well defined as it could be.
There is no guarantee that the pointer array's first
element is suitably aligned for a pointer to an array
of 9 integers. Even if it happens to be, the only
thing you can reliably do with matrix is convert it
back to a pointer to int.
The last statement here is a statement of opinion, not a statement
of fact. Plenty of people believe (and I'm one of them) that as
long as alignment requirements are met, the Standard provides that
the variable 'matrix' may be used as a two-dimensional overlay to
access elements in the original array.
Nov 9 '08 #14

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: Wihlelm Bierbaum | last post by:
I'm trying to make use of a certain method of a COM object that takes a multidimensional array as its sole parameter. Here's an example of the construction of said array: $cA = array(); $cA =...
5
by: matt melton | last post by:
Hi there, I am trying to write a method that accepts an array of any primitive type and will return the same array without copying memory as an array of bytes. ie. I'd like to be able to do...
4
by: David Rager | last post by:
Howdy, Put briefly, I have an array of chars, which I would like to access in pairs of bytes via casting the array to an array of shorts. I'm trying to be as elegant as possible. Below is a...
11
by: truckaxle | last post by:
I am trying to pass a slice from a larger 2-dimensional array to a function that will work on a smaller region of the array space. The code below is a distillation of what I am trying to...
61
by: Ken Allen | last post by:
I am relatively new to .Net, but have been using VB and C/C++ for years. One of the drawbacks with VB6 and earlier was the difficulty in casting a 'record' to a different 'shape' so one could...
0
by: Jon the Blind | last post by:
I have a set of business object classes built from the typed dataset tool in Visual Studio. Since the individual objects (such as the Order object, for example) inherit from DataRow, a common...
2
by: Enrique Bustamante | last post by:
Casting arrays that works on watch and command window but not in code. My application is casting arrays in a way it should work. To test if I was doing something invalid, I wrote a test code that...
39
by: Martin Jørgensen | last post by:
Hi, I'm relatively new with C-programming and even though I've read about pointers and arrays many times, it's a topic that is a little confusing to me - at least at this moment: ---- 1)...
2
by: eric.dennison | last post by:
In the sample below: testClass is derived from object. We can cast object to testClass, no problem We can cast testClass to object no problem Compiler is ok with cast object to testClass but...
152
by: vippstar | last post by:
The subject might be misleading. Regardless, is this code valid: #include <stdio.h> void f(double *p, size_t size) { while(size--) printf("%f\n", *p++); } int main(void) { double array = { {...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.