Output array values, get 4 elements in turn, result

1.000000 0.000000 -nan -nan 0.000000 

different from expected

 class DataSrc{ int current_position; int dlina; double * curent_elem; public: DataSrc(){ current_position=0; dlina=4; double histori[]={1, 2, 3, 7, 6, 2, 4, 3, 2}; curent_elem=&histori[0]; } double * GetNext(){ if(current_position>dlina){ return 0; } current_position++; return curent_elem+current_position-1; } }; int main(){ DataSrc MyData; double *eee=MyData.GetNext(); while(eee){ printf(" %lf ",*eee); eee=MyData.GetNext(); } return 0; } 

How to do it right, why the popular advice from textbooks about getting the next value "address ++" does not work here?

  • doesn't work because you don't use it this way :) - Sublihim

2 answers 2

Because you created a local array of histori , which, after exiting the constructor, is destroyed, and store the pointer in FIG where ...

If you want to work, for example, like this:

 class DataSrc { int current_position; int dlina; double * curent_elem; double * histori; public: DataSrc() { histori = new double[9]{1, 2, 3, 7, 6, 2, 4, 3, 2}; current_position = 0; dlina = 4; curent_elem = &histori[0]; } ~DataSrc() { delete[] histori; } double * GetNext() { if(current_position>dlina) return 0; return curent_elem+current_position++; } }; int main() { DataSrc MyData; double *eee=MyData.GetNext(); while(eee){ printf(" %lf ",*eee); eee=MyData.GetNext(); } return 0; } 

(the question of how to write so that not only works, but also makes sense, is not yet considered).

    As already noted, this declaration in the class constructor

      DataSrc(){ current_position=0; dlina=4; double histori[]={1, 2, 3, 7, 6, 2, 4, 3, 2}; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ curent_elem=&histori[0]; } 

    is a local array declaration with automatic storage time. That is, the lifetime of this array is completed after exiting the constructor. Therefore, accessing this array outside the body of the constructor leads to undefined program behavior.

    To be able to periodically access an array of class methods, you should make this array a member of the class.

    You have some redundancy in your class member data declarations. Of these two members of the class

     int current_position; double * curent_elem; 

    it is enough to have only one member of the current_position class, since the second member of the curent_elem class curent_elem always be obtained with the first member of the class.

    You can initialize an array member of a class by passing a pointer to the constructor to the first element of an array used as an argument and its size. Or you can use the initialization list as a parameter.

    It is also desirable to include the method that sets the current_position data member to the initial value in the minimum set of class methods, or it is simpler to call it as position .

    Below is a certain class framework that can be developed further by increasing its methods. This example uses the standard class std::unique_ptr . The sooner you start using standard tools from the C ++ library, the sooner you get used to them and master them.

     #include <iostream> #include <memory> #include <initializer_list> #include <algorithm> template <typename T> class DataSrc { private: size_t n; std::unique_ptr<T[]> p; mutable size_t position; public: DataSrc() : n( 0 ), p( nullptr ), position( 0 ) { } DataSrc( const T *p, size_t n ) : n( n ), p( new T[n] ), position( 0 ) { std::copy( p, p + n, DataSrc::p.get() ); } DataSrc( std::initializer_list<T> lst ) : n( lst.size() ), p( new T[lst.size()] ), position( 0 ) { std::copy( lst.begin(), lst.end(), DataSrc::p.get() ); } size_t size() const { return n; } const T * GetNext() const { return position == n ? nullptr : p.get() + position++; } T * GetNext() { return position == n ? nullptr : p.get() + position++; } void Reset() { position = 0; } void Reset() const { position = 0; } }; int main() { int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, }; DataSrc<int> data1( a, sizeof( a ) / sizeof( *a ) ); while ( int *current = data1.GetNext() ) std::cout << *current << ' '; std::cout << std::endl; DataSrc<int> data2( { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, } ); while ( int *current = data2.GetNext() ) std::cout << *current << ' '; std::cout << std::endl; data2.Reset(); while ( int *current = data2.GetNext() ) std::cout << *current << ' '; std::cout << std::endl; return 0; } 

    Output of the program to the console

     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 

    In this example, the class lacks the copy and / or move constructors and, accordingly, the copy and / or move assignment operator. You can try to write them yourself and, if there are difficulties, ask the corresponding question on the forum.