By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,667 Members | 2,611 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,667 IT Pros & Developers. It's quick & easy.

arbitrary array index range?

P: n/a
"A Book on C" explains a technique to use an arbitrary array index range.

int* p = malloc(sizeof(int) * 10) - 1;

This way, the allocated array can be accessed with index range 1 ~ 10,
not 0 ~ 9. You cannot use p[0], of course, and the memory should be
released with free(p + 1).
It worked with gcc and MSVC, but I'm not sure if it makes sense to take
the address before the initial element of an array. Does anyone have
any definite answer?

--
ES Kim
Nov 14 '05 #1
Share this Question
Share on Google+
16 Replies


P: n/a
"ES Kim" <no@spam.mail> wrote in message news:ck**********@news1.kornet.net...

int* p = malloc(sizeof(int) * 10) - 1;


correction: int* p = (int*)malloc(sizeof(int) * 10) - 1;

--
ES Kim
Nov 14 '05 #2

P: n/a
ES Kim <no@spam.mail> wrote:
"A Book on C" explains a technique to use an arbitrary array index range. int* p = malloc(sizeof(int) * 10) - 1;
Bad book.
This way, the allocated array can be accessed with index range 1 ~ 10,
not 0 ~ 9. You cannot use p[0], of course, and the memory should be
released with free(p + 1).
Whats wrong with indexes starting from zero? I find it the most
natural way ever, since I quit Pascal.

If you really-really need to index from 1, then waste one element:
int* p = malloc(sizeof(int) * (10 + 1));
It worked with gcc and MSVC, but I'm not sure if it makes sense to take
the address before the initial element of an array. Does anyone have
any definite answer?


Pure coincidence. Undefined behaviour.

A pointer can point into an array object or one past the end.

--
Stan Tobias
sed 's/[A-Z]//g' to email
Nov 14 '05 #3

P: n/a
"ES Kim" <no@spam.mail> wrote:
"ES Kim" <no@spam.mail> wrote in message news:ck**********@news1.kornet.net...

int* p = malloc(sizeof(int) * 10) - 1;


correction: int* p = (int*)malloc(sizeof(int) * 10) - 1;


Not only is the original wrong, so is the correction. You cannot
portably set a pointer to the location before the start of an object.
Both of your lines above could cause segmentation faults, or if you're
less lucky, more unobvious symptoms of undefined behaviour.

Richard
Nov 14 '05 #4

P: n/a
ES Kim wrote:
"ES Kim" <no@spam.mail> wrote in message news:ck**********@news1.kornet.net...
int* p = malloc(sizeof(int) * 10) - 1;

This is invalid and invokes undefined behaviour. Consider what might
happen if the pointer returned by malloc refers to memory which is at
the beginning of a segment for example. The C standard says this is
undefined behaviour because pointer arithmetic on a pointer (in this
case the pointer returned by malloc) must result in a pointer which
points somewhere in the same array or one past the end of that array.

Do not do this. If for some reason you want 1 based arrays just allocate
one extra element and ignore the first one. Usually this is not very
helpful though.


correction: int* p = (int*)malloc(sizeof(int) * 10) - 1;


Err, no.

Recommended malloc usage is something along the lines of

(T is an arbitrary type)

T *ptr = malloc(num_elements * sizeof *ptr);

Notice, no cast and no explicit dependency on the type of ptr
in the argument to malloc. Good Thing!

Search the archives for copious discussion on this.

HTH.

--
Thomas.
Nov 14 '05 #5

P: n/a
On Wed, 13 Oct 2004 23:33:38 +0900
"ES Kim" <no@spam.mail> wrote:
"A Book on C" explains a technique to use an arbitrary array index
range.

int* p = malloc(sizeof(int) * 10) - 1;

This way, the allocated array can be accessed with index range 1 ~ 10,
not 0 ~ 9. You cannot use p[0], of course, and the memory should be
released with free(p + 1).
It worked with gcc and MSVC, but I'm not sure if it makes sense to
take the address before the initial element of an array. Does anyone
have any definite answer?


The only values you are allowed to set a pointer to are:
1) The null pointer
2) Inside a valid C object
3) 1 passed the end of a valid C object.

1 less that the value returned by malloc is none of the above, so doing
that invokes the wrath of undefined behaviour and could cause Russia to
decide to attack you with nuclear missiles. So I would advise against
it.

Also, trying to simulate indexing from a value other than 0 in C
generally causes confusion for other programmers and makes the
introduction of errors. In languages such as Pascal which support
arbitrary indexing it is less likely to cause confusion because people
expect it.

As a final unrelated point, allocation using the form:
type *p = malloc(n * sizeof *p);
is generally less error prone since the type only appears in one place.
--
Flash Gordon
Sometimes I think shooting would be far too good for some people.
Although my email address says spam, it is real and I read it.
Nov 14 '05 #6

