PDA

Visualizza la versione completa : Array di puntatori in Turbo C++


zaltar
11-01-2003, 16:47
La consegna : :nonono:

"Scrivere un programma che generi e visualizzi 10 stringhe di caratteri aventi le seguenti caratteristiche:

-ciascuna stringa composta da un carattere ripetuto un certo numero di volte. Il carattere da utilizzare e il numero di ripetizioni sono inseriti dall'utente.

Il main gestisce solo un array di puntatori a carattere. La memoria necessaria per contenere le singole stringhe deve essere allocata al momento della dichiarazione della lunghezza delle stesse."

In pratica il programma deve fare una roba del genere:
"Inserisci un carattere:" -> L'utente esegue.
"Quante volte vuoi ripeterlo?" -> L'utente specifica.
"La stringa : xxx" -> a seconda dell'inserimento.
Questo blocco si ripete per ogni elemento dell'array (10 volte).

Il problema questo: :mad:
Riesco a sviluppare il programma in modo tale che l'inserimento dell'utente avvenga una volta, facendo poi apparire una stringa ossia trasportando il risultato nel primo elemento dell'array oppure trasportandolo indiscriminatamente in tutti gli elementi ottenendo
un array avente 10 elementi (o quello che ) tutti uguali alla stringa composta dal carattere x inserito dall'utente ripetuto n volte come specificato dall'utente. :dh:
Purtroppo per impostando un ciclo FOR per ripetere il blocco in modo da avere in ciascun elemento dell'array una stringa diversa va tutto quanto alla malora. :bh:

Aiutatemi! :cry:

r0x
12-01-2003, 02:31
Saro` stupido ma non ho capito molto. Cioe`, la traccia l`ho capita ma non i tuoi errori.. Spiega cosa intendi per 'va tutto alla malora'..

Per ora quindi non ti dico come si fa perche` non servirebbe a nulla. Chiarisci meglio il tuo problema cosi` risolviamo. :)

Ciao.

zaltar
12-01-2003, 15:15
...dovrebbe funzionare il seguente codice, ma sorpresa sorpresa d errori assurdi e naturalmente solo in esecuzione:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


void main() {
#define dim 10

typedef char *puntatore;
puntatore p, q, vett[dim];
char a;
int n, i, cont=0;

clrscr();
for (cont=0; cont<dim; cont++) {
printf("\nInserisci un carattere: ");
scanf("%c", &a);
fflush(stdin);
printf("\nQuante volte vuoi ripeterlo? ");
scanf("%d", &n);
fflush(stdin);
p=malloc((n+1)*sizeof(char));
q=p;
for (i=0; i<n; i++) {
*q=a;
q=q+1;
}
*q='\0';
strcpy(vett[cont], p);
printf("\nStringa %d: %s.", cont+1, vett[cont]);
free(q);
free(p);
}

} /* Fine del programma */


Un mio amico ha invece sviluppato questo codice, che a sentir lui va che un piacere, ma devo ancora provarlo:

# include <stdio.h>
# include <stdlib.h>
# include <string.h>

/*dichiarazioni*/

/*prototipi*/
char* inserisci (char,int);
/*funzioni*/
char* inserisci (char lettera, int numero)
{
int i;
char *punta;
punta=malloc((numero+1)*sizeof(char));
for(i=0; i<numero; i++)
{
*(punta+i)=lettera;
}
*(punta+numero)='\0';
return(punta);
}
/*principale*/
void main()
{
int num,cont=0;
char *punt[10],carat;
clrscr();
while (cont<10)
{
printf("\nInserisci il carattere: ");
fflush(stdin)
;
scanf("%c",&carat);
printf("\nInserisci il numero di iterazioni: ");
scanf("%d", &num);
punt[cont]=inserisci (carat,num);
cont++;
}
while (cont>0)
{
printf("\n inizio la stampa delle stringe");
printf("\n %s ",(punt[(cont-1)]));
cont--;
}
} /* Fine Programma */

Francamente a me sembra che facciano esattamente la stessa cosa, solo in maniere diverse, allora come si spiega l'inghippo?

zaltar
12-01-2003, 15:48
Ho notato che solitamente vengono date nulle le Stringhe 4 e 10. :confused:
Tutto ci non ha senso... ho anche provato a sostituire il ciclo for del mio programma con un corrispondente while, in pratica risulta:
while (cont<dim) {
---codice---
cont++;
}
Tanto per essere chiaro, ma sono certo che lo sapevi. :gren:

r0x
12-01-2003, 17:01
Ci sono un paio di errori.

1) Deallochi due volte la stessa zona di memoria:



p=malloc((n+1)*sizeof(char));
q=p;
...
free(q);
free(p);


2) Copi una stringa su un puntatore per il quale non hai allocato memoria:



strcpy(vett[cont], p);


'vett' e` un array di puntatori, e se scrivi all`indirizzo di tali puntatori, che in questo caso non sono ne` allocati ne` inizializzati .. beh, dovresti sapere cosa succede, anzi, l`hai visto con i tuoi occhi. :)

Soluzioni:

1) Naturalmente o deallochi 'p' o 'q', ma non entrambi perche` puntano alla stessa zona di memoria.

2) Se vuoi solo stampare la stringa, allora l`array di puntatori e` superfluo, basta che stampi 'p' invece di 'vett[ cont ]' che non si sa cosa contenga; se invece vuoi mantenere le stringhe nell`array di puntatori, invece di strcpy() devi fare cosi`:



vett[ cont ] = p; /* o q, e` uguale */


In modo che vett[ cont ] punti alla memoria allocata. In questo caso pero` free() devi chiamarlo alla fine del programma, altrimenti l`uso dell`array e` completamente superfluo (come sopra).

Per chiarimenti sono qui. :)

Ciao.

zaltar
12-01-2003, 18:32
...quindi anche se effettivamente non serve a livello pratico richiesto dalla consegna, le cui direttive sono insindacabili.

Per quanto riguarda la dritta n1 non ero tanto sicuro che funzionasse in questa maniera l'uso dell'Heap. :tongue:
Avevo il dubbio che assegnando p a q venisse implicitamente allocata di nuovo memoria, comunque ora ho capito.

La seconda dritta stata superflua, ma molto apprezzata ugualmente :p , mi ero gi accorto nel frattempo dell'errore fatto con strcpy, comunque non la stessa cosa assegnare a vett[cont] p o q, infatti p punta ancora all'inizio della stringa, mentre q punta alla fine. Al limite si potrebbe usare q-n.

Sistemando il programma utilizzando vett[cont]=p piuttosto di strcpy sembra che giri, tuttavia dopo aver stampato a video la decima ed ultima stringa correttamente viene visualizzato anche il messaggio "Null pointer assingnement".
Forse questione di deallocazione, provo a spostare free(p) alla fine e ti faccio sapere.
Ciao.

r0x
12-01-2003, 18:57
Yesse, sul fatto di 'q' dimenticavo che poi lo modificavi.

Nel ciclo non devi liberare nulla, ne` 'p' ne` tantomeno 'q', mentre alla fine cmq non devi liberare 'p', ma gli elementi di 'vett'.

L`incomprensione sulla memoria allocata per un puntatore e` dovuta principalmente ad un fatto: bisogna ricordarsi che un puntatore non contiene memoria, quindi assegnazioni di puntatori portano a "memoria condivisa". Stacci attento perche` e` un argomento fonte di numerosi grattacapi, sia in C che in C++. :master: E se ora puo` sembrare una cosa semplice .. in programmi grossi sono problemi che fanno sputare sangue. :dh:

Ciao.

P.S.: bisogna ammettere che la versione del tuo amico e` piu` elegante, :tongue: a parte un uso abbondante di asterischi.. :p Inoltre, per copiare n caratteri uguali in un array (stringa in questo caso) puoi usare memset() e mettere il solito '\0' alla fine, cosi` fai pure il fiQo col prof. :adhone:

zaltar
13-01-2003, 18:40
Ieri sera ho finito il programma. :adhone:
Oltre all'accorgimento di sostituire l'istruzione "strcpy(vett[cont], p)" con "vett[cont]=p" stato sufficiente deallocare la memoria alla fine del programma anzich alla fine del ciclo.
Mi rimasto un dubbio a livello teorico per...
ad ogni iterazione del ciclo viene eseguita l'allocazione di memoria per la stringa, questa memoria viene riutilizzata ad ogni iterazione? Sempre la stessa memoria? Allora se non si assegna a qualcosa come vett[cont] l'elaborazione della stringa, tale elaborazione si perde... giusto? Quindi sufficiente inserire free(p) alla fine del programma e viene deallocata tutta la memoria utilizzata... se ho capito bene. :quipy:
Ah, senti... com' la storia di memset? :sexpulp:

r0x
13-01-2003, 19:12
No no .. non e` assolutamente la stessa!

memset() imposta N bytes ad un certo valore. Quindi invece di:



q=p;
for (i=0; i<n; i++) {
*q=a;
q=q+1;
}
*q='\0';


Potresti fare:



...
memset( p, a, n );
p[ n ] = '\0';
...


E` molto piu` fiQo .. :sexpulp:

Ciao.

zaltar
14-01-2003, 09:41
Effettivamente memset d un tocco professionale che non guasta affatto, anzi... :D
Per il mio dubbio riguarda malloc:
quando ad ogni iterazione viene eseguita l'istruzione "p=malloc((n+1)*sizeof(char))" si alloca ogni volta nuova memoria oppure sempre la stessa che una volta allocata viene riutilizzata ad ogni iterazione?
Da quello che ho capito la seconda opzione quella corretta, anche perch altrimenti non si giustifica il fatto che basti free(p) per deallocare tutta la memoria utilizzata. :p
Ciao. :ciauz:

P.S. Aggiungo il codice definitivo del programma cos ci capiamo meglio.

#include <stdio.h>
#include <stdlib.h>

void main() {
typedef char *puntatore; /* Dichiarazione di un tipo puntatore a carattere. */
puntatore p, q, vett[10]; /* Dichiarazione di 2 puntatori e di 1 vettore di puntatori. */
char a; /* a deve contenere l'input carattere. */
int n, i, cont=0; /* n deve contenere il numero di ripetizioni. */
/* i e cont sono contatori. */
clrscr(); /* Pulisce lo schermo. */
while (cont<10) { /* il ciclo scandisce l'intero array. */
printf("\nInserisci un carattere: ");
scanf("%c", &a); /* Si inserisce il carattere. */
fflush(stdin); /* Si ripulisce la liberia Standard Input (Tastiera) */
printf("\nQuante volte vuoi ripeterlo? ");
scanf("%d", &n); /* Si specifica quante volte ripetere il carattere. */
fflush(stdin);
p=malloc((n+1)*sizeof(char)); /* Si alloca memoria per la stringa da creare */
/* prevedendo anche lo spazio occupato dal */
/* terminatore. */
q=p; /* L'indirizzo del primo carattere della stringa, */
/* contenuto in p, viene assegnato a q. */
for (i=0; i<n; i++) { /* Manipolando q, il carattere immesso viene ripetuto */
*q=a; /* n volte. */
q=q+1;
}
*q='\0'; /* L'ultimo carattere della stringa creata deve */
/* essere il terminatore "\0". */
vett[cont]=p; /* L'elemento corrente dell'array punta al principio */
/* della stringa, infatti p contiene ancora l'indirizzo */
/* corrispondente. */
printf("\nStringa %d: %s.", cont+1, vett[cont]); /* Visualizza i risultati. */
cont++; /* S'incrementa il contatore per scandire l'array */
}
free(p); /* Si dealloca la memoria. */

} /* Fine del programma */

Loading