Jump to content
  • Advertisement
Sign in to follow this  
Zaris

Bounds checking for arrays in C/C++

This topic is 4322 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Is their a benefit to C/C++ not checking arrays for going out of bounds? Is there some type of situlation where you adding elements pass the array limits could be useful?

Share this post


Link to post
Share on other sites
Advertisement
With arrays you should always know the length of it, because memory beyond the array isn't yours and contains junk. If you want to extend the length of the array then you need to reallocate and copy.

Dave

Share this post


Link to post
Share on other sites
Quote:
Original post by Zaris
Is their a benefit to C/C++ not checking arrays for going out of bounds? Is there some type of situlation where you adding elements pass the array limits could be useful?


There is NEVER (edit: except, I suppose, in SiCranes example...) a case when you should write or read past the bounds of an array. That will quickly land you in Undefined Behavior, and that is bad.

C/C++ not doing automatic bounds checking is an example of C/C++ trading safety for speed.

[Edited by - Driv3MeFar on July 26, 2006 12:43:54 PM]

Share this post


Link to post
Share on other sites
One C-ism, known as the struct hack, involves deliberately reading past the end of an array in a struct. It goes something like this:

struct DataBlock {
int size;
int data[1];
};

struct DataBlock * make_data_block(int size) {
struct DataBlock * dblk = malloc(sizeof(int) + size * sizeof(int));
dblk->size = size;
return dblk;
}

struct DataBlock * dblk = make_data_block(5);
for (int i = 0; i < dblk->size; i++) {
dblk->data = i;
}

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
One C-ism, known as the struct hack, involves deliberately reading past the end of an array in a struct. It goes something like this:

struct DataBlock {
int size;
int data[1];
};

struct DataBlock * make_data_block(int size) {
struct DataBlock * dblk = malloc(sizeof(int) + size * sizeof(int));
dblk->size = size;
return dblk;
}

struct DataBlock * dblk = make_data_block(5);
for (int i = 0; i < dblk->size; i++) {
dblk->data = i;
}


Note that this style of "inline over-allocation" is basically just to avoid adding a pointer to the 'data', but it requires you to take special care to copy the blocks, only allows for one data block per structure (unless you want to do exceptionally strange things with array indices), prevents you from storing the things by value in arrays (for the same reason that storing derived classes in that way is problematic), is not self-documenting, and is potentially brittle (a better way to write the malloc expression would be as 'sizeof(struct DataBlock) + (size-1) * sizeof(int)'; and even then, you have to fix it if you change the type of 'data' - although I guess you could keep a static, unused instance around and check the sizeof(instance.data[0])?).

Anyway, here you are reading/writing past the bounds of "the array", but really the [1] isn't an array size except to placate the compiler. Oh, and if you want a bounds-checked array, and for some reason (a specific array size that's dictated by the problem domain qualifies) you specifically don't want the array to be resizable like std::vector, you may be interested in boost::array.

(Question: Do any published std::vector implementations use this hack? If not, are there technical problems that would make it impossible to implement the full spec this way? If so, why doesn't everyone do it?)

Share this post


Link to post
Share on other sites
Quote:
Original post by Zaris
Is their a benefit to C/C++ not checking arrays for going out of bounds? Is there some type of situlation where you adding elements pass the array limits could be useful?


In case part of your question was to ask why C and C++ allow you to write past the end of arrays, it is one of those situations where the onus is upon you to ensure that you do not.

If the languages had "built-in" ways to prevent you from doing this, like other more managed languages, that would impose run-time overhead that you would not be able to avoid if you wanted to.

By placing the onus on the programmer, C and C++ maintain the "If you don't want it, you don't pay for it" mentality that has always characterised languages designed to be appropriate for writing low-level code.

Thankfully the onus can be easily taken off you these days by avoiding arrays altogether and using std::vector instead.

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
(Question: Do any published std::vector implementations use this hack? If not, are there technical problems that would make it impossible to implement the full spec this way? If so, why doesn't everyone do it?)

I don't think any published implementation use the struct hack, but you can certainly do it. It does seem somewhat annyoing to do and still guarantee alignment for the stored type though. For example if the type was 128 bit aligned on a platform with 32 bit address space, then there would need to be an overallocation necessary to get alignment. Not insurmountable, but still not something I'd want to bother with.

Share this post


Link to post
Share on other sites
Thanks for all the information. The question came to me after trying to index a array starting at 1 not 0 and was curious if there a possible use to over extending an array.

Share this post


Link to post
Share on other sites
Quote:
Original post by Zaris
Thanks for all the information. The question came to me after trying to index a array starting at 1 not 0 and was curious if there a possible use to over extending an array.


With practice and experience, you'll learn to avoid that mistake. As a side effect, you will likely find that your code contains a lot fewer strange arbitrary +1's and -1's. :) (You will sometimes need them when you're getting an index value from the user, but you should wrap that as "tightly" as possible: do the conversion right after getting the value or before reporting it, and use the converted value internally.)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!