PDA

View Full Version : [C++] Puntatori


uscrocc
14-10-2014, 13:47
Ciao ragazzi! Non ho chiaro l'argomento dei puntatori applicato a questo esercizio:

//ordinare acquisendo la matricola
#include <iostream>
using namespace std;
struct classe {
int matricola;
char nome[20];
};
int main(){
int n,scelta=0,nal;
classe alunno[5];
classe *palunno[5];
palunno[5]=&alunno[5];


for (int i=0;i<999;i++){
cout<<" "<<endl;
cout<<"*********Menu'*********"<<endl;
cout<<"0-Esci"<<endl;
cout<<"1-Acquisisci gli alunni"<<endl;
cout<<"2-Ordinali tramite matricola"<<endl;
cout<<"Inserisci la scelta: "<<endl;
cin>>scelta;

if (scelta==0) return 0;
if (scelta==1){
cout<<"Inserisci il numero degli alunni (max 5): "<<endl;
cin>>nal;
for (int i=0; i<nal; i++){
cout<<"Inserisci matricola: "<<endl;
cin>>alunno[i].matricola;
cout<<"Inserisci nome: "<<endl;
cin>>alunno[i].nome;

}
for (int i=0; i<nal;i++){
(*(*(palunno+i))).matricola=alunno[i].matricola;
(*(*(palunno+i))).nome=alunno[i].nome;
}
cout<<"Operazione completata con successo."<<endl;

}

if (scelta==2){
for (int i=0; i<nal-1; i++){
for (int j=i+1; j<nal;j++){
if(((*(palunno+i))->matricola)>((*(palunno+j))->matricola)){
palunno[i]=&alunno[j];
palunno[j]=&alunno[j];
}
for (int i=0; i<nal; i++){
cout<<(*(alunno+i)).matricola<<endl;
cout<<(*(alunno+i)).nome<<endl;
}

}




}
}
}


system ("PAUSE");
return 0;
}


Consiste nell'acquisire massimo 5 studenti in una struttura con matricola e nome, solo nome non nominativo. Ordinare crescente In base la matricola. il puntatore al vettore di struct l'ho già dichiarato però non capisco come riempirlo e il collegamento di essa con il vettore di struct. Poi l'ordinamento,peggio.. raga non voglio fatto l'esercizio per intero ma voglio ragionare e capire come funzionano questi puntatori! Grazie per le risposte :P

biowep
14-10-2014, 15:05
Un ciclo tipo
for (int i = 0; i < 999; i++);
Non ha molto senso, meglio fare così:
Messaggio di istruzioni su cosa inserire;
scelta = input;
while (scelta != valoreUscita) {
fai quello che devi in base alla scelta;
Messaggio di istruzioni su cosa inserire;
scelta = input;
}
Al corso di fondamenti di informatica mi hanno insegnato che vedere nel codice un numero tipo 999 come l'hai scritto te è sbagliato. Non il numero in sé ma il fatto che quel numero non significhi niente. Se tu conosci l'esatto numero di volte che il ciclo verrà eseguito allora usi il ciclo for e fai una define che contenga quel numero. Altrimenti (ed è questo il caso) usi il ciclo while perché non devi fare un determinato numero di iterazioni ma hai una condizione di uscita dal ciclo.
Inoltre pensa se io volessi ripetere le operazioni per 999 volte +1. In questo programma non sarebbe possibile.
#define ITERAZIONI 999
void f() {
int i;
for (i = 0; i < ITERAZIONI; i++);//Ora capisco cosa significa quel 999
}

Altra cosa:
if (scelta == valore) {
faccio questo;
}
if (scelta == altroValore) {
faccio altro;
}
Non ha senso se non stai modificando il valore della scelta nel corpo del primo ciclo. Meglio usare il costrutto else if() o switch. Così risparmi l'ulteriore controllo sulla variabile scelta.

Qua non riesco a capire cosa volevi fare:
palunno[5]=&alunno[5];
Se il tuo ragionamento è "faccio in modo che la variabile palunno punti ad alunno", è sbagliato. Dovresti inizializzare l'array dei puntatori elemento per elemento (cosa che non hai fatto).

