Zoeken…


Invoering

Arrays zijn elementen van hetzelfde type die op aangrenzende geheugenlocaties worden geplaatst. De elementen kunnen individueel worden aangeduid door een unieke identificatiecode met een toegevoegde index.

Hiermee kunt u meerdere variabele waarden van een specifiek type declareren en deze afzonderlijk openen zonder dat u voor elke waarde een variabele hoeft te declareren.

Matrixgrootte: typ veilig tijdens het compileren.

#include <stddef.h>     // size_t, ptrdiff_t

//----------------------------------- Machinery:

using Size = ptrdiff_t;

template< class Item, size_t n >
constexpr auto n_items( Item (&)[n] ) noexcept
    -> Size
{ return n; }


//----------------------------------- Usage:

#include <iostream>
using namespace std;
auto main()
    -> int
{
    int const   a[]     = {3, 1, 4, 1, 5, 9, 2, 6, 5, 4};
    Size const  n       = n_items( a );
    int         b[n]    = {};       // An array of the same size as a.
    
    (void) b;
    cout << "Size = " << n << "\n";
}

Het C-idioom voor sizeof(a)/sizeof(a[0]) , sizeof(a)/sizeof(a[0]) , accepteert een pointer als argument en levert dan meestal een onjuist resultaat op.

Voor C ++ 11

met C ++ 11 kunt u het volgende doen:

std::extent<decltype(MyArray)>::value;

Voorbeeld:

char MyArray[] = { 'X','o','c','e' };
const auto n = std::extent<decltype(MyArray)>::value;
std::cout << n << "\n"; // Prints 4

Tot C ++ 17 (vanaf dit schrijven beschikbaar) C ++ had geen ingebouwde kerntaal of standaard bibliotheekhulpprogramma om de grootte van een array te verkrijgen, maar dit kan worden geïmplementeerd door de array door te geven aan een functiesjabloon, zoals hierboven weergegeven. Prima, maar belangrijk punt: de sjabloon formaat parameter is een size_t , enigszins in strijd met de ondertekende Size typefunctie resultaat, om tegemoet te komen aan de g ++ compiler die soms dringt aan op size_t voor template matching.

Met C ++ 17 en later kan men in plaats daarvan std::size , wat gespecialiseerd is voor arrays.

Dynamische onbewerkte array

// Example of raw dynamic size array. It's generally better to use std::vector.
#include <algorithm>            // std::sort
#include <iostream>
using namespace std;

auto int_from( istream& in ) -> int { int x; in >> x; return x; }

auto main()
    -> int
{
    cout << "Sorting n integers provided by you.\n";
    cout << "n? ";
    int const   n   = int_from( cin );
    int*        a   = new int[n];       // ← Allocation of array of n items.
    
    for( int i = 1; i <= n; ++i )
    {
        cout << "The #" << i << " number, please: ";
        a[i-1] = int_from( cin );
    }

    sort( a, a + n );
    for( int i = 0; i < n; ++i ) { cout << a[i] << ' '; }
    cout << '\n';
    
    delete[] a;
}

