[C] problema di implementazione

fk16
Ragazzi sto svolgendo questo esercizio in C. Ho un problema nelle righe numero 42 e 43. C'è un modo per passare alla funzione prendi s e s[j] in modo che la funzione mi possa ritornare gli ultimi caratteri delle stringhe considerate?????....Grazie a tutti per le risposte. Il tsto è questo:
/*scrivere una funzione in linguaggio C che utilizzando l'algoritmo del
"bubble sort" ordini in ordine crescente un vettore di stringhe in
funzione del valore del codice ASCII dell'ultimo carattere.*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 6

void stampa(char *a[MAX]);
void ordina(char *s[MAX]);
char* prendi(char *a[MAX]);

int main(){
    char *s[MAX]={"Fogli","Telefono","sole","MOUSE","BATTERIA","Casa"};
    stampa(s);
    ordina(s);
    printf("\n");
    stampa(s);
    printf("\n");
    system("pause");
    return 0;
}

void stampa(char *s[MAX]){
     int i;
     for(i=0;i<MAX;i++)
     printf("[%s] ",s[i]);
     return;
     }
                        
void ordina(char *s[MAX]){
     int i,j;
     char *temp_swap;
     char *temp_1;
     char *temp_2;
     temp_1=(char*)malloc(sizeof(char));
     temp_2=(char*)malloc(sizeof(char));
     temp_swap=(char*)malloc(sizeof(char));
     for(i=0;i<MAX;i++){
        for(j=MAX-1;j>=0;j--){                
           temp_1=prendi(s);                     //In questo punto: c'è un modo per passare s[i] e s[j]?????
           temp_2=prendi(s);                    
           if(*temp_1 > *temp_2){
             temp_swap = strcpy(temp_swap,s[i]);                                                                               
             s[i] = strcpy(s[i],s[j]);
             s[j] = strcpy(s[j],temp_swap);
             }}}
             free(temp_1);
             free(temp_2);
             free(temp_swap);
             return;
             }
     
char* prendi(char *a[MAX]){     
     int i;
     char *temp_p;
     temp_p=(char*)malloc(sizeof(char));
     for(i=0;i<MAX;i++){
               temp_p=a[i];
               while(*(temp_p+1)!='\0')   //In questo modo prende l'ultimo
                      temp_p++;           //carattere della stringa passata
                      }
       return(temp_p);
       }

Risposte
yoshiharu
"fk16":

void ordina(char *s[MAX]){
     int i,j;
     char *temp_swap;
     char *temp_1;
     char *temp_2;
     temp_1=(char*)malloc(sizeof(char));
     temp_2=(char*)malloc(sizeof(char));
     temp_swap=(char*)malloc(sizeof(char));
     for(i=0;i<MAX;i++){
        for(j=MAX-1;j>=0;j--){                
           temp_1=prendi(s);                     //In questo punto: c'è un modo per passare s[i] e s[j]?????
           temp_2=prendi(s);                    
           if(*temp_1 > *temp_2){
             temp_swap = strcpy(temp_swap,s[i]);                                                                               
             s[i] = strcpy(s[i],s[j]);
             s[j] = strcpy(s[j],temp_swap);
             }}}
             free(temp_1);
             free(temp_2);
             free(temp_swap);
             return;
             }



Perche' usi tutta questa memoria dinamica? temp_1 e temp_2 sono solo dei caratteri, giusto? E allora perche' devi malloc-arli? Basta dichiarare
    char temp_1,temp_2;


E la funzione prendi() in modo che ritorni un char invece che un char *. Peraltro puoi anche evitare di usare temp_1 e temp_2.
Inoltre temp_swap deve contenere tutta una stringa, devi allocare spazio per piu' di un carattere. Per l'esattezza il massimo tra le lunghezze delle stringhe da ordinare.

Altra cosa che secondo me e' sbagliata e' che s punta alle stringhe in ingresso. Sei all'interno di due cicli, dovresti passare s e s[j] a prendi(), non s. Il tipo char *s[MAX] e' un array di puntatori (cf. K&R), per cui s da solo e' un puntatore ad un puntatore (all'inizio del primo array), mentre ogni elemento s dell'array e' un puntatore ad un char (in realta' alla i-esima stringa, ma questo il puntatore non lo sa - lui punta all'inizio della stringa).
Forse questa e' la risposta alla tua domanda?


     
char* prendi(char *a[MAX]){     
     int i;
     char *temp_p;
     temp_p=(char*)malloc(sizeof(char));
     for(i=0;i<MAX;i++){
               temp_p=a[i];
               while(*(temp_p+1)!='\0')   //In questo modo prende l'ultimo
                      temp_p++;           //carattere della stringa passata
                      }
       return(temp_p);
       }


Questa e' secondo me sbagliata in conseguenza dell'errore della sezione precedente. Dovresti fargli cercare l'ultimo carattere di ogni stringa, visto che viene eseguito dentro un loop. Quindi io la scriverei

char prendi(char *a) {
    
    if(*a == '\0') return(*a);  // stringa vuota, ritorna carattere nullo

    while(*a) {
        a++;
    }
    return(*(a-1));  // poiche' la stringa non e' vuota, il terminatore ha un carattere che lo precede
}


e non hai bisogno di variabili ausiliarie.

fk16
Ciao, grazie tante della risposta e anche per aver esplicato gli errori che ho fatto. Ti volevo chiedere solo una cosa che ancora non capisco, quando tu dici:

"Inoltre temp_swap deve contenere tutta una stringa, devi allocare spazio per piu' di un carattere. Per l'esattezza il massimo tra le lunghezze delle stringhe da ordinare."

Non capisco cosa sbaglio....l'allocazione della memoria di temp_swap non è corretta??è sbagliata fare questa asseganzione forse?????
"temp_swap = strcpy(temp_swap,s);"

Grazie ancora per l'eventuale risposta.

yoshiharu
"fk16":
Ciao, grazie tante della risposta e anche per aver esplicato gli errori che ho fatto. Ti volevo chiedere solo una cosa che ancora non capisco, quando tu dici:

"Inoltre temp_swap deve contenere tutta una stringa, devi allocare spazio per piu' di un carattere. Per l'esattezza il massimo tra le lunghezze delle stringhe da ordinare."

Non capisco cosa sbaglio....l'allocazione della memoria di temp_swap non è corretta??è sbagliata fare questa asseganzione forse?????
"temp_swap = strcpy(temp_swap,s);"


piu' in alto nel codice hai allocato

    temp_swap = (char *)malloc(sizeof(char));


questo richiede al sistema di allocare da qualche parte lo spazio per un carattere, il cui puntatore viene messo in temp_swap. Tu invece vuoi che temp_swap punti a una stringa, per cui devi allocare lo spazio sufficiente, tipo


    temp_swap = (char *)malloc(sizeof(char)*max_len);


laddove max_len e' il numero di caratteri della stringa piu' lunga. In questo modo quando copi con strcpy() una stringa nello spazio puntato da temp_swap non "la fai fuori dal vaso".

fk16
Ora ho capito, il nostro professore neanche le ha spiegate queste cose, lui durante il corso ha detto solo come si usano la malloc e la calloc e niente di più. Comunque grazie mille per i chiarimenti.

fk16
Ti chiedo l'ultima cosa e non ti disturbo più. Quando compilo mi va in crash. Io suppongo che sia una questione di allocazione della memoria, perchè come mi hai detto prima se temp_swap aveva bisogno di aver allocato una memoria sufficiente per poter memorizzare il valore di una stringa, allora anche *s[MAX] ha bisogno di allocare una certa quantità di memoria o no?

yoshiharu
"fk16":
Ti chiedo l'ultima cosa e non ti disturbo più. Quando compilo mi va in crash. Io suppongo che sia una questione di allocazione della memoria, perchè come mi hai detto prima se temp_swap aveva bisogno di aver allocato una memoria sufficiente per poter memorizzare il valore di una stringa, allora anche *s[MAX] ha bisogno di allocare una certa quantità di memoria o no?


No, quella e' statica. Una scrittura come

    char *c = "pippo";


alloca la stringa a destra, e assegna a c l'indirizzo della stringa stessa.
Lo stesso vale per un array come il tuo.
Prova a testare ogni singola funzione, e cerca di capire quale e' la funzione che da il crash, poi magari posta quella.
Se hai usato il programma che hai postato originariamente deve per forza crashare, pero' se hai fatto delle modifiche io non posso saperlo.
Comunque un problema che sicuramente c'e' (e mi sono dimenticato di metterlo in evidenza prima) e' che se copi una stringa su un'altra di lunghezza minore vai a sovrascrivere qualcosa che non dovresti. E le tue stringhe sono tutte lunghe diverse. Il problema si potrebbe risolvere eliminando la dipendenza da strcpy(), usando un vettore ausiliario di puntatori, che vengono inizializzati all'indirizzo delle stringhe da ordinare. In questo modo nel bubble-sort invece di scambiare le stringhe puoi scambiare i puntatori ausiliari (che poi e' pure computazionalmente piu' efficiente).
Praticamente una cosa come
  char *aux[MAX];
  char *dummy;

  ...

  for(i=0;i<MAX;i++) aux[i] = s[i];


e poi nel bubble-sort usi aux invece di s, e invece di strcpy() per scambiare puoi usare semplicemente

  dummy = aux[i];
  aux[i] = aux[j];
  aux[j] = dummy;


che scambia solo i puntatori ausiliari. L'output si trova in aux[].
Potresti pure farlo usando solo gli s, ma mi sembra piu' pulito cosi', visto che le parole in input potrebbero anche venire da una struttura diversa da un array.
Se hai bisogno cmq non farti problemi a postare ancora.

fk16
Allora, questa è la nuova implementazione del programma.
C'è ancora un problema:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 6
#define MAX_LEN 9

void stampa(char *a[MAX]);
void ordina(char *s[MAX]);
char prendi(char a[MAX]);

int main(){
    char *s[MAX]={"Fogli","Telefono","sole","MOUSE","BATTERIA","Casa"};
    stampa(s);
    ordina(s);
    printf("\n");
    stampa(s);
    printf("\n");
    system("pause");
    return 0;
}

void stampa(char *s[MAX]){
     int i;
     for(i=0;i<MAX;i++)
     printf("[%s] ",s[i]);
     return;
     }
                        
void ordina(char *s[MAX]){
     int i,j;
     char *str[MAX];
     char *temp_swap;
     char a;
     char b;
     for(i=0;i<MAX;i++)
     str[i]=s[i];
     temp_swap=(char*)malloc(sizeof(char)*MAX_LEN);
     for(i=0;i<MAX;i++){
        for(j=MAX-1;j>i;j--){                
           a=prendi(s[i]); 
           b=prendi(s[j]);           
           if(a > b){
             temp_swap = str[i];                                                                               
             str[i] = str[j];
             str[j] = temp_swap;
             printf("%s ",str[i]);   //ho messo queste due printf solo per vedere quali elementi mi selezionava nel bubblesort
             printf("%s \n",str[j]);
             }}}
             free(temp_swap);
             return;
             }

char prendi(char *a) {
   if(*a == '\0') 
        return(*a); 
    while(*a !='\0') {
        a++;
    }
    return(*(a-1)); 
}


Praticamente il risultato del compilatore mi mostra il vettore di puntatori inziale. Mi sono scritto su un foglio i vari passaggi che esegue il compilatore e mi sono accorto che:
i=o j varia sole Telefono MOUSE BATTERIA Casa Fogli (Notare che sole non è la stringa col carattere più piccolo)
i=1 j varia sole MOUSE BATTERIA Casa Fogli Telefono
i=2 j varia sole MOUSE Casa Fogli Telefono BATTERIA
i=3 j varia sole MOUSE Casa Telefono Fogli BATTERIA
i=4 j=5 sole MOUSE Casa Telefono Fogli BATTERIA (Notare che in codice ASCII e=101, E=69, a=97, o=111, i=105, A=65)
Quindi non sono ordinati in modo giusto e poi sull' output viene stampato:
Fogli Telefono sole MOUSE BATTERIA Casa.
Per favore aiutami perchè non ci sto capendo più niente........

yoshiharu
"fk16":
Allora, questa è la nuova implementazione del programma.
C'è ancora un problema:

               
void ordina(char *s[MAX]){
     int i,j;
     char *str[MAX];
     char *temp_swap;
     char a;
     char b;
     for(i=0;i<MAX;i++)
     str[i]=s[i];
     temp_swap=(char*)malloc(sizeof(char)*MAX_LEN);
     for(i=0;i<MAX;i++){
        for(j=MAX-1;j>i;j--){                
           a=prendi(s[i]); 
           b=prendi(s[j]);           
           if(a > b){
             temp_swap = str[i];                                                                               
             str[i] = str[j];
             str[j] = temp_swap;
             printf("%s ",str[i]);   //ho messo queste due printf solo per vedere quali elementi mi selezionava nel bubblesort
             printf("%s \n",str[j]);
             }}}
             free(temp_swap);
             return;
             }




Guarda, e' molto piu' semplice di quello che pensi.
Anzitutto nella bubble-sort alle righe
  a=prendi(s[i]); 
  b=prendi(s[j]);    

ti sei dimenticato di sostituire l'array originale con l'array ausiliario str[].
Inoltre, ricordati che l'output e' nel vettore ausiliario, invece il tuo programma continua pervicacemente a stampare quello originario 8-)
Questi sono i tipici bachi da stanchezza, li conosco pure troppo bene ;-)
Comunque, visto che il programma ha tutto sommato un utilizzo limitato, forse usare l'array ausiliario e' overkilling, prova a eliminarlo e risostituire ovunque s[] (se hai un buon editor fa tutto lui :-) ).
Acevo in mente possibili generalizzazioni, ma chiaramente se il programma e' la soluzione di un esercizio potrebbe giustamente non fregartene niente...scusa se ti ho fatto fare il giro lungo...

Altra cosa, una semplice imprecisione che non inficia niente nel programma: adesso nel bubble-sort scambi solo i puntatori, e' diventato inutile allocare lo spazio per una stringa puntata da temp_swap: basta eliminare le righe con malloc() e free().
Per convincerti che funziona fai i classici disegnini con scatoline e freccette (coi puntatori aiutano, per la mia esperienza).

fk16
Grazie tante finalmente è riuscito.....non ne potevo più...ti ringrazio per la tua pazienza. :D

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.