Per quanto riguarda il resto, anche io sto imparando ora la sintassi del C++ :D
Ti posso però dire che per fare in modo che un puntatore punti ad una determinata variabile devi fare così:
palunno[i] = &alunno[i];
Tu stai usando l'aritmetica dei puntatori che è più difficile che la sintassi degli array.
Per accedere al valore di un puntatore puoi usare
*palunno[i];

Nella mente io i due simboli li traduco come
*var : valore della variabile che si trova all'indirizzo contenuto in var
&var : indirizzo della variabile var
palunno[i] = &alunno[i];//nel contenitore palunno[i] ci metti l'indirizzo del variabile alunno[i]

uscrocc
14-10-2014, 19:14
Un ciclo tipo
for (int i = 0; i < 999; i++);
Non ha molto senso, meglio fare così:
Messaggio di istruzioni su cosa inserire;
scelta = input;
while (scelta != valoreUscita) {
fai quello che devi in base alla scelta;
Messaggio di istruzioni su cosa inserire;
scelta = input;
}
Al corso di fondamenti di informatica mi hanno insegnato che vedere nel codice un numero tipo 999 come l'hai scritto te è sbagliato. Non il numero in sé ma il fatto che quel numero non significhi niente. Se tu conosci l'esatto numero di volte che il ciclo verrà eseguito allora usi il ciclo for e fai una define che contenga quel numero. Altrimenti (ed è questo il caso) usi il ciclo while perché non devi fare un determinato numero di iterazioni ma hai una condizione di uscita dal ciclo.
Inoltre pensa se io volessi ripetere le operazioni per 999 volte +1. In questo programma non sarebbe possibile.
#define ITERAZIONI 999
void f() {
int i;
for (i = 0; i < ITERAZIONI; i++);//Ora capisco cosa significa quel 999
}

Altra cosa:
if (scelta == valore) {
faccio questo;
}
if (scelta == altroValore) {
faccio altro;
}
Non ha senso se non stai modificando il valore della scelta nel corpo del primo ciclo. Meglio usare il costrutto else if() o switch. Così risparmi l'ulteriore controllo sulla variabile scelta.

Qua non riesco a capire cosa volevi fare:
palunno[5]=&alunno[5];
Se il tuo ragionamento è "faccio in modo che la variabile palunno punti ad alunno", è sbagliato. Dovresti inizializzare l'array dei puntatori elemento per elemento (cosa che non hai fatto).

Per quanto riguarda il resto, anche io sto imparando ora la sintassi del C++ :D
Ti posso però dire che per fare in modo che un puntatore punti ad una determinata variabile devi fare così:
palunno[i] = &alunno[i];
Tu stai usando l'aritmetica dei puntatori che è più difficile che la sintassi degli array.
Per accedere al valore di un puntatore puoi usare
*palunno[i];

Nella mente io i due simboli li traduco come
*var : valore della variabile che si trova all'indirizzo contenuto in var
&var : indirizzo della variabile var
palunno[i] = &alunno[i];//nel contenitore palunno[i] ci metti l'indirizzo del variabile alunno[i]
Ciao scusami ma non capisco se e dove sbaglio nei puntatori. Il ciclo ok

biowep
15-10-2014, 10:19
Te l'ho detto i tuoi puntatori non stanno puntando dove dovrebbero. Proponi un'altra soluzione.

gianmpu
15-10-2014, 13:10
Oltre a quanto già detto, c'è anche un problema concettuale a monte.
Personalmente, se trovo una struct chiamata classe, posso ipotizzare che faccia riferimento ad un insieme di alunni. Tu invece hai definito classe inserendo al suo interno i dati che di fatto identificano un singolo studente (una matricola e un nome).
In un caso reale dove lo sviluppo viene portato avanti da più persone perchè i programmatori sono più di uno non riuscireste a capirvi se non definite le cose con il loro nome.
E' bene imparare subito le basi della buona programmazione per evitare problemi in seguito. ;)

