|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Senior Member
Iscritto dal: Jul 2003
Città: Alessandria
Messaggi: 10167
|
[C] Vettore di puntatori
Devo fare un programma che creato un array di puntatori, ad ogni indice, inserisco una stringa di testo ( di lunghezza indefinita ).
Siccome quando è stato assegnato l'esercizio, non ci era dato sapere come si allocava dinamicamente la memoria, deduco che il vettore avrà una lunghezza massima specificata ( quindi x puntatori ). Il mio problema ora è capire come caricare le stringhe in ogni indice dell'array. Sui libri che ho, dando uno sguardo, utilizzano tutti il malloc per fare ciò... Vorrei capire se è possibile farlo senza specificare la lunghezza massima di ogni stringa ( penso di si visto che comunque ogni indice punta ad un indirizzo ). Ho provato una cosa del genere: Codice:
/*
Write a C function that takes an array of pointers to strings as an argument and sorts the array in ascending length order.
Write also a main that tests the function by sorting a sequence of words read from keyboard.
Hint: For the main, you can re-use the functions of the stringsort.c program.
For the sort function, you can modify the sort function in the stringsort.c program.
*/
#include <stdio.h>
#define MAX 10 //Maximum number of strings
char *sarray[MAX];
void string_sort (void);
void get_size_sarray( int *n);
void get_strings(int *n);
void get_lenght(void);
int main (void)
{
int n; //How many string we want to enter
printf("Enter how many strings you want to enter\n");
printf("This program can hold a maximum of %d strings\n", MAX);
get_size_sarray(&n);
get_strings(&n);
return 0;
}
void get_size_sarray(int *n)
{
scanf("%d", n);
while( *n <= 0 || *n > MAX)
{
printf("Invalid number entered, try again\n");
scanf("%d\n", n);
}
}
void get_strings(int *n)
{
int i;
for ( i=0; i < *n; i++)
scanf("%s", sarray[i]);
}
__________________
Dell XPS 13 (9350) :: i5-2500K - HD6870 - AsRock Z68 Pro3 - Corsair Vengeance 8GB (4x2) DDR3 :: Samsung Galaxy S4 GT-i9505
|
|
|
|
|
|
#2 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
void get_strings(int *n)
Qui non ha senso fare il passaggio per indirizzo. Chiaro che tu abbia problemi, non essendo stato allocato sarray[i]. L'unico modo è allocare staticamente il vettore di stringhe: char sarray[SMAX][MAX]; Consiglio: non usare mai variabili globali. Prendila come regola |
|
|
|
|
|
#3 | |
|
Senior Member
Iscritto dal: Jul 2003
Città: Alessandria
Messaggi: 10167
|
Quote:
Per la variabile globale, so che non è buona abitudine usarle, ma ho avuto due professori durante il corso di programmazione: il primo si sarebbe fatto fucilare prima di usare una variabile globale, l'altro era solito impostare alcune variabili come globali ( quelle che quasi sicuramente vengono chiamate in ogni funzione del programma ). Mi pare una buona idea fare così per questo tipo di variabili, invece che chiamarle ogni volta... Alla fine chiamarle in ogni funzione e avere la memoria allocata per queste variabili durante tutta l'esecuzione del programma è pressochè uguale no? Comunque per il vettore di puntatori: scritto come hai detto tu, vado a porre un limite al numero massimo di caratteri di ogni stringa, o sbaglio?
__________________
Dell XPS 13 (9350) :: i5-2500K - HD6870 - AsRock Z68 Pro3 - Corsair Vengeance 8GB (4x2) DDR3 :: Samsung Galaxy S4 GT-i9505
|
|
|
|
|
|
|
#4 | ||
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Quote:
Quote:
Metti caso volessi spostare la funzione in un altro modulo... Ti toccherebbe usare extern in ogni modulo in cui usi quella variabile globale. Certo, ma se non usi l'allocazione dinamica non puoi fare altrimenti. |
||
|
|
|
|
|
#5 | |||
|
Senior Member
Iscritto dal: Jul 2003
Città: Alessandria
Messaggi: 10167
|
Quote:
Quote:
Quote:
Se io lo pongo come argomento di funzione la sintassi è corretta... Quando lavoravo con le matrici, negli argomenti definivo solo l'ultima dimensione.
__________________
Dell XPS 13 (9350) :: i5-2500K - HD6870 - AsRock Z68 Pro3 - Corsair Vengeance 8GB (4x2) DDR3 :: Samsung Galaxy S4 GT-i9505
|
|||
|
|
|
|
|
#6 | ||
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Quote:
Quello che sto dicendo è che se il valore non viene modificato all'interno della funzione, non ha senso passare un argomento per puntatore. Quote:
Però la memoria per contenere gli elementi di ogni singolo vettore deve essere allocata. Quindi l'unico modo che attualmente conosci è quello di creare una matrice di caratteri. Così come per allocare una stringa usi: char s[MAX]; così per allocare un vettore di stringhe dovrai usare char v[MAX][N]; |
||
|
|
|
|
|
#7 | |
|
Senior Member
Iscritto dal: Apr 2010
Città: Frosinone
Messaggi: 416
|
Quote:
void get_size_sarray(int n): invece di void get_size_sarray(int *n); daresti la garanzia che il valore di n non viene modificato (perché eventuali modifiche non si ripercuoterebbero sul chiamante).. e funzionerebbe comunque quello che ti sta dicendo è che se non serve realmente a qualcosa scriverci (ad esempio potresti avere due valori da ritornare, quindi uno lo ritorni e uno lo scrivi in una variabile di cui ti sei fatto passare il puntatore) è bene che tu garantisca che non ci scrivi passando per valore a volte ti può anche capitare di dover necessariamente passare un puntatore (come per le stringhe e gli array) anche se non devi modificare niente, se ci fai caso, in questi casi, le funzioni della standard library che usano le stringhe e che non le modificano, come strcmp o printf, prendono un const char * proprio per garantire che non vengano modificate, quindi tu, dopo averle chiamate, sei certo che siano rimaste uguali a quelle di prima.. quello che sto cercando di dire in questo italiano stentato è che è bene fornire una garanzia che le variabili nel main rimangano invariate se non è necessario |
|
|
|
|
|
|
#8 | |||
|
Senior Member
Iscritto dal: Jul 2003
Città: Alessandria
Messaggi: 10167
|
Quote:
Quote:
Quote:
__________________
Dell XPS 13 (9350) :: i5-2500K - HD6870 - AsRock Z68 Pro3 - Corsair Vengeance 8GB (4x2) DDR3 :: Samsung Galaxy S4 GT-i9505
|
|||
|
|
|
|
|
#9 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
|
|
|
|
|
|
#10 |
|
Senior Member
Iscritto dal: Jul 2003
Città: Alessandria
Messaggi: 10167
|
Riesumo il topic.
Ho reiniziato con un programma semplificato, cercando prima di fare in modo che mi ordini le parole contenute in un file, ecco ciò che ho scritto ( non è tutto di mio pugno, ho preso un po' dal libro cercando di capire esattamente cosa facesse ogni comando ): Codice:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MWORDLENGHT 30 //We need to define a maximum word lenght since we must know what's the lenght of each string
#define MSTRING 10 //Maximum number of strings in array of pointers
void error_calloc (void); //Memory allocation failed, error!
void error_string(void); //The string is too long ( too many words ), error!
void error_word(void); //The word is too long, error!
void word_sort (char *w[], int n);
void swap(char **p, char **q );
void write_words(char *w[], int n);
int main (void)
{
char word[MWORDLENGHT]; //Stores single words
char *w[MSTRING]; //Stores strings ( Array of pointers )
int n; //Stores how many words we have to sort
int i;
for (i=0; scanf("%s", word) == 1; i++) //This stops when scanf cannot read anymore char
{
if ( i >= MSTRING )
error_string();
if ( strlen(word) >= MWORDLENGHT )
error_word();
w[i] = calloc(strlen(word)+1, sizeof(char)); //Memory allocation, we add +1 to have space for \0
if ( w[i] == NULL )
error_calloc();
strcpy ( w[i], word );
}
n = i; //Now we now how many words we must sort
word_sort( w, n); //Sort words
write_words( w, n); //Write words
return 0;
}
void error_calloc (void)
{
printf("%s", "ERROR: Failed in using calloc(), cannot allocate requested memory \n QUIT\n");
exit(1); //Exit the whole program
}
void error_string (void)
{
printf("ERROR: you are trying to sort more than %d words, that's not allowed\n QUIT", MSTRING);
exit(1);
}
void error_word(void)
{
printf("%s%d%s", "ERROR: You entered a word with lenght greater than ", MWORDLENGHT, "\n QUIT\n");
exit(1);
}
void word_sort ( char *w[], int n)
{
int i, j;
for (i=0; i < n; i++)
for (j=0; j<n; j++)
if ( strcmp(w[i], w[j]) > 0 )
swap ( &w[i], &w[j]);
}
void swap ( char **p, char **q )
{
char *tmp; //Temporary stores address of pointer
tmp = *p;
*p = *q;
*q = tmp;
}
void write_words(char *w[], int n)
{
int i;
for ( i=0; i < n; i++)
printf("%s\n", w[i]);
}
__________________
Dell XPS 13 (9350) :: i5-2500K - HD6870 - AsRock Z68 Pro3 - Corsair Vengeance 8GB (4x2) DDR3 :: Samsung Galaxy S4 GT-i9505
|
|
|
|
|
|
#11 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Per fermare la scanf:
for (i=0; scanf("%s", word) == 1 && i < MSTRING; i++) Esatto, lo swap scambia i puntatori |
|
|
|
|
|
#12 |
|
Senior Member
Iscritto dal: Jul 2003
Città: Alessandria
Messaggi: 10167
|
Perchè mai scambiare i puntatori? Non è più semplice cambiare la posizione delle stringhe?
__________________
Dell XPS 13 (9350) :: i5-2500K - HD6870 - AsRock Z68 Pro3 - Corsair Vengeance 8GB (4x2) DDR3 :: Samsung Galaxy S4 GT-i9505
|
|
|
|
|
|
#13 | |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Quote:
Parlando in termini di byte, supponendo 4 la dimensione di un puntatore, swappare i puntatori comporta la lettura e la scrittura di 3*4 byte (swap = a, a = b, b = swap). Scambiare due stringhe significa leggere e scrivere strlen(a) + strlen(b) + strlen(b oppure a) byte. Senza contare che quando non si ha un limite superiore sulla dimensione della stringa siamo costretti anche a fare l'allocazione dinamica delle stringa che deve contenere lo swap. |
|
|
|
|
|
|
#14 | |
|
Senior Member
Iscritto dal: Jul 2003
Città: Alessandria
Messaggi: 10167
|
Quote:
__________________
Dell XPS 13 (9350) :: i5-2500K - HD6870 - AsRock Z68 Pro3 - Corsair Vengeance 8GB (4x2) DDR3 :: Samsung Galaxy S4 GT-i9505
|
|
|
|
|
|
|
#15 |
|
Senior Member
Iscritto dal: Jul 2003
Città: Alessandria
Messaggi: 10167
|
Devo veramente capire come si fa sto esercizio. Sono giunto alla conclusione che per ordinare una stringa si intende ordinare una serie di parole date in input.
Quindi, ho pensato a come operare:. 1. CARICAMENTO: - Inserisco la stringa - Ad ogni spazio carico la parola nel vettore di puntatori - Alloco spazio sufficiente per la parola dentro il vettore di puntatori - Torno indietro di uno, sostituisco lo spazio con \0 - Calcolo la lunghezza della parola - Ciclo finchè non ho terminato la stringa 2. ORDINAMENTO - Uso funzione strcmp ... Per l'ordinamento devo ancora pensarci, però per caricare le parole mi pare possa funzionare la cosa. Quello che non capisco è perchè sui vari libri viene imposta una costante per la lunghezza massima della stringa e della singola parola, quando secondo me è superfluo visto che si potrebbe ( credo ) allocare lo spazio. Siccome mi rendo conto che le parole possono essere di lunghezza diversa, e quindi immagino occupino spazio differente, non potrei utilizzare la funzione realloc qualora lo spazio precedentemente allocato non sia sufficiente?
__________________
Dell XPS 13 (9350) :: i5-2500K - HD6870 - AsRock Z68 Pro3 - Corsair Vengeance 8GB (4x2) DDR3 :: Samsung Galaxy S4 GT-i9505
Ultima modifica di kwb : 22-08-2010 alle 09:54. |
|
|
|
|
|
#16 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Esatto, per la lettura ve bene così.
A cose normali la lunghezza massima della parola serve comunque, il buffer su cui la parola viene riversata temporaneamente è comunque un buffer di dimensione finita. Anche se si possono attuare varie soluzioni per togliere queste limitazioni. Tra l'altro potrebbe essere un ottimo esercizio. Tu pensa che fgets permette di specificare la dimensione del buffer, quindi può terminare la lettura anche in caso di raggiungimento della massima dimensione, pur lasciando altri caratteri nell'input (in questo caso l'ultimo carattere non è '\n'): http://www.cplusplus.com/reference/c.../cstdio/fgets/ |
|
|
|
|
|
#17 |
|
Senior Member
Iscritto dal: Jul 2003
Città: Alessandria
Messaggi: 10167
|
Ho fatto così per la lettura ma ho alcuni problemi, infatti non riesco a caricare dentro l'array di puntatori...
Codice:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define WORD_MAX 40
#define STRING_MAX 300
int main (void)
{
char **pstring, input_string[STRING_MAX], word[WORD_MAX];
int i=0, word_counter=0, slen=0, j=0;
int actual_index=0;
printf("Insert a string to be sorted\n");
if ((fgets(input_string, WORD_MAX, stdin))==NULL)
{
printf("Read line error, QUIT\n");
exit(1);
}
slen = strlen(input_string);
for ( i=0; i < slen; i++)
{
if ( isspace(input_string[i]))
word_counter++; // How many words we have in the string? So we know how much memory to allocate
}
if ((pstring = calloc(word_counter, sizeof(char *)))==NULL)
{
printf("Memory row allocation error, QUIT\n");
exit(1);
}
for ( i=0; i < slen; i++)
{
if ( isspace(input_string[i]))
{
strncpy ( word, input_string, i);
for ( j = 0; j < word_counter; j++)
if ((pstring[i] = calloc(strlen(word), sizeof(char)))==NULL)
{
printf("Memory columns allocation error, QUIT\n");
exit(1);
}
actual_index=i+1;
input_string += actual_index;
}
}
for (i =0; i < word_counter; i++)
fputs(pstring[i], stdout);
return 0;
}
So che il programma è ben poco ottimizzato e ci sono risoluzioni migliori, però il mio scopo ora è quello di riuscire a fargli stampare ste stringhe...
__________________
Dell XPS 13 (9350) :: i5-2500K - HD6870 - AsRock Z68 Pro3 - Corsair Vengeance 8GB (4x2) DDR3 :: Samsung Galaxy S4 GT-i9505
|
|
|
|
|
|
#18 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
http://www.cplusplus.com/reference/c...tring/strncpy/
No null-character is implicitly appended to the end of destination, so destination will only be null-terminated if the length of the C string in source is less than num. Devi aggiungere \0 in fondo alla stringa. Codice:
if ( isspace(input_string[i]))
{
strncpy ( word, input_string, i);
word[i] = '\0';
actual_index=i+1; input_string += actual_index; Se fai così dovresti anche azzerare nuovamente i. Senza contare che non puoi cambiare l'indirizzo a cui punta input_string, visto che allocata staticamente. Dovresti usare una variabile per contare il numero dei caratteri da copiare in word. Inoltre in pstring[i] non copi alcuna stringa e la dimensione di pstring[i] dovrebbe essere pari a strlen(word) + 1, perché deve contenere anche il carattere di fine stringa. |
|
|
|
|
|
#19 | ||
|
Senior Member
Iscritto dal: Jul 2003
Città: Alessandria
Messaggi: 10167
|
Quote:
Quote:
Il fatto è che cercavo di spostarmi tra gli indirizzi perchè lo avevo già fatto in un altro programma, e aveva funzionato, solo che li l'array veniva passato ad una funzione come argomento, sebbene fosse allocato in modo statico ( grandezza predefinita ). EDIT: Ne sono venuto a capo, ora le stringhe vengono caricate dentro il vettore di puntatori correttamente, così: Codice:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define WORD_MAX 40
#define STRING_MAX 300
int main (void)
{
char **pstring, input_string[STRING_MAX], word[WORD_MAX];
int i=0, word_counter=0, slen=0, j=0;
int iactual_index=0, jactual_index=0;
printf("Insert a string to be sorted\n");
if ((fgets(input_string, WORD_MAX, stdin))==NULL)
{
printf("Read line error, QUIT\n");
exit(1);
}
slen = strlen(input_string);
for ( i=0; i < slen; i++)
{
if ( isspace(input_string[i]))
word_counter++; // How many words we have in the string? So we know how much memory to allocate
}
if ((pstring = calloc(word_counter, sizeof(char *)))==NULL)
{
printf("Memory row allocation error, QUIT\n");
exit(1);
}
for ( i=0; i < slen; i++)
{
if ( isspace(input_string[i]))
{
strncpy ( word, input_string + iactual_index, i);
iactual_index += i+1;
for ( j = jactual_index; j < word_counter; j++)
{ if ((pstring[j] = calloc(strlen(word)+1, sizeof(char)))==NULL)
{
printf("Memory columns allocation error, QUIT\n");
exit(1);
}
strcpy(pstring[j], word);
}
jactual_index++;
}
}
for (i =0; i < word_counter; i++)
{
fputs(pstring[i], stdout);
printf("\n");
}
return 0;
}
__________________
Dell XPS 13 (9350) :: i5-2500K - HD6870 - AsRock Z68 Pro3 - Corsair Vengeance 8GB (4x2) DDR3 :: Samsung Galaxy S4 GT-i9505
Ultima modifica di kwb : 24-08-2010 alle 16:18. |
||
|
|
|
|
|
#20 | |||
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Quote:
Ma anche supponendo che sia inizializzato con 0, il contenuto cambia... Se io la prima volta ci copio dentro "abcdef" e la seconda volta "abcd", la strlen ritornerà nuovamente 6. Questo perché strncpy non aggiunge automaticamente '\0'. Quote:
Quote:
Nel codice sopra continui a fare lo stesso errore concettuale di prima (supponiamo che tu aggiunga il carattere di fine stringa dopo strncpy, altrimenti non se ne esce): strncpy ( word, input_string + iactual_index, i); iactual_index += i+1; Supponiamo che la stringa sia: "nel mezzo del cammin" Quando i == 2 c'è la prima iterazione: - strncpy(word, input_string + 0, 3); - word è "Nel " - iactual_index = 4; Quando i == 9 c'è la seconda iterazione: - strncpy(word, input_string + 4, 9); - word è "mezzo del " - iactual_index = 4 + 10 = 14; Quando i == 9 c'è la seconda iterazione: - strncpy(word, input_string + 4, 9); - word è "mezzo del " - iactual_index = 4 + 10 = 14; Quando i == 13 c'è la seconda iterazione: - strncpy(word, input_string + 14, 13); - ovvio che tu abbia un overflow Inoltre perché allochi ogni volta i vettori che vanno da jactual_index a word_counter ? Non serve quel for lì dentro: per ogni parola trovata devi allocare un solo elemento di pstring. Suggerimento: dato un puntatore a char, scrivi una funzione che ti ritorna la lunghezza della PRIMA parola incontrata. Altro suggerimento: avendo come parametro un puntatore alla stringa contente i dati, devi usare la funzione sopra, allocare lo spazio necessario e copia la parola trovata con la funzione sopra nella nuova stringa allocata. La funzione ritorna il puntatore alla memoria allocata. Ultimo suggerimento: avendo la funzione del suggerimento precedente, usa l'aritmetica dei puntatori per dare in pasto una stringa contente molte parole alla funzione sopra. |
|||
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 14:55.




















