Newsgroup: it.comp.lang.c++
Titolo: Passaggio di array a funzione

 
Ho provato ad aggiungere (al fine di controllare e stampare il valore
di n nel for) l'istruzione: cout<<n<<endl nel seguente programma di
esempio al link:
 
http://cplusplus.com/doc/tutorial/arrays/
 
 
=====================================
 
 
// arrays as parameters
#include <iostream>
using namespace std;
 
void printarray (int arg[], int length) {
  for (int n=0; n<length; n++)
 
  cout<<n<<endl; //riga aggiunta
 
  cout << arg[n]<< " ";
 
  cout << "\n";
}
 
int main ()
{
  int firstarray[] = {5, 10, 15};
  int secondarray[] = {2, 4, 6, 8, 10};
  printarray (firstarray,3);
  printarray (secondarray,5);
 
 
  return 0;
}
 
====================================
 
ma ottengo l'errore:
 
"C:\Users\Desktop\Programmi\main.cpp||In function 'void
printarray(int*, int)':|
C:\Users\Desktop\Programmi\main.cpp|11|error: 'n' was not declared in
this scope|
||=== Build finished: 1 errors, 0 warnings (0 minutes, 0 seconds)
===|"
 
La riga 11 corrisponde all'istruzione:
 
cout << arg[n]<< " ";
 