Een programma dat een array T a[n]; verklaart T a[n]; waarbij n een runtime wordt bepaald, kan deze worden gecompileerd met bepaalde compilers die C99 variadic length arrays (VLA's) ondersteunen als taalextensie. Maar VLA's worden niet ondersteund door standaard C ++. Dit voorbeeld laat zien hoe u handmatig een array met dynamische grootten kunt toewijzen via een new[] -expressie,

int*        a   = new int[n];       // ← Allocation of array of n items.

... gebruik het dan en verwijder het uiteindelijk via een delete[] -expressie:

delete[] a;

De hier toegewezen array heeft onbepaalde waarden, maar kan nul worden geïnitialiseerd door een lege haakjes () toe te voegen, zoals deze: new int[n]() . Meer in het algemeen voert dit voor een willekeurig itemtype een waarde-initialisatie uit .

Als onderdeel van een functie in een aanroephiërarchie zou deze code niet uitzonderlijk veilig zijn, omdat een uitzondering vóór de delete[] -expressie (en na de new[] ) een geheugenlek zou veroorzaken. Een manier om dat probleem aan te pakken, is door het opschonen te automatiseren via bijvoorbeeld een slimme aanwijzer std::unique_ptr . Maar een over het algemeen betere manier om dit aan te pakken, is gewoon een std::vector : daar is std::vector voor.

Matrix met dynamische grootte uitbreiden met std :: vector.

// Example of std::vector as an expanding dynamic size array.
#include <algorithm>            // std::sort
#include <iostream>
#include <vector>               // std::vector
using namespace std;

int int_from( std::istream& in ) { int x = 0; in >> x; return x; }

int main()
{
    cout << "Sorting integers provided by you.\n";
    cout << "You can indicate EOF via F6 in Windows or Ctrl+D in Unix-land.\n";
    vector<int> a;      // ← Zero size by default.

    while( cin )
    {
        cout << "One number, please, or indicate EOF: ";
        int const x = int_from( cin );
        if( !cin.fail() ) { a.push_back( x ); }  // Expands as necessary.
    }

    sort( a.begin(), a.end() );
    int const n = a.size();
    for( int i = 0; i < n; ++i ) { cout << a[i] << ' '; }
    cout << '\n';
}

std::vector is een standaardbibliotheekklasse-sjabloon die het idee van een array met variabele grootte biedt. Het zorgt voor al het geheugenbeheer en de buffer is aaneengesloten, zodat een pointer naar de buffer (bijvoorbeeld &v[0] of v.data() ) kan worden doorgegeven aan API-functies die een onbewerkte array vereisen. Een vector kan zelfs tijdens runtime worden uitgebreid, bijvoorbeeld via de functie push_back member die een item push_back .

De complexiteit van de reeks n push_back , inclusief het kopiëren of verplaatsen van de push_back , wordt afgeschreven O ( n ). "Geamortiseerd": gemiddeld.

Intern wordt dit meestal bereikt door de vector die zijn buffergrootte, zijn capaciteit verdubbelt, wanneer een grotere buffer nodig is. Bijv. Voor een buffer die begint met grootte 1 en herhaaldelijk wordt verdubbeld als nodig voor n = 17 push_back oproepen, omvat dit 1 + 2 + 4 + 8 + 16 = 31 kopieerbewerkingen, wat minder is dan 2 × n = 34. En meer in het algemeen mag de som van deze reeks niet groter zijn dan 2 × n .

Vergeleken met het voorbeeld van de onbewerkte array met dynamische grootte, vereist deze vector code niet dat de gebruiker vooraf het aantal items opgeeft (en weet). In plaats daarvan wordt de vector zo nodig uitgebreid voor elke nieuwe itemwaarde die door de gebruiker wordt opgegeven.

Een onbewerkte matrix met een vaste grootte (dat wil zeggen een 2D onbewerkte matrix).

// A fixed size raw array matrix (that is, a 2D raw array).
#include <iostream>
#include <iomanip>
using namespace std;

auto main() -> int
{
    int const   n_rows  = 3;
    int const   n_cols  = 7;
    int const   m[n_rows][n_cols] =             // A raw array matrix.
    {
        {  1,  2,  3,  4,  5,  6,  7 },
        {  8,  9, 10, 11, 12, 13, 14 },
        { 15, 16, 17, 18, 19, 20, 21 }
    };
    
    for( int y = 0; y < n_rows; ++y )
    {
        for( int x = 0; x < n_cols; ++x )
        {
            cout << setw( 4 ) << m[y][x];       // Note: do NOT use m[y,x]!
        }
        cout << '\n';
    }
}

Output:

   1   2   3   4   5   6   7
   8   9  10  11  12  13  14
  15  16  17  18  19  20  21

C ++ ondersteunt geen speciale syntaxis voor het indexeren van een multidimensionale array. In plaats daarvan wordt een dergelijke array gezien als een array van arrays (mogelijk van arrays, enzovoort), en de gewone notatie met enkele index [ i ] wordt gebruikt voor elk niveau. In het bovenstaande voorbeeld verwijst m[y] naar rij y van m , waarbij y een op nul gebaseerde index is. Vervolgens kan deze rij om de beurt worden geïndexeerd, bijvoorbeeld m[y][x] , die verwijst naar het x de item - of kolom - van rij y .

Dwz de laatste index varieert het snelst, en in de verklaring is het bereik van deze index, dat hier het aantal kolommen per rij is, de laatste en "binnenste" opgegeven grootte.

Omdat C ++ geen ingebouwde ondersteuning biedt voor dynamische grootteklassificaties, anders dan dynamische toewijzing, wordt een dynamische groottematrix vaak geïmplementeerd als een klasse. Dan heeft de ruwe matrixindex-notatie m[y][x] enige kosten, hetzij door de implementatie bloot te leggen (zodat bijvoorbeeld een weergave van een getransponeerde matrix praktisch onmogelijk wordt) of door wat overhead en licht ongemak toe te voegen wanneer dit wordt gedaan door terug te keren een proxy-object van operator[] . En dus kan en zal de indexnotatie voor een dergelijke abstractie meestal verschillen, zowel qua uiterlijk als in de volgorde van indices, bijvoorbeeld m(x,y) of m.at(x,y) of m.item(x,y) .

Een dynamische groottematrix met std :: vector voor opslag.

Helaas is er vanaf C ++ 14 geen dynamische groottematrixklasse in de C ++ standaardbibliotheek. Matrix klassen die steun dynamische grootte zijn echter verkrijgbaar bij een aantal 3rd party bibliotheken, waaronder de Boost Matrix bibliotheek (een sub-bibliotheek binnen de Boost bibliotheek).

Als je geen afhankelijkheid van Boost of een andere bibliotheek wilt, dan is de dynamische groottematrix van een arme man in C ++ net als

vector<vector<int>> m( 3, vector<int>( 7 ) );

... waar vector std::vector . De matrix wordt hier gemaakt door een rijvector n keer te kopiëren waarbij n het aantal rijen is, hier 3. Het heeft het voordeel dat het dezelfde m[y][x] indexnotatie biedt als voor een onbewerkte matrixmatrix met een vaste grootte, maar het is een beetje inefficiënt omdat het een dynamische toewijzing voor elke rij inhoudt, en het is een beetje onveilig omdat het mogelijk is om per ongeluk het formaat van een rij te wijzigen.

Een veiligere en efficiëntere aanpak is om een enkele vector als opslag voor de matrix te gebruiken en de klantcode ( x , y ) toe te wijzen aan een overeenkomstige index in die vector:

// A dynamic size matrix using std::vector for storage.

//--------------------------------------------- Machinery:
#include <algorithm>        // std::copy
#include <assert.h>         // assert
#include <initializer_list> // std::initializer_list
#include <vector>           // std::vector
#include <stddef.h>         // ptrdiff_t

namespace my {
    using Size = ptrdiff_t;
    using std::initializer_list;
    using std::vector;

    template< class Item >
    class Matrix
    {
    private:
        vector<Item>    items_;
        Size            n_cols_;
        
        auto index_for( Size const x, Size const y ) const
            -> Size
        { return y*n_cols_ + x; }

    public:
        auto n_rows() const -> Size { return items_.size()/n_cols_; }
        auto n_cols() const -> Size { return n_cols_; }

        auto item( Size const x, Size const y )
            -> Item&
        { return items_[index_for(x, y)]; }
        
        auto item( Size const x, Size const y ) const
            -> Item const&
        { return items_[index_for(x, y)]; }

        Matrix(): n_cols_( 0 ) {}

        Matrix( Size const n_cols, Size const n_rows )
            : items_( n_cols*n_rows )
            , n_cols_( n_cols )
        {}
        
        Matrix( initializer_list< initializer_list<Item> > const& values )
            : items_()
            , n_cols_( values.size() == 0? 0 : values.begin()->size() )
        {
            for( auto const& row : values )
            {
                assert( Size( row.size() ) == n_cols_ );
                items_.insert( items_.end(), row.begin(), row.end() );
            }
        }
    };
}  // namespace my

//--------------------------------------------- Usage:
using my::Matrix;

auto some_matrix()
    -> Matrix<int>
{
    return
    {
        {  1,  2,  3,  4,  5,  6,  7 },
        {  8,  9, 10, 11, 12, 13, 14 },
        { 15, 16, 17, 18, 19, 20, 21 }
    };
}

#include <iostream>
#include <iomanip>
using namespace std;
auto main() -> int
{
    Matrix<int> const m = some_matrix();
    assert( m.n_cols() == 7 );
    assert( m.n_rows() == 3 );
    for( int y = 0, y_end = m.n_rows(); y < y_end; ++y )
    {
        for( int x = 0, x_end = m.n_cols(); x < x_end; ++x )
        {
            cout << setw( 4 ) << m.item( x, y );        // ← Note: not `m[y][x]`!
        }
        cout << '\n';
    }
}

Output:

   1   2   3   4   5   6   7
   8   9  10  11  12  13  14
  15  16  17  18  19  20  21

De bovenstaande code is niet van industriële kwaliteit: het is ontworpen om de basisprincipes te tonen en te voldoen aan de behoeften van studenten die C ++ leren.

Men kan bijvoorbeeld operator() overbelastingen definiëren om de indexnotatie te vereenvoudigen.

Initialisatie van de array

Een array is slechts een blok opeenvolgende geheugenlocaties voor een specifiek type variabele. Arrays worden op dezelfde manier toegewezen als normale variabelen, maar met vierkante haken toegevoegd aan de naam [] die het aantal elementen bevatten dat in het arraygeheugen past.

Het volgende voorbeeld van een array gebruikt het type int , de variabelenaam arrayOfInts en het aantal elementen [5] waar de array ruimte voor heeft:

int arrayOfInts[5];

Een array kan tegelijkertijd als volgt worden gedeclareerd en geïnitialiseerd

int arrayOfInts[5] = {10, 20, 30, 40, 50};

Bij het initialiseren van een array door alle leden op te sommen, is het niet nodig om het aantal elementen tussen vierkante haken op te nemen. Het wordt automatisch berekend door de compiler. In het volgende voorbeeld is het 5:

int arrayOfInts[] = {10, 20, 30, 40, 50};

Het is ook mogelijk om alleen de eerste elementen te initialiseren terwijl meer ruimte wordt toegewezen. In dit geval is het verplicht om de lengte tussen haakjes te definiëren. Het volgende zal een array van lengte 5 toewijzen met gedeeltelijke initialisatie, de compiler initialiseert alle resterende elementen met de standaardwaarde van het elementtype, in dit geval nul.

int arrayOfInts[5] = {10,20}; // means 10, 20, 0, 0, 0

Arrays van andere basistypen kunnen op dezelfde manier worden geïnitialiseerd.

char arrayOfChars[5]; // declare the array and allocate the memory, don't initialize

char arrayOfChars[5] = { 'a', 'b', 'c', 'd', 'e' } ; //declare and initialize

double arrayOfDoubles[5] = {1.14159, 2.14159, 3.14159, 4.14159, 5.14159};

string arrayOfStrings[5] = { "C++", "is", "super", "duper", "great!"};

Het is ook belangrijk op te merken dat bij het openen van matrixelementen de elementindex (of positie) van de matrix begint vanaf 0.

int array[5] = { 10/*Element no.0*/, 20/*Element no.1*/, 30, 40, 50/*Element no.4*/};
std::cout << array[4]; //outputs 50
std::cout << array[0]; //outputs 10


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow