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

C++ Puzzle

P: 34
Hello all,
I got one question from my colleagues to answer.

The question is:

" How can I declare an array with only one element and still access elements beyond the first element (in a valid fashion)? "

But, I could not answer, Can anyone please help me to solve this problem?

Thanx in advance

Suyash
Jun 7 '07 #1
Share this Question
Share on Google+
6 Replies


Expert 100+
P: 181
Hello all,
I got one question from my colleagues to answer.

The question is:

" How can I declare an array with only one element and still access elements beyond the first element (in a valid fashion)? "

But, I could not answer, Can anyone please help me to solve this problem?

Thanx in advance

Suyash
You can do something like this
Expand|Select|Wrap|Line Numbers
  1. struct dynamic
  2. {
  3. int a[1]
  4. };
  5.  
struct dynamic * ptr = (struct dynamic *) malloc(size of struct dynamic + 100 * sizeof(int));

now u can use ptr->a[1], ..... 100

Many say this code is not portable. But i really dont know y they say so. :(
Jun 7 '07 #2

P: 33
Hello all,

" How can I declare an array with only one element and still access elements beyond the first element (in a valid fashion)? "
If you declare an array of one or several elements using [] or pointers (*), it seems to me there is no way to access elements beyond the range you specify in your declaration and safely ensure the integrity of the data at this position. I mean if you do:

Expand|Select|Wrap|Line Numbers
  1. char array1[]="a" //fixed size array of 1 element
  2. char *array2="a" //variable size array, currently dimensioned for 1 element
  3.  
You would be able to retrieve the character 'a' by doing:

Expand|Select|Wrap|Line Numbers
  1. std::cout << array1[0] // Outputs 'a'
  2. std::cout << array2[0] << *array2(0) // Outputs "aa"
  3.  
Anything you try to retrieve beyond the range of your array is undefined. It's because this space of memory is not reserved for your array, so any other process might me using it, or not, so you can't predict what is its content. Furthermore, you should not write in a memory address not allocated specifically for your process, as you might alter data used by another program.

Actually, the array definition written above could also be done the following way and it would be exactly the same:

Expand|Select|Wrap|Line Numbers
  1. char array1[]={'a','/0'}
  2. char *array2={'a','/0'}
  3.  
So it's really in trying to retrieve array1[2] and array2[2] that you will not know what you'll get.

Finally, there is no way to access valid data outside the range you specify.

However, while when you declare a fixed size array you're stuck with it in your entire program, if you declare a variable size array, then you could redefine it several times.


Ras.
Jun 7 '07 #3

P: 34
Thanx for your reply,

But why it is necessary to use pointers:-

Following code produces same result upto some extent( till 4th-5th elements):-

Expand|Select|Wrap|Line Numbers
  1. #include<iostream>
  2. using namespace std;
  3.  
  4. struct exp
  5. {
  6.     int a[1];
  7. };
  8.  
  9.  
  10. int main()
  11. {
  12.     struct exp s;
  13.     for(int i=0;i<4;i++)
  14.         s.a[i]=i;
  15.     cout<<endl;
  16.     for(int i=0;i<4;i++)
  17.         cout<<s.a[i]<<" ";
  18.     return 0;
  19. }
  20.  
Why is it so?

Please help me,

Thanx
Jun 7 '07 #4

AdrianH
Expert 100+
P: 1,251
Thanx for your reply,

But why it is necessary to use pointers:-

Following code produces same result upto some extent( till 4th-5th elements):-

Expand|Select|Wrap|Line Numbers
  1. #include<iostream>
  2. using namespace std;
  3.  
  4. struct exp
  5. {
  6.     int a[1];
  7. };
  8.  
  9.  
  10. int main()
  11. {
  12.     struct exp s;
  13.     for(int i=0;i<4;i++)
  14.         s.a[i]=i;
  15.     cout<<endl;
  16.     for(int i=0;i<4;i++)
  17.         cout<<s.a[i]<<" ";
  18.     return 0;
  19. }
  20.  
Why is it so?

Please help me,

Thanx
It works, but it is overwriting data that doesn't belong to it. As svlsr2000 said, you need to allocate the extra amount or you will bleed into another memory location that may be used by some other object and may also corrupt the heap/stack. Generally considered a bad thing. ;)

If using a struct/class with a constructor, you may wish to do it this way:
Expand|Select|Wrap|Line Numbers
  1. #include<iostream>
  2. using namespace std;
  3.  
  4. struct exp
  5. {
  6.   int a[1];
  7.  
  8.   static size_t sizeOfExp(size_t numElements)
  9.   {
  10.     return sizeof(exp) + sizeof(int) * (numElements-1);
  11.   }
  12.  
  13.   static exp* allocate(size_t numElements)
  14.   {
  15.     // inplace constructor
  16.     return new(::operator new(sizeOfExp(numElements))) exp();
  17.   }
  18. };
  19.  
  20.  
  21. int main()
  22. {
  23.     exp * s = exp::allocate(20);
  24.     for(int i=0;i<4;i++)
  25.         s->a[i]=i;
  26.     cout<<endl;
  27.     for(int i=0;i<4;i++)
  28.         cout<<s->a[i]<<" ";
  29.     delete s;
  30.     return 0;
  31. }
However, if your array is not a base type, you should also override the delete operator and keep track of the number of elements with a variable.

You can remove this problem using a template, but that brings other issues.
Expand|Select|Wrap|Line Numbers
  1. template<int size>
  2. struct exp
  3. {
  4.   int a[size];
  5. };
  6.  
C/C++ does not do bounds checking on raw arrays. Some containers may, but I'm not sure if the STL ones do.


Adrian
Jun 7 '07 #5

P: 33
But why it is necessary to use pointers:-
It's got nothing to do with using pointers or not, or using structs or not. Chek my previous answer, it also tells why you can't do:


Expand|Select|Wrap|Line Numbers
  1. struct exp
  2. {
  3.     int a[1];
  4. };
  5.  
  6. int main()
  7. {
  8.         ...
  9.     for(int i=0;i<4;i++)
  10.         cout<<s.a[i]<<" ";
  11.     return 0;
  12. }
  13.  
With the answer of svrsl2000 you dynamically dimension a "special array" (sum of structs), composed of regular arrays with unitary size. But still, you can't try to access the 101th struct if you declare only 100.

You might find the last line of his code clearer if written like this:
Expand|Select|Wrap|Line Numbers
  1. for (i=0, i<=10,i++){
  2.     ptr = new dynamic;
  3. }
  4.  
That's to reserve the place for 11 of your structs. Then if you want to access them, you do a linked list (because you need to know their location in memory). But in no way you can try to access the 11th element and expect a non-garbage output.
Jun 7 '07 #6

AdrianH
Expert 100+
P: 1,251
Or a seg fault/page fault. Sometimes there is no physical memory allocated after an allocated section. On OSs that support memory mapping this can be done to catch boundry overrun errors.


Adrian
Jun 9 '07 #7

Post your reply

Sign in to post your reply or Sign up for a free account.