448,935 Members | 1,634 Online
Need help? Post your question and get tips & solutions from a community of 448,935 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
16 Replies

 P: n/a "ES Kim" 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 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" wrote: "ES Kim" 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" 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" 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 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 wrote:Thomas Stegen 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 ofRecommended, but not dogmatic. There are cases where it canbe appropriate to use a cast... T *ptr = malloc(num_elements * sizeof *ptr);In this case the cast is necessary, because you cannot doarithmetic on void pointers (the first example should failto compile, or even worse, subtract 1 byte because somecompilers have extensions where void* arithmetic is treatedas 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 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" 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 canbe 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 doarithmetic on void pointers (the first example should failto 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 somecompilers have extensions where void* arithmetic is treatedas char* arithmetic) What? -- Mark McIntyre CLC FAQ CLC readme: ----== 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 wrote: ol*****@inspire.net.nz (Old Wolf) wrote:In this case the cast is necessary, because you cannot doarithmetic on void pointers (the first example should failto 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 somecompilers have extensions where void* arithmetic is treatedas 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 , Mark McIntyre 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 canbe 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" 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 , Mark McIntyre 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 orderto inspect an object's representation, or to copy it to another areaof 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 CLC readme: ----== 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.