P: n/a
Thomas Stegen <th***********@gmail.com> wrote:
ES Kim wrote:
int* p = malloc(sizeof(int) * 10) - 1;
correction: int* p = (int*)malloc(sizeof(int) * 10) - 1;


Err, no.

Recommended malloc usage is something along the lines of


Recommended, but not dogmatic. There are cases where it can
be appropriate to use a cast...

T *ptr = malloc(num_elements * sizeof *ptr);


In this case the cast is necessary, because you cannot do
arithmetic on void pointers (the first example should fail
to compile, or even worse, subtract 1 byte because some
compilers have extensions where void* arithmetic is treated
as char* arithmetic).
Nov 14 '05 #7

P: n/a
In article <84**************************@posting.google.com >,
Old Wolf <ol*****@inspire.net.nz> wrote:
Thomas Stegen <th***********@gmail.com> wrote:
ES Kim wrote:
>
>>int* p = malloc(sizeof(int) * 10) - 1;
>
> correction: int* p = (int*)malloc(sizeof(int) * 10) - 1;
Err, no.

Recommended malloc usage is something along the lines of


Recommended, but not dogmatic. There are cases where it can
be appropriate to use a cast...

T *ptr = malloc(num_elements * sizeof *ptr);


In this case the cast is necessary, because you cannot do
arithmetic on void pointers (the first example should fail
to compile, or even worse, subtract 1 byte because some
compilers have extensions where void* arithmetic is treated
as char* arithmetic).


True, but in this case, it doesn't matter if you invoke undefined behavior
by calling malloc without a prototype (causing the return type to be
incorrectly defaulted to int) and the compiler didn't warn you about
it because you told it to shut up with the cast, because you're already
invoking undefined behavior by creating a pointer off the beginning of
mallocd memory.

The solution is to Just Don't Do That, not to use the cast.
dave

--
Dave Vandervies dj******@csclub.uwaterloo.ca I can't think of any programming language whose niche is larger than C's.

English as spoken by teachers in U.S. public schools.
--Dan Pop and Mike Wahler in comp.lang.c
Nov 14 '05 #8

P: n/a
ES Kim wrote:
"A Book on C" explains a technique to use an arbitrary array index range.

int* p = malloc(sizeof(int) * 10) - 1;
int* p = ((int*)malloc(10*sizeof(int))) - 1;
This way, the allocated array can be accessed with index range 1 ~ 10,
not 0 ~ 9. You cannot use p[0], of course,
and the memory should be released with free(p + 1).
It worked with gcc and MSVC,
And it will work with every ANSI/ISO compliant C compiler.
but I'm not sure if it makes sense to take
the address before the initial element of an array.
Does anyone have any definite answer?


According to the ANSI/ISO standards, p is undefined!
Nov 14 '05 #9

P: n/a
E. Robert Tisdale <E.**************@jpl.nasa.gov> wrote:
[snip]
And it will work with every ANSI/ISO compliant C compiler.
[snip]
According to the ANSI/ISO standards, p is undefined!


I envy those people who can write two such sentences together
and still live happily! :-)

--
Stan Tobias
sed 's/[A-Z]//g' to email
Nov 14 '05 #10

P: n/a
"E. Robert Tisdale" <E.**************@jpl.nasa.gov> wrote:
ES Kim wrote:
"A Book on C" explains a technique to use an arbitrary array index range.

int* p = malloc(sizeof(int) * 10) - 1;


int* p = ((int*)malloc(10*sizeof(int))) - 1;


Doesn't help, although in this case the cast is at least conceptually
right. It's the subtraction which is the problem.
This way, the allocated array can be accessed with index range 1 ~ 10,
not 0 ~ 9. You cannot use p[0], of course,
and the memory should be released with free(p + 1).
It worked with gcc and MSVC,


And it will work with every ANSI/ISO compliant C compiler.


Care to explain why something that invokes undefined behaviour would
work with _every_ ISO C compiler?
but I'm not sure if it makes sense to take
the address before the initial element of an array.
Does anyone have any definite answer?


According to the ANSI/ISO standards, p is undefined!


Quite.

Richard
Nov 14 '05 #11

P: n/a
On 13 Oct 2004 16:49:39 -0700, in comp.lang.c , ol*****@inspire.net.nz (Old
Wolf) wrote:
Recommended, but not dogmatic. There are cases where it can
be appropriate to use a cast...
Name one. Answer restricted to C code only.
T *ptr = malloc(num_elements * sizeof *ptr);


In this case the cast is necessary, because you cannot do
arithmetic on void pointers (the first example should fail
to compile,


In the above case if ptr is of type void* then this should just fail to
compile end of story. If ptr is not of type void, then your comment doesn't
seem to make sense.
or even worse, subtract 1 byte because some
compilers have extensions where void* arithmetic is treated
as char* arithmetic)


What?
--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
CLC readme: <http://www.ungerhu.com/jxh/clc.welcome.txt>
----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption =---
Nov 14 '05 #12

P: n/a
Richard Bos wrote:
Care to explain why something that invokes undefined behavior
would work with _every_ ISO C compiler?


The term "undefined behavior" means exactly that.
The ISO C standards do *not* specify the behavior
of pointers to objects outside of array bounds
so they are allowed to "work" and, in fact, they do work
for every compiler that complies with ISO C99.
Nov 14 '05 #13

P: n/a
Mark McIntyre <ma**********@spamcop.net> wrote:
ol*****@inspire.net.nz (Old Wolf) wrote:
In this case the cast is necessary, because you cannot do
arithmetic on void pointers (the first example should fail
to compile,


In the above case if ptr is of type void* then this should just fail to
compile end of story. If ptr is not of type void, then your comment doesn't
seem to make sense.
or even worse, subtract 1 byte because some
compilers have extensions where void* arithmetic is treated
as char* arithmetic)


What?


If we can return to the original case, which seems to have
been misquoted:

malloc(sizeof(int) * 10) - 1
That need not compile on a standards-conforming compiler.
Gcc warns:
g.c:5: warning: pointer of type `void *' used in arithmetic

Furthermore there is a common extension where void* arithmetic
is treated as char* arithmetic. You may not be familiar with
this; the upshot is that the above quote will compile
without warning and give the same result as:

(void *)(((char *)malloc(sizeof(int) * 10)) - 1)

[Note, if you care about the issue that it's undefined
to subtract from the pointer, change all '-' to '+']
Nov 14 '05 #14

P: n/a

In article <oi********************************@4ax.com>, Mark McIntyre <ma**********@spamcop.net> writes:
On 13 Oct 2004 16:49:39 -0700, in comp.lang.c , ol*****@inspire.net.nz (Old
Wolf) wrote:
Recommended, but not dogmatic. There are cases where it can
be appropriate to use a cast...


Name one. Answer restricted to C code only.


Casting an object pointer of another type to unsigned char * in order
to inspect an object's representation, or to copy it to another area
of memory, and so forth. (Note for the second case that we may be
using a freestanding implementation which does not provide memcpy and
memmove.) The alternative is to use an otherwise extraneous temporary
void *. I'd consider the cast in this situation preferable, and so
appropriate.

Casting the result of the sizeof operator to unsigned long in order
to format it with fprintf, in a conforming hosted implementation
prior to C99 (which introduced a conversion specifier guaranteed to
be suitable for size_t).

Casting a plain char or explicitly signed char variable to unsigned
char for use with the is... and to... "functions" defined in ctype.h,
which may be implemented as macros and may invoke UB if called with a
negative value.

I agree that casts should be rare in most well-written C code.

--
Michael Wojcik mi************@microfocus.com

Unlikely predition o' the day:
Eventually, every programmer will have to write a Java or distributed
object program.
-- Orfali and Harkey, _Client / Server Programming with Java and CORBA_
Nov 14 '05 #15

P: n/a
"E. Robert Tisdale" <E.**************@jpl.nasa.gov> wrote:
Richard Bos wrote:
Care to explain why something that invokes undefined behavior
would work with _every_ ISO C compiler?


The term "undefined behavior" means exactly that.
The ISO C standards do *not* specify the behavior
of pointers to objects outside of array bounds
so they are allowed to "work" and, in fact, they do work
for every compiler that complies with ISO C99.


That is so blatant a contradiction that I won't even start trying to
explain where you're going wrong. If you don't see that "It needn't
work, so it works everywhere" is idiotic, there's no curing you.

Richard
Nov 14 '05 #16

P: n/a
On 18 Oct 2004 17:48:14 GMT, in comp.lang.c , mw*****@newsguy.com (Michael
Wojcik) wrote:

In article <oi********************************@4ax.com>, Mark McIntyre <ma**********@spamcop.net> writes:
On 13 Oct 2004 16:49:39 -0700, in comp.lang.c , ol*****@inspire.net.nz (Old
Wolf) wrote:
>Recommended, but not dogmatic. There are cases where it can
>be appropriate to use a cast...


Name one. Answer restricted to C code only.


Casting an object pointer of another type to unsigned char * in order
to inspect an object's representation, or to copy it to another area
of memory, and so forth.


Grin. All accepted.

I was thinking more of the context of Old Wolf's post, which as far as I
recall was suggesting that the casting of malloc was sometimes appropriate.

--
Mark McIntyre
CLC FAQ <http://www.eskimo.com/~scs/C-faq/top.html>
CLC readme: <http://www.ungerhu.com/jxh/clc.welcome.txt>
----== Posted via Newsfeed.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeed.com The #1 Newsgroup Service in the World! >100,000 Newsgroups
---= 19 East/West-Coast Specialized Servers - Total Privacy via Encryption =---
Nov 14 '05 #17

This discussion thread is closed

Replies have been disabled for this discussion.