multi dimensional arrays as one dimension array

J

James Tursa

If all you want is a solution that is guaranteed not to break any rules,
it's pretty easy. If MATLAB provides a space into which you need only copy
the data, you can do so in a simple loop:

(If MATLAB wants you to provide the space and tell it where to look, then
you allocate a big enough space: p = malloc(ROWS * COLS * sizeof *p), and,
provided that the allocation was successful, copy the array into it as
shown above. Then tell MATLAB about p.)

Side note FYI: It can be done either way.You can call a MATLAB
function to build the complete mxArray structure (serves as a MATLAB
style "variable" that can be used in the MATLAB workspace) and then
get the pointer to the data area which you then fill in. Or you can
allocate some raw memory, fill it in, then attach it to a bare bones
mxArray structure, What you can't do is attach a C variable directly
to the mxArray structure ... it would mess up the MATLAB memory
manager. Hence the need to do a copy.
I'm not saying this is the fastest way to do it, but I think it's the
fastest way that is guaranteed not to break any rules!

Well, of course, I know how to do assignments in loops ... but who
wants to give up speed if they don't have to? Particularly if there is
a library function available that does exactly what you want.

James Tursa
 
K

Keith Thompson

pete said:
Has it occurred to you that "library functions" are called that,
because they are part of the library,
and not because of what they do?

Of course.

So you're saying that memcpy is a string function because it's
declared in <string.h>? The same reasoning implies that size_t is a
string type, and NULL is a string macro.
 
K

Keith Thompson

pete said:
That's what I was thinking at the time,
but upon further consideration,
I think memcpy is called a string function
probably because in some dialects of computer science,
"string" is a synonym for "array".

Intel 80286 and 80287 Programmer's Reference Manual
2.2 data types
String: A contiguous sequence of bytes or words.
A string may contain from 1 byte to 64K bytes.

Perhaps, but in C string has a very specific meaning.
 
V

vippstar

Perhaps, but in C string has a very specific meaning.

And "string literal" has a completely different one. Thus, "string
function" can have a meaning that doesn't have to do anything with
"string".
 
V

vippstar

(e-mail address removed) said:





No, it doesn't. It is a specification, that's all. A string literal /is/ a
string, /and/ it's a literal. Hence, string literal.

A string literal needs not to be a string, for example "hello\0world"
is not a string.
There is a footnote somewhere in the standard explicity mentioning
that.
 
V

vippstar

(e-mail address removed) said:



Right. It's several strings. (I count twelve.) I should have said "a string
literal contains at least one string".

Wrong, it's not several strings. It's a string literal. It contains
two strings.
Now show me a string literal that doesn't contain *any* strings.

Show me a flying elephant. :)
Where, exactly?

n1256.pdf,
6.4.5 footnote 66
 
V

vippstar

Wrong, it's not several strings. It's a string literal. It contains
two strings.

Whoops, you are right: twelve strings. However, it's not several
strings, it's a string literal that contains twelve strings.
 
K

Keith Thompson

Richard Heathfield said:
(e-mail address removed) said:

No, it doesn't. It is a specification, that's all. A string literal
/is/ a string, /and/ it's a literal. Hence, string literal.

No, a string literal is a token in a C source file, and a string is
something that exists during program execution. For example, "\n" is
a string literal; it consists of 4 characters, none of which exist in
the corresponding string that exists at run time -- just as the digits
1, 2, and 3 exist in the integer constant token 123 but not in the
corresponding run-time value of type int.

However, string literal certainly are very closely tied to strings; a
string literal (in C source) is almost always intended to specify a
string value (during program execution), with minor exceptions such as
"foo\0bar" and ``char s[3] = "foo"'' (as I recall, the latter still
theoretically specifies the terminating '\0', but I'd expect a typical
compiler to optimize it away).

[...]
 
B

Ben Bacarisse

pete said:
I made a mistake when I said "parameter".
The internal workings of the string functions are described as:

Are the internal workings in dispute? I thought we were both
commenting on what gets passed.
N869
7.21 String handling <string.h>
<snip>
 
J

James Kuyper

Ben said:
I can't find the other message so I'll have to ask here. Are you
saying that converting a double * to, say, unsigned char * permits one
to access parts of an array that are not accessible via the double *?
What are the limits on addition that one is exempted from and where is
this permission granted?

The description of how addition of an integer to a pointer works in
6.5.6p8 is entirely in terms of positions within (and one beyond the end
of) an array of the pointed-at type. The only array of 'double' declared
anywhere in the program that contains the position pointed at by
(double*)a is a[0]. Therefore, the limits based upon array length
imposed by 6.5.6p8 refer to the length of the array a[0] (which is 1),
not the length of 'a' itself (which is 2), and not the length of a
1-dimensional array which could have been allocated in the same memory
as 'a', which would have had a length of 2x1 == 2.

The special characteristic of unsigned char* is that 6.2.6.1p4 defines
C's object model, for non-character types with a size of 'n' bytes, in
terms of treating them as arrays of n unsigned chars - such an array is
defined as constituting the _object representation_ of such types. The
standard guarantees that an object may be copied into such an array, and
gives memcpy() as an example of how this may be done. The fact that
memcpy is given as an example, rather than requiring the use of memcpy()
to perform such a copy, implies that if I were to write a function named
my_memcpy() which matched the other specifications given by the standard
for memcpy(), it must also be usable for copying the object
representation. In other words, the ability to copy object
representations is not a magical additional ability of memcpy(), but is
merely a side-effect of the fact that the behavior of memcpy() is
defined in terms of copying arrays of unsigned char.

If run-time bounds checking were applied to unsigned char* in the most
extreme way otherwise permitted by 6.5.6p8, it would prevent my_memcpy()
from working properly. The undefined behavior allowed by 6.5.6p8 for
adding too large of an integer value to a pointer value, is trumped by
the defined behavior provided by 6.2.6.1p4 for copying an entire object
as an array of unsigned char, even if that object is a multi-dimensional
array of some other type.
You go on to say that these limits are meaningless for void *, but at
some point, useful void *s are converted back. Do the limits that are
then imposed derive from the original pointer or can they get lost?
I.e. is (double *)(void *)dp different in what it can access to
(double *)(void *)(unsigned char *)dp?

The standard is not at all clear about what happens in most pointer
conversions, including those. However, I see no technical difficulty
with retaining the bounds-checking information inside a pointer
throughout a long series of intermediate pointer conversions. The
bounds-checking information cannot be used if the current pointer type
is "unsigned char*", and it's meaningless if the current pointer type
"void*", but it can still reside inside such pointers, hidden, waiting
for conversion to a type which does permit run-time bounds-checking. It
is 6.5.6p8 which makes such bounds-checking legal.
 
J

James Kuyper

Tim said:
James Kuyper said:
James Tursa wrote:
...
OK, that's fine for objects, but that doesn't answer my question. What
is it about 2-dimensional (or multi-dimensional) arrays of double that
does not allow them to be stepped through with a double* ?
Ultimately, nothing more or less than the fact that the standard says
that the behavior is undefined. Because the behavior is undefined,
compilers are allowed to generate code that might fail if such stepping
is attempted (though this is rather unlikely). More importantly,
compilers are allowed to generate code that assumes that such stepping
will not be attempted, and therefore fails catastrophically if it
actually is attempted - the most plausible mode of failure is a failure
to check for aliasing.

Specific details:

Given

double array[2][1];
double *p = (double*)array;

If there is code which sets array[1] to one value, and p[j] to
another value, the compiler not required to consider the possibility
that p[j] and array[1] might point at the same location in memory.
It's allowed to keep either value in a register, or to keep the two
values in different registers. It's not required to make the next
reference to array[1] give the same value as the next reference to p[j].