uscrocc
17-10-2014, 15:07
acquisizione
for (int i=0; i<n; i++){
pclasse[i]=&classe[i];
}

e l'ordinamento

for (int i=0; i<n-1;i++){
for (int j=i+1;j<n;j++){
if (*(*(pclasse[i])).matricola>(*(pclasse[j]).matricola){
x=pclasse [i];
pclasse[i]=pclasse[j];
pclasse[j]=x;
}

Abbiamo fatto le stringhe con i puntatori e l'esercizio chiede:
-visualizza una stringa al contrario
-contare le vocali in una stringa
-visualizzare i caratteri in celle con indice pari
-visualizzare l'indirizzo iniziale e finale
-conta quanti caratteri effettivamente ci sono
CON FUNZIONI E PUNTATORI

e questo quello che ho fatto
/* -visualizza una stringa al contrario
-contare le vocali in una stringa
-visualizzare i caratteri in celle con indice pari
-visualizzare l'indirizzo iniziale e finale
-conta quanti caratteri effettivamente ci sono
CON FUNZIONI E PUNTATORI*/
#include <iostream>
#include <stdio.h> //la uso per il numero4
using namespace std;
void num1(char pstr[10]);
void num2 (char pstr[10]);
void num3 (char pstr[10]);
void num4 (char pstr[10]);
void num5 (char pstr[10]);
int main (){
char str [10];
char *pstr [10];

cout<<"Inserisci stringa"<<endl;
cin>> str;

for (int i=0;(i<9 or (*(pstr+i))!= '\0' ;i++){
pstr[i]=&str[i];
}

num1(pstr[10]);
num2(pstr[10]);
num3(pstr[10]);
num4(pstr[10]);
num5(pstr[10]);

return 0;
system ("PAUSE");
}

void num1 (char pstr[10]){
int j=0;
while (*(pstr+j) != '\0'){
j++;
}

while (j=0){
cout<<*(pstr+j)<<endl;
j--;
}
}
void num2 (char pstr[10]){
int j=0;
for (int i=0; pstr[i]!='\0';i++){
if(*(pstr+i)=='a' or 'A' or 'e' or 'E' or 'i' or 'I' or 'o' or 'O' or 'u' or 'U'){
j++;
}
cout<<"le vocali sono"<<j+1<<endl;
}
}

void num3 (char pstr[10]){
int j=0;
for (int i=0; pstr[i]!='\0';i++){
cout<<*(pstr+j)<<endl;
j+=2;
}
}

void num4 (char pstr[10]){
int i=0;
printf("%d",*(pstr+i));

while (*(pstr+i) != '\0'){
i++;
}
printf("%d",*(pstr+i));
}

void num5 (char pstr[10]){
int i=0;
while (*(pstr+i) != '\0'){
i++;
}
cout<<"sono "<<i+1<<" caratteri"<<endl;
}

ma non mi stampa nulla, deve esserci qualcosa di sbagliato a passare i parametri del sottoprogramma, forse.. cosa dite voi? uso dev c++. comunque grazie per i consigli :)

biowep
17-10-2014, 22:06
Vedo che sei passato ad un altro programma...
Se stai usando il programma che hai preso dal sito bloodshed sappi che è molto vecchio e non viene più aggiornato.

Le funzioni prendono argomenti di tipo char[] ma tu gli passi un *char[]
Devi sistemare le parentesi sulla linea #22
Se chiami funzione(array[i]) stai passando l'elemento i dell'array, non tutto l'array.
Sulla linea #42 forse volevi dire while (j>0). Sempre in quel ciclo devi fare prima il decremento, altrimenti alla prima iterazione stampi '\0'.
L'operatore "or" me lo compila ma non so se sia standard c++. Molto meglio usare "||"
Sulla linea #50 stai sbagliando perché stai scrivendo
(*(pstr + i) == 'a') oppure
('A' è un valore che si traduce in true) oppure
('e' è un valore...)
Si usa uno switch in questi casi.

Ci sono anche altri errori comunque. Questo è tanto per cominciare :)

uscrocc
17-10-2014, 22:43
Vedo che sei passato ad un altro programma...
Se stai usando il programma che hai preso dal sito bloodshed sappi che è molto vecchio e non viene più aggiornato.

Le funzioni prendono argomenti di tipo char[] ma tu gli passi un *char[]
Devi sistemare le parentesi sulla linea #22
Se chiami funzione(array[i]) stai passando l'elemento i dell'array, non tutto l'array.
Sulla linea #42 forse volevi dire while (j>0). Sempre in quel ciclo devi fare prima il decremento, altrimenti alla prima iterazione stampi '\0'.
L'operatore "or" me lo compila ma non so se sia standard c++. Molto meglio usare "||"
Sulla linea #50 stai sbagliando perché stai scrivendo
(*(pstr + i) == 'a') oppure
('A' è un valore che si traduce in true) oppure
('e' è un valore...)
Si usa uno switch in questi casi.

Ci sono anche altri errori comunque. Questo è tanto per cominciare :)

A scuola utilizziamo questo quindi sono obbligato a questo programma..

-Come faccio a operare sul puntatore del char se passo il char?
-Riga 22 intendi così?
for (int i=0; (i<9 || str[i]!='\0'); i++){
pstr[i]=&str[i];
}
-Se faccio così (senza la [i])
num1(pstr);
mi da errore
cannot convert `char**' to `char*' for argument `1' to `void num1(char*)'
-Perchè (j>0) nella riga 42 scusami? deve stampare fino alla prima che è 0.
-Riga 50, con lo switch mai fatto, mi daresti uno spunto?

Gentilissimo, ma la prossima volta rispondi prima :ave:

uscrocc
18-10-2014, 14:01
A scuola l'ho sistemato

/* -visualizza una stringa al contrario
-contare le vocali in una stringa
-visualizzare i caratteri in celle con indice pari
-visualizzare l'indirizzo iniziale e finale
-conta quanti caratteri effettivamente ci sono
CON FUNZIONI E PUNTATORI*/

#include <iostream>
#include <stdio.h> //la uso per il numero4
using namespace std;
void num1 (char *str);
void num2 (char *str);
void num3 (char *str);
void num4 (char *str);
void num5 (char *str);
int main (){
char str [10];

cout<<"Inserisci stringa"<<endl;
cin>> str;

num1(str);
num2(str);
num3(str);
num4(str);
num5(str);

system ("PAUSE");
return 0;

}

void num1 (char *str){
int j=0;
cout<<"La stringa al contrario: ";
while (*(str+j) != '\0'){
j++;
}

while (j>=0){
cout<<*(str+j)<<endl;
j--;
}
cout<<" "<<endl;
}
void num2 (char *str){
int j=0;

for (int i=0; *(str+i)!='\0';i++){
if((*(str+i)=='a') || (*(str+i)=='A') || (*(str+i)=='e') || (*(str+i)=='E') || (*(str+i)=='i') || (*(str+i)=='I') || (*(str+i)=='o') || (*(str+i)=='O') || (*(str+i)=='u') || (*(str+i)=='U')){
j++;
}
}

cout<<"le vocali sono: "<<j<<endl;
cout<<" "<<endl;

}

void num3 (char *str){
int j=0,z=0;

while (*(str+j) != '\0'){
j++;
}

cout<<"I caratteri con indice pari: "<<endl;

while(z<j){
cout<<*(str+z)<<endl;
z+=2;
}
cout<<" "<<endl;
}

void num4 (char *str){
int i=0;
cout<<"L'indirizzo iniziale e': ";
printf("%p",*(str+i));

while (*(str+i) != '\0'){
i++;
}
cout<<" "<<endl;
cout<<"Indirizzo finale e': ";
printf("%p",*(str+i));

cout<<" "<<endl;
cout<<" "<<endl;
}

void num5 (char *str){
int i=0;
while (*(str+i) != '\0'){
i++;
}
cout<<"sono "<<i<<" caratteri"<<endl;
}

biowep
18-10-2014, 14:39
-Come faccio a operare sul puntatore del char se passo il char?

Stai facendo confusione tra puntatori e valori. Nel tuo caso, per come le hai dichiarate, le funzioni accettano degli array di char quindi, avendo a disposizione 2 variabili (str e pstr), dovrai chiamare le funzioni in questo modo:
funzione(str);//mando l'array
funzione(*pstr);//mando il valore puntato da pstr, che è un array
Devi essere coerente su quello che dichiari e quello che passi come parametro.

-Riga 22 intendi così?
for (int i=0; (i<9 || str[i]!='\0'); i++){
pstr[i]=&str[i];
}

Va bene,ora puoi trogliere del tutto le parentesi interne e diventa ancora più leggibile.

-Se faccio così (senza la [i])
num1(pstr);
mi da errore
cannot convert `char**' to `char*' for argument `1' to `void num1(char*)'

Te l'ho mostrato sopra. Fossi in te studierei molto bene le varie differenze tra:
array, elemento dell'array, puntatore ad array, puntatore ad elemento dell'array.
Ti spiego brevemente il messaggio d'errore: "cannot convert `char**' to `char*' for argument `1' to `void num1(char*)" È un problema di casting, tu stai passando un puntatore ad un puntatore ma la funzione richiede un puntatore normale (anche se in realtà è un array). Gli array sono dei puntatori. Quando dichiari ad esempio:
char str[N];// 1
char *p;// 2
char strArray[N][N];//3
char *pstr[N];// 4
char **pp;// 5

Stai dichiarando un array di elementi char ed allocando memoria nello stack per N di essi. Il nome (str) è un puntatore che contiene l'indirizzo del primo elemento.
Stai dichiarando un puntatore ad un elemento char. La grande differenza con la dichiarazione di prima è che non sto allocando memoria per degli elementi.
Stai dichiarando una matrice di char ed allocando memoria nello stack per N*N di essi. Ogni elemento del primo array (strArray[i]) è a sua volta un array di N elementi char, nessuna differenza con il primo caso
Stai dichiarando un array di puntatori ad elementi char ed allocando memoria nello stack per N di essi. Ogni elemento di questo array è un puntatore come p. Questa volta il nome è un puntatore ad un puntatore, cioè un puntatore al primo elemento dell'array (che è un puntatore).
Stai dichiarando la stessa cosa di prima ma non allocando spazio per degli elementi.

I primi due si possono considerare dati dello stesso tipo così come gli utimi 3.
Array e puntatori non sono proprio la stessa cosa, ma gli array sono implementati con dei puntatori. Ovviamente quando dichiari un array, a differenza di un puntatore, questo non può essere riassegnato (oltre al fatto di allocare memoria).

-Perchè (j>0) nella riga 42 scusami? deve stampare fino alla prima che è 0.

Avere nell'argomento di un ciclo un valore costante è (quasi?) sempre sbagliato. Completamente illogico da momento che quella condizione stabilisce quando il ciclo si deve ripetere. Se è una condizione costante allora il ciclo o si ripete all'infinito (a meno di un break) o non viene mai eseguito ed allora è ancora più inutile.
Da quel che ho intuito in quel ciclo tu vorresti iterare fino alla fine della stringa e poi iterare ancora dalla fine all'inizio stampando questa volta le lettere una ad una. Bene, un buon modo per fare ciò sarebbe: parto dal primo elemento e vado sempre avanti controllando che non ci sia un elemento == '\0'. Se c'è allora fermo il ciclo. Il prossimo ciclo avrà una condizione del tipo (--j >= 0) oppure (j-- > 0). Studia bene la differenza tra le due cose. Per accedere ad un elemento dell'array poso usare le due sintassi alternative, cioè:
array[i] oppure *(array+i). La prima è molto meglio secondo me.

-Riga 50, con lo switch mai fatto, mi daresti uno spunto?

Se vuoi farlo con lo switch trovi la sintassi ovunque cercando su google. È molto semplice. Se invece vuoi farlo con il costrutto if, allora considera ogni possibile caso. Esempio:
if(
array[i] == 'a' ||
array[i] == 'A' ||
...
);

Gentilissimo, ma la prossima volta rispondi prima :ave:

Rispondo quando posso :) . Se facessi delle domande più mirate di sicuro riceveresti più aiuto dagli altri utenti del forum, molto più esperti di me.

uscrocc
30-10-2014, 10:11
Ciao ragazzi potete consigliarmi degli esercizi sui puntatori e la ricorsione?? Su internet nada

uscrocc
02-11-2014, 21:15
Ciao raga cerco di fare questo esercizio ma continua a stamparmi gli indirizzi al posto del contenuto!! nel numero1. invece nel numero3 non mi dice i reali numeri pari. Nel 4 propio non ho idea, come faccio? come divido e prendo il resto?. Nel numero6 invece non mi accetta l'operazione *(indoc+i)=vet+i;. nel numero 7 invece devo confermare la presenza di interi nella cella 1 e 2? nel numero8 idem nella cella 1 5 e 8?

Raga aiutatemi, e' un'esercitazione pre compito! HElppp :(

/*caricare un vettore VET di 20 numeri interi e ,
utilizzando il puntatore VET,

1) visualizzarlo dall'ultima cella alla prima, visualizzare la somma e la media
2) visualizzarne ogni elemento preceduto dal rispettivo indirizzo
3) contare gli elementi pari
4) visualizzarne soltanto gli elementi posti in celle aventi indirizzo pari
5) contare le occorrenze di un elemento acquisito da tastiera
6) visualizzare l'indirizzo della prima occorrenza di un intero acquisito
da tastiera
7) verificare la presenza della sequenza di interi 1-2
8) visualizzare l'indirizzo iniziale della sequenza 1-5-8 ( 0 se non è
presente )
*/
#include <iostream>
using namespace std;
void numero1(int nmax, int vet[]);
void numero2e3(int nmax, int vet[]);
void numero5e6(int nmax, int vet[], int indoc[]);
int main(){
int vet[20],indoc[20];
int nmax;
cout<<"Inserisci il numero delle celle del vettore (max 20):"<<endl;
cin>>nmax;

for(int i=0;i<nmax;i++){
cout<<"Inserisci il contenuto del vettore: ";
cin>>*(vet+i);
}

numero1(nmax,vet);
numero2e3(nmax,vet);
numero5e6(nmax,vet,indoc);




system("PAUSE");
return 0;
}

void numero1 (int nmax, int vet[])
{
int somma,media, i;
i=nmax;

while (i>=0)
{
cout<<*(vet+i)<<endl; //stampa decrescente
somma+=*(vet+i); //somma
i--;
}

media=somma/nmax; //media
cout<<"La somma e'"<<somma<<endl;
cout<<"La media e'"<<media<<endl;

}

void numero2e3 (int nmax, int vet[]){
int i=0,pari=0;

while (i!=nmax){
cout<<vet+i<<endl;
cout<<*(vet+i)<<endl;
i++;
}

i=0;
if( (*(vet+i)%2)==0 ) pari++; //numero3

cout<<"Ci sono elementi pari "<<pari<<" volte"<<endl;
}

void numero5e6(int nmax, int vet[]){
int numc,occor=0,i=0;
cout<<"Inserisci il numero da cercare: "<<endl;
cin>>numc;

while (i!=nmax){
if ((*(vet+i))==numc){
occor++;
*(indoc+i)=vet+i; //numero6 <---- Non capisco perchè non mi fa questa operazione
} //vorrei creare un vettore che contiene gli indirizzi
i++; //dei numeri trovati cosi' da stampare il primo
}
i=0;
cout<<"Numero di occorrenze "<<occor<<endl;
cout<<"L'indirizzo del primo intero trovato e': "<<(*(indoc+i))<<endl;
}

uscrocc
03-11-2014, 14:32
upp :cry: