Er det noen måte å passere en anonym matrise som et argument i C ++?

stemmer
23

Jeg ønsker å være i stand til å erklære en matrise som en funksjon argument i C ++, som vist i eksemplet nedenfor koden (som ikke kompilere). Er det noen måte å gjøre dette på (annet enn å erklære rekke separat på forhånd)?

#include <stdio.h>

static void PrintArray(int arrayLen, const int * array)
{
   for (int i=0; i<arrayLen; i++) printf(%i -> %i\n, i, array[i]);
}

int main(int, char **)
{
   PrintArray(5, {5,6,7,8,9} );  // doesn't compile
   return 0;
}
Publisert på 16/07/2009 klokken 22:16
kilden bruker
På andre språk...                            


13 svar

stemmer
27

Hvis du bruker eldre C ++ varianter (pre-C ++ 0x), da dette ikke er tillatt. Den "anonyme array" du refererer til er faktisk en initializer liste . Nå som C ++ 11 er ute, kan dette gjøres med den innebygde initializer_listtypen. Du teoretisk kan også bruke den som en C-stil initializer listen ved hjelp extern C, hvis kompilatoren analyserer dem som C99 eller senere .

For eksempel:

int main()
{
    const int* p;
    p = (const int[]){1, 2, 3};
}
Svarte 16/07/2009 kl. 22:19
kilden bruker

stemmer
4

Ja og nei. I den nåværende versjonen av standarden (ISO C ++ 1998 med ammendments fra 2003), er det ikke mulig. Men i neste versjon av standarden "C ++ 0x" (som, til tross for navnet antyder at det vil bli gitt ut i 200x, vil mest sannsynlig bli utgitt i 2010), vil det være mulig med std :: initializer_list <> .

Svarte 16/07/2009 kl. 22:22
kilden bruker

stemmer
-3

Nei, og det er dårlig koding praksis uansett. Bare erklære const int* foo = {5,6,7,8,9};før funksjonskall. Selv om dette fungerte, ville det ikke fart på programmet eller kompilere tid. Verdiene vil fortsatt trenger å bli tildelt i minnet og gått gjennom funksjonskall.

Svarte 16/07/2009 kl. 22:22
kilden bruker

stemmer
19

Dette kompilerer, men jeg vil ikke anbefale det.

#include <stdio.h>

struct arr
{
   int array[5];
};

static void PrintArray(int arrayLen, arr array)
{
   for (int i=0; i<arrayLen; i++) printf("%i -> %i\n", i, array.array[i]);
}

int main(int, char **)
{
   PrintArray(5, (arr){5,6,7,8,9});
   return 0;
}
Svarte 16/07/2009 kl. 22:28
kilden bruker

stemmer
2

Du kan bruke et variabelt antall argumenter i stedet for å passere en rekke:

static void PrintArray(int arrayLen, ...)
{
   int this_value;
   va_list array;

   va_start(array, arrayLen);
   for (int i=0; i<arrayLen; i++) 
   {
     this_value = va_arg(array, int);
     printf("%i -> %i\n", i, this_value);
   }
   va_end(array);
}

Jeg hadde ikke kompilere dette så jeg sannsynligvis gjort en feil eller to, men forhåpentligvis er det nært nok. Slå opp va_start for referanse.

Svarte 16/07/2009 kl. 22:36
kilden bruker

stemmer
7

Disclaimer: For dette svaret får jeg noen downvotes, men det stammer fra 2009, der C ++ 11 var i ferd med å bli definert. For moderne C ++ kan du bla nedenfor.

Vel, prøv å bruke boost ...

Her er løsningen å bruke boost :: tildele bibliotek og litt mer C ++ som programmerings;)

#include <boost/assign/list_of.hpp>

#include <iostream>
#include <algorithm>


namespace
{
  template<class CollectionT>
  void print(CollectionT const& coll)
  {
    std::ostream_iterator<int> out(std::cout, ", ");
    std::copy(coll.begin(), coll.end(), out);
  }
}



int main()
{
  using namespace boost::assign;

  print( list_of(1)(2)(3)(4)(5) );

  return 0;
}

C ++ 11 og høyere med forklaring av spesielle funksjoner

Holdt klang: clang++ -std=c++14 -I /usr/local/include/ main.cpp

#include <boost/assign/list_of.hpp>

#include <iostream>
#include <iterator>
#include <algorithm>
#include <initializer_list>


template<typename CollectionT, typename OStream>
auto // <- auto result type deduction from C++ 14
  make_output_iterator(CollectionT const& coll, OStream& out)
{
  return std::ostream_iterator<typename CollectionT::value_type>(out, ", ");
}

// here template specialization is used, to demonstrate initializer lists from C++ 11
template<typename T>
void print(std::initializer_list<T> items)
//         ^----------------------^ passed by value due to move semantics
{
  using namespace std;
  cout << "printing an initializer list: ";
  copy(items.begin(), items.end(), make_output_iterator(items, cout));
  cout << endl;
}


template<typename CollectionT>
void print(CollectionT const& items)
{
  using namespace std;
  cout << "printing another collection type: ";
  copy(items.begin(), items.end(), make_output_iterator(items, cout));
  cout << endl;
}


int main()
{
  print({0,1,2,3,4,5,6,7,9});

  using namespace boost::assign;
  print( list_of(0)(1)(2)(3)(4)(5)(6)(7)(8)(9) );
}
Svarte 16/07/2009 kl. 23:02
kilden bruker

stemmer
28

Det er tillatt med en typecast i C ++ 11 og extern "C"med C99:

void PrintArray(size_t len, const int *array)
{
    for(size_t i = 0; i < len; i++)
        printf("%d\n", array[i]);
}

int main(int argc, char **argv)
{
    PrintArray(5, (const int[]){1, 2, 3, 4, 5});
    return 0;
}
Svarte 16/07/2009 kl. 23:17
kilden bruker

stemmer
1

Et annet valg ville være å bruke matrisen i TR1 biblioteket som er sannsynlig å bli en del av den neste standarden og støttes av mange kompilatorer.

#include <array>
#include <algorithm>
#include <iostream>

using std::tr1::array;
using std::cout;
using std::copy;
using std::ostream_iterator;

template <class Container>
void PrintArray(Container &values)
{
  copy(values.begin(), values.end(), ostream_iterator<int>(cout, "\n"));
}

int main()
{
  array<int, 5> values = {1, 2, 3, 4, 5};
  PrintArray(values);
}
Svarte 17/07/2009 kl. 00:08
kilden bruker

stemmer
4

Med C ++ 0x kan du bruke en std::initializer_list(og en foreach loop)

#include <iostream>
#include <initializer_list>

void print (const std::initializer_list<int>& array)
{
    for (auto x : array) // C++0x foreach loop
        std::cout << x << std::endl;
}

int main (int argc, char ** argv)
{
    print ({ 1, 2, 3, 4, 5 });
}

Svarte 15/04/2010 kl. 19:51
kilden bruker

stemmer
0

Du kan gjøre dette i ANSI-C ved hjelp av god ol' va_list

Malbaserte C ++ med et std::vectorreturneres for bekvemmelighet i tillegg

#include <stdarg.h>
#include <vector>
using namespace std ;

struct Point
{
  int x,y;
  Point():x(0),y(0){}
  Point( int ix, int iy ):x(ix),y(iy){}
  ~Point(){printf("%d %d - the point has been destroyed!\n",x,y);}
  void print(){printf("%d,%d\n",x,y);}
} ;

// Concrete example using a list of int
int* initFrom( int numItems, ... )
{
  int* list = new int[ numItems ] ;

  va_list listPointer;
  va_start( listPointer, numItems );

  for( int i = 0 ; i < numItems; i++ )
    list[ i ] = va_arg( listPointer, int ) ;

  return list ;
}

// templatized version.
template <typename T> vector<T> initFrom( int numItems, ... )
{
  vector<T> list ;
  list.resize( numItems ) ;

  va_list listPointer;
  va_start( listPointer, numItems );

  for( int i = 0 ; i < numItems; i++ )
    list[ i ] = va_arg( listPointer, T ) ;

  return list ;
}

int main()
{
  int* theList = initFrom( 4, 900, 2000, 1000, 100 ) ;
  for( int i = 0 ; i < 4 ; i++ )
    printf( "Item %d=%d\n", i, theList[i] );

  puts( "\n\n--Lots of destruction using non-ptr" ) ;
  vector<Point> thePoints = initFrom<Point>( 3, Point(3,7), Point(4,5), Point(99,99) ) ;
  puts( "Our listing:" ) ;
  for( int i = 0 ; i < 3 ; i++ )
    thePoints[i].print() ;

  puts( "\n\n-- Less destruction using ptr" ) ;
  // Be careful of extra copy construction. Using a vector of pointers
  // will avoid that
  vector<Point*> theNewPoints = initFrom<Point*>( 3, new Point(300,700), new Point(400,500), new Point(990,990) ) ;
  puts( "Our listing:" ) ;
  for( int i = 0 ; i < 3 ; i++ )
    theNewPoints[i]->print() ;

  puts( "END OF PROGRAM --" ) ;
}
Svarte 28/08/2011 kl. 22:36
kilden bruker

stemmer
2

Du kan bruke std :: initializer_list liste Joe D antyder, men jeg er ikke sikker på at du kan bruke den hvis du vil at andre parametere. (Jeg kan ikke synes å finne noe informasjon om det.) Men hvis du deklarerer en const referanse til en vektor, den initializer_list som er opprettet med {...} vil bli konvertert til vektoren.

#include <iostream>
#include <vector>

void PrintArray(const char* prefix, const std::vector<int>& array)
{
    std::cout << prefix << std::endl;
    for (int i : array) {
        std::cout << i << std::endl;
    }
}

int main(int, char **)
{
    PrintArray("test array", {5,6,7,8,9} );
    return 0;
}
Svarte 27/07/2016 kl. 20:04
kilden bruker

stemmer
2

Starter fra C ++ 11, kan du bare bruke std::begin(std::initializer_list const&)for å få pekeren. Eksempel:

#include <iostream>
void func(int len, const int* x)
{
    for(int i=0;i<len;++i)
        std::cout << x[i] << "\n";
}
int main()
{
    func(5, std::begin({1,3,6,823,-35}));
}

I motsetning til den aksepterte svaret, er dette virkelig Standard-kompatibel kode.

Svarte 16/05/2017 kl. 09:45
kilden bruker

stemmer
0

Her er en enkel ren løsning for å få en C-stil array som ingen andre har nevnt:

#include <iostream>

using namespace std;

template <int N>
int
get_last( const int ( &my_array )[N] ) {
  return my_array[N-1];
}


int main()
{
    cout << "Last: " << get_last( { 1, 2, 3, 55 } );

    return 0;
}
Svarte 26/09/2017 kl. 16:53
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more