...NON capisco dove sbaglio! :-((
 
 
Ciao e grazie mille!
 

 
 
Controlla le parentesi
 
 
Ciao!


Ciao,
come gi� segnalatoti, l'errore � dovuto alla mancanza delle parentesi {} 
nel ciclo for.
Errore a parte, cerca di abituarti quanto prima ad evitare di utilizzare 
i cosiddetti "numeri magici" nel codice, anche se potrebbe essere un p� 
troppo presto per il tuo livello di conoscenza del linguaggio (leggi: 
entriamo dell'ambito dei template).
Nel tuo caso, i "numeri magici" sono il 3 ed il 5 nelle seguenti due righe:
=====================================
   printarray (firstarray,3);
   printarray (secondarray,5);
=====================================
Prova a vedere cosa succede se modifichi la riga
=====================================
   int secondarray[] = {2, 4, 6, 8, 10};
=====================================
in
=====================================
   int secondarray[] = {2, 4, 6, 8};
=====================================
senza modificare il resto del programma.
Per evitare problemi, puoi crearti una funzione del tipo
=====================================
template <typename T, size_t N>
inline
size_t SizeOfArray( const T(&)[ N ] )
{
   return N;
}
=====================================
ed utilizzare la suddetta funzione dove serve, modificando le due 
chiamate a printarray come segue:
=====================================
   printarray (firstarray,SizeOfArray(firstarray));
   printarray (secondarray,SizeOfArray(secondarray));
=====================================
Vedi "
http://www.cplusplus.com/faq/sequences/arrays/sizeof-array/
" per 
ulteriori dettagli.
 
Meglio ancora, ma questo lo scoprirai solo quando prenderai un p� di 
dimestichezza con i template, potresti modificare la dichiarazione della 
funzione printarray come segue:
=====================================
template <size_t length>
void printarray (int (&arg)[length])
=====================================
(lasciando inalterato il corpo della funzione), cos� potresti scrivere
=====================================
   printarray (firstarray);
   printarray (secondarray);
=====================================
 

Il 16/04/2013 21:26, Osvald ha scritto:
 
Il problema nel tuo codice è che hai dimenticato di racchiudere le tre 
istruzioni da eseguire nel ciclo for nelle parentesi graffe.
 
L'esempio che fai può essere reso più interessante con l'uso dei
puntatori e dell'istruzione sizeof() che indica la dimensione in byte
del suo argomento per rendere il programma poco più flessibile:
Nell'esempio da te riportato gli array sono piccoli e la loro copia
[*il passaggio di argomento a funzione è sempre per valore*]
non richiede grande memoria, ma per grossi array conviene passare
un puntatore all'array che non l'array stesso.
 
#include <iostream>
#include <climits>  // utilizzato per INT_MAX
#include <cstdlib>  // utilizzato per srand e rand
#include <ctime>    // utilizzato per time()
 
using std::cout;
using std::cin;
using std::endl;
 
void stampa_array(int *, int);
void inizializza_array(int *, int);
 
int main()
{
     int n = 0;
 
     // imposta il seme del random
     // utilizzando l'ora corrente
 
     srand(time(0));
 
     cout << "Inerisci la dimensione dell'array: ";
 
     // la procedura che segue permette di controllare
     // un input errato
 
     while((cin >> n) == 0 )
     {
         cin.clear();
         cin.ignore(LONG_MAX,'\n');
 
         // a rigore dovrei usare
         // cin.ignore(numeric_limits<streamsize>::max() ,'\n')
         // ma il mio compilatore non
         // lo supporta ancora
 
         cout << "Per favore reinserisci: ";
     }
 
     int array[n];
 
     int size = sizeof(array) / sizeof(array[0]);
 
     // sizeof(array) dice quanti byte è grande l'array
     // sizeof[array[0] dice quanto è grande il dato
     // memorizzato nell'array. il rapporto di queste quantità
     // fornisce il numero di elementi nell'array
 
     inizializza_array(array, size);
 
     stampa_array(array, size);
 
 
 
     return 0;
}
 
void stampa_array(int * array_p, int sz)
{
     for(int i=0; i < sz; i++)
     {
         cout << array_p[i] << " ";
     }
 
     cout << endl;
}
 
void inizializza_array(int * array_p, int sz )
{
     for(int i=0; i < sz; i++)
     {
         array_p[i] = (rand() % 10) + 1;
     }
 
     // rand % 10 imposta il numero
     // casuale in modo che sia
     // compreso tra 0 e 9
 
}
 


 
 
-- 
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)
 

 [...]
 
 
Ciao  Manlio

 Ciao  Manlio
 
 


 =====================================
 
Fortunatamente nel 2013 si pu� scrivere qualcosa di pi� leggibile e allo
stesso tempo di pi� generico :)
 
template <typename T>
void print_sequence(T&& arg) {
     for (const auto& e : arg)
         std::cout << e << '\n';
}
 
int main () {
   int firstarray[] = {5, 10, 15};
   std::array<int, 5> secondarray = {2, 4, 6, 8, 10};
   print_sequence(firstarray);
   print_sequence(secondarray);
   print_sequence(std::vector<int>{1, 2, 3, 4});
}
 

 [...]
 
 
Ciao  Manlio

 
http://cplusplus.com/doc/tutorial/arrays/
 
 
Quel sito era, � e sar� qualcosa da evitare.
Dico "sar�" perch� per rimuovere tutte le idiozie
che ci son scritte ci vorrebbe un tempo infinito.
 
Qualcosa di meglio a detta di molti � senz'altro:
http://en.cppreference.com/
 
 
Tuttavia, nel tuo caso ribadisco che niente
sostituisce un buon libro di testo ricco di esempi
ed esercizi per imparare il C++.
 


 
eh ... prima o poi dovrò svegliarmi ed ammettere con me 
stesso che non conosco più questo linguaggio, e che lo uso 
troppo poco perché abbia senso reimpararlo :_( sniff sniff


 Ciao  Manlio
 
ciao

 ciao
 
 


 i cosiddetti "numeri magici" nel codice, anche se potrebbe essere un pò

..purtroppo NON ho ancora studiato i template, ma ritornero' sugli
esempi quando sarò piu' preparato...il primo esempio al link che hai
segnalato, dichiara una costante:
 
const size_t ROWS = 3;
 
al posto di size_t si poteva scrivere anche :
 
const unsigned integer ROWS = 3;
 
in quanto size_t puo' rappresenta sia un intero senza segno che la
grandezza in byte di oggetti (programmazione ad oggetti e' un
argomento, al momento, solo accennato a lezione):
 
http://www.cplusplus.com/reference/cstddef/size_t/?kw=size_t
 
 
.....ma quando già si conosce che un intero sarà sempre positivo e'
piu' opportuno dichiararlo come unsigned?...pero', ad es., ho notato
che, in alcuni esempi, i contatori dei cicli for sono dichiarati come
int anche se poi, in realta', nei predetti esempi, le variabili
contatore sono sempre positive.
 
Ciao a grazie milleeee!
 
 
 

 
 
Studiati lo standard C99!
Anche io mi ero reso conto che non lo conoscevo bene, e ho deciso di 
studiarlo come si deve.
 
 
Tra l'altro la specifica del C è una delle meglio scritte che abbia mai 
letto (e ne ho lette diverse).  Poi hai anche a disposizione il rationale.
 
 
Ciao  Manlio

 
 
Si.
Ma non sono sicuro che si possa chiamare array, dato che array ha un 
significato ben preciso in C++, dichiarato tramite:
 
  T a[n]
 
dove n è una costante, e T un tipo completo.
 
 
 
Ciao  Manlio

 
 
Strano che nessuno l'abbia ancora scritto, lo faccio io:
 
template<class T>
void print_seq(T *beg, T *end) {
    for (;beg!=end;++beg)
        cout << *beg << " ";
    cout << endl;
}
 
che funziona sia con gli array a-la-c che con vari iteratori.
 
Per gli array:
int firstarray[] = {5, 10, 15};
print_seq(firstarray, firstarray+3);
 
Ciao!

 che funziona sia con gli array a-la-c che con vari iteratori.
 
Perchè non leggi *bene* e soprattutto non provi il codice prima di rispondere? Non vedi che l'esempio postato da Luca vale correttamente anche per la stampa degli elementi di un "array C"?
 
Inoltre la funzione che proponi è poco elegante per stampare tutti gli elementi di una sequenza perchè obblighi chi la usa a passare come argomento un riferimento all'elemento finale.

 un riferimento all'elemento finale.
 
Personalmente tra le due userei la mia, visto che la puoi chiamare così come
chiami gran parte delle funzioni STL (con due iteratori) e come comunque 
costruisci un vector a partire da un array.
 
Son gusti..
Ciao!

 costruisci un vector a partire da un array.
 
Evidentemente non sai che esiste *già* nello standard l'algoritmo std::for_each che scorre proprio gli elementi di un *range* (anziché *tutti gli elementi*). Non serve reinventare la ruota con versioni casalinghe, meno generiche, rischiando oltretutto, come nel tuo caso (al contrario di quanto affermi) di uscire con delle versioni in realtà poco "in sintonia" con gli algoritmi generici di STL (confronta i tipi degli argomenti).

 algoritmi generici di STL (confronta i tipi degli argomenti).
 
Sì, vabbè.
 
Ciao!

 E adesso che c'entra il for_each()?
 
C'entra perchè a una funzione che stampava tutti gli elementi di una sequenza e che non esiste in C++ hai risposto con una funzione che ha un altro uso e che ha già una migliore alternativa nella libreria standard. Non c'e' niente di più inutile, se non addirittura rischioso, che reinventare una cosa ben collaudata e ben integrata come la libreria standard. E' uno dei comandamenti del C++: se una cosa esiste già nello standard, usa quella! (altrimenti torna a programmare in C).


Suvvia.
 
La soluzione STL pura semmai sarebbe qualcosa tipo:
copy(beg, end, ostream_iterator<int>(cout, " "));
o simili.
 
Ma tanto hai più voglia di litigare che di dire cose sensate, per cui lasciamo
stare.
 
Ciao!

 copy(beg, end, ostream_iterator<int>(cout, " "));
 
Non so cosa vuoi dire con "soluzione STL pura". Sicuramente std::for_each è più flessibile perchè aderisce meglio al concetto di "fai qualcosa per ogni elemento" (obbiettivo della domanda) anzichè al concetto di "copia ogni elemento da un container a un altro". Insomma, per la stampa di ogni elemento, std::copy fa storcere il naso. Ma con std::for_each e lambda la stessa cosa:
 
for_each(beg, end, [](int& e) {cout << e << ' ';});
 
è sicuramente più leggibile. Non mi venire a dire che è questione di opinioni.
 
Ad ogni modo ribasisco il vero punto, che è un altro: usa lo standard, non reinventarti niente.

 reinventarti niente.
 
Anch'io non posso che essere d'accordo, ma lo spirito del thread era dare
all'OP delle strade per correggere e provare al suo livello di conoscenze: se,
al post iniziale, gli avessimo sparato a secco le nostre due ultime versioni
(una con la copy e l'altra con una lambda), quale aiuto potremo mai avergli
dato?
 
Ciao!

 
 
..avremmo mai potuto dargli?
 
Scusate, sto scordardo l'italiano. :(
 
Ciao!

 Comunque questo IMHO rientra nell'ambito dei gusti personali.
 
Se appena appena complichi il problema, std::copy non va più bene e si dimostra debole. Supponi di volere stampare gli interi inferiori a 10. Come fai con std::copy? Usare std::copy e' una zappa sui piedi, perchè è la scelta che solo *per un caso* può andare bene.


 
Le parentesi sono necessarie, altrimenti il compilatore (almeno quello 
MS) dï¿œ errore.
Ma non so il motivo esatto di questo.
 


copy_if(beg, end, ostream_iterator<int>(cout, " "), bind2nd(less<int>(),10));
 
ma ho giocato sporco.. :)
 
Ovviamente se hai una funzione hai più flessibilità, questo è fuori
discussione. Ma così usciamo dal problema e andiamo su un argomento
completamente diverso.
 
Ciao!

 Ciao  Manlio
 
ciao

 ciao
 
 



Probabilmente l'aiuto su un modo di vedere il C++ da un punto di
vista ahimè raro. Troppo spesso, infatti, si vede il C++ insegnato o
indegnamente usato esclusivamente come il C. E' un peccato, perchè il
C++ ha il suo punto di forza nel supporto alle astrazioni, che per il
modo di pensare di un matematico, di un fisico o di un ingegnere sono 
tutto. Se ci pensi bene, per uno studente di ingegneria l'esempio con la
funzione lambda non dovrebbe essere qualcosa di poi tanto difficile da
capire, essendo il lambda calcolo un concetto per natura matematico
probabilmente già annusato in passato in altre salse.
 

 delle ipotesi con un cast esplicito.
 
Mi sono espresso male, volevo dire, se, ad es., nella seguente
istruzione, al predetto link:
 
for (size_t i = 0; i < n; i++)
 
scrivo:
 
for (unsigned i = 0; i < n; i++)
 
e' la stessa cosa?
 
..visto che, in entrambi i casi, si fa riferimento ad un tipo (di
variabile i) intero e *sempre positivo*?
 
C'e' differenza nell'usare size_t e unsigned?
 
Inoltre, in molti for, ho notato la dichiarazione di una variabile
contatore i, come int i,  anche se, in realta', la variabile i,
risulta *sempre positiva*: non sarebbe piu' opportuno usare unsigned
se sappiamo già che una varabile di tipo intero sarà *sempre
positiva*?
 
Ciao e grazie mille!
 
 
 
 
 
 
 

 Ciao e grazie mille!


 int * chunk = new int[n];
 
* mi è rimasto sulla tastiera ;o)

 * mi è rimasto sulla tastiera ;o)
 
 


 
http://cplusplus.com/doc/tutorial/arrays/
 
 
[cut]
 
Per quanto ho capito al predetto link, riepilogando:
 
Il passaggio di un'array ad una funzione avviene per *riferimento* in
quato l'array stesso, e' per definizione, un puntatore costante che
punta al primo elemento dell'array; quindi,alla funzione, passiamo per
riferimento, un puntatore al primo elemento dell'array.
 
Per quanto sopra, dobbiam,o con qualche artificio, passare il numero
di elementi che compone l'array.
 
Quando invece lavoro con array a piu' dimensioni, allora solo solo il
primo elemento a non essere definito nel passaggio dell'array?
 
Ad es., per  un' array a due dimensioni, si avra' per quanto spiegato
al suddetto link:
 
 void procedure (int myarray[][3])
 
...ma come mai invece, viene indicato esplicitamente il numero di
colonne(pari a 3)?..per  analogia con l'array monodimensionale, NON
avrei dovuto avere:
 
 void procedure (int myarray[][])
 
 
Ciao e grazie mille!!!
 
 
 

 primo elemento a non essere definito nel passaggio dell'array?
 
...volevo scrivere: e' solo il numero di righe a non essere definito.



Sono due i motivi principali del perché il linguaggio si insegna in questo
modo: il primo è didattico, il secondo è logico.
- Didatticamente, per chi non ha mai programmato e ha davanti un lungo corso
do approfondimenti, il C, essendo molto più intuitivo, è più versatile per
spiegare il comportamento di molti altri linguaggi ad alto livello; è quindi
logico seguire un percorso che passi dalle basi fino ai livelli più alti
facendo vedere come questi rendano trasparenti operazioni macchina sempre più
complesse e soprattutto come.
- Logicamente, avendo a disposizione solo gli strumenti base del linguaggio
è possibile costruire tutti gli strumenti avanzati, ma non è (ovviamente) vero
il contrario. Se si facessero le cose fatte bene, dopo un corso di C++ (ma
vale per qualsiasi altro linguaggio) dove non si sono toccate per nulla le
librerie standard si dovrebbe poter riuscire a reimplementarle da zero
(efficienza a parte e sotto la guida di qualcuno con esperienza, ma tant'è).
 
Per tornare a noi, siccome non trovo nulla di sbagliato in questo modo di
fare, dare i consigli di cui sopra sarebbe non solo inutile (visto che l'OP
non avrebbe la minima idea di cosa si sta parlando) ma magari psicologicamente
frustrante (visto che quelle cose non le sa perché non _deve_ saperle ancora).
 
M2C
Ciao!

 (efficienza a parte e sotto la guida di qualcuno con esperienza, ma tant'è).
 
Ti rispondo quotando Stroustrup, che, come sai, è sia insegnante
sia il creatore del C++. Alla domanda se il C sia più "intuitivo" o
debba considerarsi un prerequisito del C++ (cosa che mi pare tu stia
dicendo in sostanza), ecco cosa risponde:
 
"Q: Knowing C is a prerequisite for learning C++, right?
 
A: Wrong. The common subset of C and C++ is easier to learn than C.
There will be less type errors to catch manually (the C++ type system is
stricter and more expressive), *fewer tricks to learn* (C++ allows you
to express more things without circumlocution), and *better libraries
available*. The best initial subset of C++ to learn is not "all of C"."
 
Sull'altro punto, in cui dici "dopo un corso di C++ [...] dove non si
siano toccate per nulla le librerie standard" - ovviamente è un
controsenso per un corso sul C++ - "si dovrebbe riuscire a implementarle
da zero efficienza a parte" : qui hai voglia di scherzare, perchè lo
standard C++ *impone* requisiti sull'efficienza di ogni operazione.
Imporre requisiti sull'efficienza significa vincolarti ad usare solo
alcune strutture dati ed algoritmi, che bisogna ovviamente conoscere a 
priori.
Riuscire a implementare una libreria aderente allo standard C++ è
considerata una delle cose più difficili in assoluto anche per un
esperto di C++ e richiede un'esperienza di apprendimento che va
sicuramente al di là di qualsiasi corso, perchè le competenze richieste
non riguardano solo il C++.
 


Sono d'accordo, ma forse non ho sottolineato abbastanza la chiave di lettura
del mio commento iniziale, che era "per chi non ha mai programmato e ha davanti
un lungo corso do approfondimenti".
 
Se parliamo di, mettiamo, un matematico, un fisico o un semplice appassionato,
la conoscenza del linguaggio sufficente a scrivere il codice che gli serve è
più che abbastanza.
Se parliamo di un informatico di professione, non basta che conosca e sappia
usare alla perfezione in linguaggio, deve conoscere tutti i meccanismi
interni, dall'astrazione più alta fino all'elettronica; ovviamente non è
necessario che si sappia tutto alla perfezione, ma ci vuola una conoscenza
abbastanza approfondita di ogni livello.
In tutto il corso degli studi, specialmente a ingegneria, ti troverai
probabilmente a calcolare le correnti su un A/D, a scrivere un micropressore
in VHDL, a scrivere simulatori in C++, a inventare un linguaggio e scriverne
il parser, a calcolare la complessità di algoritmi astratti, a studiare il
ciclo di vita di un software. Queste cose le abbiamo fatte tutti e ancora si
fanno, ma il punto è che non sono sequenziali: quello che serve è un filo
conduttore che costruisca la forma mentis dell'informatico.
 
Il tuo discorso è giustissimo per chi questo modo di pensare lo ha già dentro,
ma chi deve imparare (e soprattutto chi deve insegnare!) deve seguire una
strada diversa.
Non ho molta esperienza con la didattica, ma la poca che ho mi ha fatto capire
che riuscire ad insegnare solo una parte di cose che sono così correlate tra
loro (come lo sono quelle che compongono l'"informatica") è un compito arduo.
 
Per questo, secondo me, utilizzare un linguaggio come il C++ solo come "scusa"
per insegnare qualcosa che, alla fine dei conti, è più importante, è prassi
buona e giusta (e infatti molto comune).
 
Ciao!


Credo sia opportuno aprire un nuovo thread!
 
Ciao e grazie a tutti!
 


 
 