This is because the behavior would be undefined if 'i' and 'j' had
values that might ordinarily cause you the expect array[1] and p[j]
to refer to the same location. Note: this convoluted wording is
necessary, because if 'i' and 'j' have such values, then at least one of
the two expressions has undefined behavior, rendering it meaningless to
talk about which location that expression actually refers to.


You're starting with the conclusion, and then "proving" the
conclusion. This conclusion isn't consistent with other
behavior and language in the standard.


I was not trying to prove that the behavior was undefined. I was trying
to explain how it is that the fact that the behavior is undefined can
make it dangerous to rely upon such code.

I've presented my argument that the behavior IS undefined elsewhere,
most recently in the response I just posted to Ben Bacarisse.

....
Irrelevant, because that's talking about whether a memory access
can have undefined behavior because of an invalid representation.
It's just as illegal to access outside of an array using unsigned
char as it is using double. The only question is, what memory
may be accessed. Since 'array' is what was converted, any memory in
array may be accessed.

There are multiple arrays involved, and the question is - which array is
the one which 6.5.6p8 is referring to? A careful examination of 6.5.6p8
reveals that what is says constitutes utter nonsense unless the element
type of the relevant array is the same as the type pointed at by the
pointer. Example:

int matrix[3][5];
int *pi = matrix[1];

For purposes of integer additions to "pi", if the array referred to by
6.5.6p8 were "matrix" rather than matrix[1], then because pi points at
the second element of matrix, matrix[1], pi+1 would have to point at the
third element, matrix[2]. If "matrix" were the relevant array, then the
largest amount which could be added to matrix[1] would be 2, not 5,
because the length of matrix is only 3, while the length of matrix[1] is 5.

This is a wholly indefensible interpretation of 6.5.6p8. The only array
that it could possibly be referring, when applied to "pi", is matrix[1].

People have claimed that there is a one-dimensional array of 15 ints
which should be used when applying 6.5.6p8, but I see no such array
declared anywhere in the above code.
 
B

Barry Schwarz

Richard said:
(e-mail address removed) said:



Right. It's several strings. (I count twelve.) I should have said "a string
literal contains at least one string".

Now show me a string literal that doesn't contain *any* strings.

char hello[5] = "Hello";

hello is not a literal. The string literal used to initialize it, if
it does exist in the object module (it need not), will certainly
contain the terminating '\0'. The code that initializes hello with
the literal will not copy the '\0'.
 
R

Richard Bos

Barry Schwarz said:
Right. It's several strings. (I count twelve.) I should have said "a string
literal contains at least one string".

Now show me a string literal that doesn't contain *any* strings.

char hello[5] = "Hello";

hello is not a literal. The string literal used to initialize it, if
it does exist in the object module (it need not), will certainly
contain the terminating '\0'. The code that initializes hello with
the literal will not copy the '\0'.[/QUOTE]

static char hello[5]="Hello";

Richard
 
B

Ben Bacarisse

I thought we were talking about the difference bewteen what
memcpy(p, arr, sizeof arr) does, and what
memcpy(p, &arr, sizeof arr) does.

In both cases, the second argument will be treated
as the address of an object which will be treated
as an array of character type,
which means that the elements of the object
will be accessed as though by a pointer to character type.

Then we are in total agreement.

The only (tiny) issue is that you said "in both cases the second
parameter is initialised to the address of the lowest addressable byte
of the object refered to by the second argument". This wording
applies only to the conversion to character pointer types and there
has been some argument in the past along the lines of "where does a
void * actually point?". I don't think those arguments really stick,
but I would prefer a more explicit guarantee that, barring any
alignment issues, pointer conversions can be piled up in any order
without affecting the result. I.e. that what memcpy sees

(char *)(void *)a

is really the same as (char *)a.
 
B

Ben Bacarisse

James Kuyper said:
Ben said:
I can't find the other message so I'll have to ask here. Are you
saying that converting a double * to, say, unsigned char * permits one
to access parts of an array that are not accessible via the double *?
What are the limits on addition that one is exempted from and where is
this permission granted?

The description of how addition of an integer to a pointer works in
6.5.6p8 is entirely in terms of positions within (and one beyond the
end of) an array of the pointed-at type. The only array of 'double'
declared anywhere in the program that contains the position pointed at
by (double*)a is a[0]. Therefore, the limits based upon array length
imposed by 6.5.6p8 refer to the length of the array a[0] (which is 1),
not the length of 'a' itself (which is 2), and not the length of a
1-dimensional array which could have been allocated in the same memory
as 'a', which would have had a length of 2x1 == 2.

The special characteristic of unsigned char* is that 6.2.6.1p4 defines
C's object model, for non-character types with a size of 'n' bytes, in
terms of treating them as arrays of n unsigned chars - such an array
is defined as constituting the _object representation_ of such
types. The standard guarantees that an object may be copied into such
an array, and gives memcpy() as an example of how this may be
done. The fact that memcpy is given as an example, rather than
requiring the use of memcpy() to perform such a copy, implies that if
I were to write a function named my_memcpy() which matched the other
specifications given by the standard for memcpy(), it must also be
usable for copying the object representation. In other words, the
ability to copy object representations is not a magical additional
ability of memcpy(), but is merely a side-effect of the fact that the
behavior of memcpy() is defined in terms of copying arrays of unsigned
char.

If run-time bounds checking were applied to unsigned char* in the most
extreme way otherwise permitted by 6.5.6p8, it would prevent
my_memcpy() from working properly. The undefined behavior allowed by
6.5.6p8 for adding too large of an integer value to a pointer value,
is trumped by the defined behavior provided by 6.2.6.1p4 for copying
an entire object as an array of unsigned char, even if that object is
a multi-dimensional array of some other type.

If I understand your point of view, you are saying that any bounds
checking applied to character pointers must be relaxed so that it
applies (if at all) only to the largest enclosing object, because a
char * can range over the whole object's representation.

I like your line of reasoning and I find it persuasive.

To clarify: in 6.5.6p9 (about pointer difference) you presumably take
the view that &a[0][0] and &a[2][0] are not "in the same array" and
therefore can't be subtracted (or compared)? This is entirely
logical, given your argument above, but rather counter-intuitive given
the normal meaning of the term.
The standard is not at all clear about what happens in most pointer
conversions, including those. However, I see no technical difficulty
with retaining the bounds-checking information inside a pointer
throughout a long series of intermediate pointer conversions. The
bounds-checking information cannot be used if the current pointer type
is "unsigned char*", and it's meaningless if the current pointer type
"void*",

I don't think it is meaningless for void *s. It could, for example,
be used to check if a comparison is defined or not. The relational
operators are defined in terms in array elements but not in relation
to pointer arithmetic, so comparing void *s is permitted and the
bounds information could be used to raise an error in those situations
where the objects pointed to are not in the same array.
 
J

jameskuyper

Ben said:
The description of how addition of an integer to a pointer works in
6.5.6p8 is entirely in terms of positions within (and one beyond the
end of) an array of the pointed-at type. The only array of 'double'
declared anywhere in the program that contains the position pointed at
by (double*)a is a[0]. Therefore, the limits based upon array length
imposed by 6.5.6p8 refer to the length of the array a[0] (which is 1),
not the length of 'a' itself (which is 2), and not the length of a
1-dimensional array which could have been allocated in the same memory
as 'a', which would have had a length of 2x1 == 2.

The special characteristic of unsigned char* is that 6.2.6.1p4 defines
C's object model, for non-character types with a size of 'n' bytes, in
terms of treating them as arrays of n unsigned chars - such an array
is defined as constituting the _object representation_ of such
types. The standard guarantees that an object may be copied into such
an array, and gives memcpy() as an example of how this may be
done. The fact that memcpy is given as an example, rather than
requiring the use of memcpy() to perform such a copy, implies that if
I were to write a function named my_memcpy() which matched the other
specifications given by the standard for memcpy(), it must also be
usable for copying the object representation. In other words, the
ability to copy object representations is not a magical additional
ability of memcpy(), but is merely a side-effect of the fact that the
behavior of memcpy() is defined in terms of copying arrays of unsigned
char.

If run-time bounds checking were applied to unsigned char* in the most
extreme way otherwise permitted by 6.5.6p8, it would prevent
my_memcpy() from working properly. The undefined behavior allowed by
6.5.6p8 for adding too large of an integer value to a pointer value,
is trumped by the defined behavior provided by 6.2.6.1p4 for copying
an entire object as an array of unsigned char, even if that object is
a multi-dimensional array of some other type.

If I understand your point of view, you are saying that any bounds
checking applied to character pointers must be relaxed so that it
applies (if at all) only to the largest enclosing object, because a
char * can range over the whole object's representation.
Exactly.

I like your line of reasoning and I find it persuasive.

To clarify: in 6.5.6p9 (about pointer difference) you presumably take
the view that &a[0][0] and &a[2][0] are not "in the same array" and
therefore can't be subtracted (or compared)? This is entirely
logical, given your argument above, but rather counter-intuitive given
the normal meaning of the term.

Yes, that is how I interpret 6.5.6p9.
I don't think it is meaningless for void *s. It could, for example,
be used to check if a comparison is defined or not.

You're right; I wasn't thinking about comparisons. Also, I had
forgotten that the behavior was undefined when comparing pointers that
do not point into (or one past the end of) the same array - I'd
thought it produced an unspecified result. Offhand, I can't think of
any reason why it's undefined behavior, but maybe someone else can
come up with an example of an implementation where it would have been
problematic to have such comparisons merely return an unspecified
value.
 
A

Antoninus Twink

Of course.

So you're saying that memcpy is a string function because it's
declared in <string.h>? The same reasoning implies that size_t is a
string type, and NULL is a string macro.

FFS... it must be, like, 6 months or something since we last went
through this completely absurdly argument that excites such passion in
the breasts of the clc pedants club.
 
B

Barry Schwarz

Barry Schwarz said:
Richard Heathfield wrote:
Right. It's several strings. (I count twelve.) I should have said "a string
literal contains at least one string".

Now show me a string literal that doesn't contain *any* strings.

char hello[5] = "Hello";

hello is not a literal. The string literal used to initialize it, if
it does exist in the object module (it need not), will certainly
contain the terminating '\0'. The code that initializes hello with
the literal will not copy the '\0'.

static char hello[5]="Hello";

I don't see that this makes any difference.
 
B

Barry Schwarz

Barry said:
Richard Heathfield wrote:
(e-mail address removed) said:
(e-mail address removed) said:
<snip>

Perhaps, but in C string has a very specific meaning.
And "string literal" has a completely different one.
No, it doesn't. It is a specification, that's all. A string literal /is/
a string, /and/ it's a literal. Hence, string literal.
A string literal needs not to be a string, for example "hello\0world"
is not a string.
Right. It's several strings. (I count twelve.) I should have said "a string
literal contains at least one string".

Now show me a string literal that doesn't contain *any* strings.
char hello[5] = "Hello";

hello is not a literal.

Agreed. Neither is char, [, 5, ], =, ;, or the white space.
Everything else in the source line is a string literal.
The string literal used to initialize it, if
it does exist in the object module (it need not), will certainly
contain the terminating '\0'.

Chapter and verse?

6.4.5-5 seems to fit. 6.4.5-6 adds confirmation.
It certainly cannot "copy the '\0'," just as it cannot copy
a three-kilogram slab of luminiferous ether. As far as I can tell,
the Standard says the same thing about the existence of the former
and the latter, to wit, nothing at all.

So you think the initialization of an automatic array of char does not
involve any code to copy the initial value into the array? How does
recursion work if code is not involved?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top