[C] Esercizio Stringhe

mirko.saggioro
Ciao a tutti :D ho questo esercizio in c sulle stringhe:
"Sono date due stringhe s1 e s2. Inserire in una terza stringa u i caratteri di s1 e di s2 alternativamente; quando la stringa più breve tra s1 e s2 si è esaurita, inserire in u ogni carattere dell'altra stringa. Es. I: abc 1234 O: a1b2c34 "
Allora io ho fatto questo:
void ins(char *s1,char *s2,char* u)
{
    int i;
    for(i=0;s1[i]!='\0'||s2!='\0';i++){
        strcat(u,s1[i]);
        strcat(u,s2[i]);
    }
    if(i==strlen(s1)-1)
    {
        for(;s2!='\0';i++)
            strcat(u,s2[i]);
    }
    else if(i==strlen(s2)-1)
    {
        for(;s1!='\0';i++)
            strcat(u,s1[i]);
    }
}

Qualcuno mi può aiutare a capire dove sbaglio? :(

Risposte
Summerwind78
Ciao


ho la vaga impressione che tu ti sia complicato tanto la vita. :D

La prima cosa che noto è che hai usato delle funzioni della libreria string.h che, per quanto valide, non serve andare a scomodare.

Ti è sufficiente fare tutto con qualche simpatico puntatore

Premetto che il codice che segue è abbastanza grezzo e non include tanti controlli sulle stringhe sarebbero stati opportuni, ma in linea di massima funziona.

void ins (char *s1, char *s2, char *u)
{
    unsigned char s1ptr;
    unsigned char s2ptr;
    unsigned char uptr;
    unsigned char stop;

    s1ptr = 0;
    s2ptr = 0;
    uptr = 0;
    
    stop = 0;
    
    while(stop == 0)
    {
        stop = 1; //Presumo che entrambe le stringhe siano terminate. Il valore di questa variabile verrà cambiato se almeno una delle due stringe non è terminata

        if (s1[s1ptr] != '\0') //Se la prima stringa è terminata non la considero
        {
            stop = 0;
            u[uptr++] = s1[s1ptr++] ;
        }
        
        if (s2[s2ptr] != '\0') //Se la seconda stringa è terminata non la considero
        {
            stop = 0;
            u[uptr++] = s2[s2ptr++] ;
        }
    }
    u[uptr]  = '\0'; //Chiudi la stringa di destinazione
  
}

int main (void)
{
    
  char sa[6]; //Stringa in ingresso con dimensione maggiorata di uno rispetto a quella desiderata per poter includere il carattere \0
  char sb[6]; //Stringa in ingresso con dimensione maggiorata di uno rispetto a quella desiderata per poter includere il carattere \0
  char x[20];  //dimensione impostata volutamente molto grande per poter contenere l'unione delle due stringhe


 //Popolo la prima stringa
  sa[0] = '0';
  sa[1] = '1';
  sa[2] = '2';
  sa[3] = '3';
  sa[4] = '4';
  sa[5] = '\0';

  //Popolo la seconda stringa
  sb[0] = 'a';
  sb[1] = 'b';
  sb[2] = 'c';
  sb[3] = 'd';
  sb[4] = 'e';
  sb[5] = '\0';

  ins (sa, sb, x);

  return 0;

}



Che ne dici?

mirko.saggioro
grazie molto chiaro :)

vict85
"Summerwind78":
Ciao


ho la vaga impressione che tu ti sia complicato tanto la vita. :D

La prima cosa che noto è che hai usato delle funzioni della libreria string.h che, per quanto valide, non serve andare a scomodare.

Ti è sufficiente fare tutto con qualche simpatico puntatore

Premetto che il codice che segue è abbastanza grezzo e non include tanti controlli sulle stringhe sarebbero stati opportuni, ma in linea di massima funziona.

void ins (char *s1, char *s2, char *u)
{
    unsigned char s1ptr;
    unsigned char s2ptr;
    unsigned char uptr;
    unsigned char stop;

    s1ptr = 0;
    s2ptr = 0;
    uptr = 0;
    
    stop = 0;
    
    while(stop == 0)
    {
        stop = 1; //Presumo che entrambe le stringhe siano terminate. Il valore di questa variabile verrà cambiato se almeno una delle due stringe non è terminata

        if (s1[s1ptr] != '\0') //Se la prima stringa è terminata non la considero
        {
            stop = 0;
            u[uptr++] = s1[s1ptr++] ;
        }
        
        if (s2[s2ptr] != '\0') //Se la seconda stringa è terminata non la considero
        {
            stop = 0;
            u[uptr++] = s2[s2ptr++] ;
        }
    }
    u[uptr]  = '\0'; //Chiudi la stringa di destinazione
  
}

int main (void)
{
    
  char sa[6]; //Stringa in ingresso con dimensione maggiorata di uno rispetto a quella desiderata per poter includere il carattere \0
  char sb[6]; //Stringa in ingresso con dimensione maggiorata di uno rispetto a quella desiderata per poter includere il carattere \0
  char x[20];  //dimensione impostata volutamente molto grande per poter contenere l'unione delle due stringhe


 //Popolo la prima stringa
  sa[0] = '0';
  sa[1] = '1';
  sa[2] = '2';
  sa[3] = '3';
  sa[4] = '4';
  sa[5] = '\0';

  //Popolo la seconda stringa
  sb[0] = 'a';
  sb[1] = 'b';
  sb[2] = 'c';
  sb[3] = 'd';
  sb[4] = 'e';
  sb[5] = '\0';

  ins (sa, sb, x);

  return 0;

}



Che ne dici?


Perché usi dei [inline]unsigned char[/inline] per la dimensione della stringa? Sembra una ottimizzazione, ma in realtà rende solo il codice più soggetto a problemi. Per esempio non puoi fare questa operazione su stringhe più grandi di poche centinaia di caratteri. Inoltre per ridurre l'uso di memoria è sufficiente eliminare quelle variabili e usare direttamente i puntatori per tutto. Per esempio come ho fatto qui (il codice è basato sul tuo)
void
ins(const char * s1, const char * s2, char * u)
{
  if (!u)
    {
      return;
    }
  if (!s1)
    {
      s1 = "";
    }
  if (!s2)
    {
      s2 = "";
    }

  while (*s1 != '\0' || *s2 != '\0')
    {
      if (*s1 != '\0')
        {
          *(u++) = *(s1++);
        }
      if (*s2 != '\0')
        {
          *(u++) = *(s2++);
        }
    }
  *u = '\0';
}

int
main(void)
{
  const char sa[] = "01234";
  const char sb[] = "abcdefghil";
  char x[50] = "";

  ins("", "", x);
  puts(x);  // ""
  ins(NULL, NULL, x);
  puts(x);  // ""
  ins(sa, "", x);
  puts(x);  // 01234
  ins("", sb, x);
  puts(x);  // abcdefghil
  ins(NULL, sb, x);
  puts(x);  // abcdefghil
  ins(sa, NULL, x);
  puts(x);  // 01234
  ins(sa, sb, x);
  puts(x);  // 0a1b2c3d4efghil
  ins(sb, sa, x);
  puts(x);  // a0b1c2d3e4fghil
  ins(sa, sa, x);
  puts(x);  // 0011223344
  ins(sb, sb, x);
  puts(x);  // aabbccddeeffgghhiill
}
In questo codice ho aggiunto qualche controllo sui puntatori, ma sarebbe buona norma passare la dimensione di [inline]u[/inline] alla funzione [inline]ins[/inline].

Summerwind78
Ciao

come ho premesso nel mio precedente messaggio, la funzione sarebbe stata molto ottimizzabile.

Il fatto che io abbia usato un unsigned char al posto di un char, deriva dal fatto che la dimensione in memoria di una variabile dipende dal compilatore.

Io, per lavoro, sono abituato a lavorare su microcontrollori il cui compilatore solitamente distingue il char dall'unsigned char solamente per l'uso del segno, ma in entrambi i casi sono variabili a 8 bit; pertanto sufficienti per contenere il valore del carattere stampabile da tabella ASCII.

vict85
Non ho capito la connessione tra il mio commento e la tua risposta. Io mi riferivo al fatto che uptr è un unsigned char ed è usato come indice di un array. Se la stringa è più grande del massimo valore che può essere memorizzato in un unsigned char ti potresti trovare con un ciclo infinito. Lo stesso problema esiste con qualsiasi variabile di indice la cui dimensione sia minore di quella del tipo puntatore. Usare una variabile di dimensione più piccola non è necessariamente sbagliato, ma devi essere consapevole che aggiunge una precondizione ai parametri di input.

Summerwind78
In effetti hai ragione, avevo frainteso il commento.

L'ho riletto e mi sono accorto di aver capito male io.

La prima parte della mia risposta rimane valida. Il mio codice era un'indicazione molto migliorabile, cosa che ho detto subito.

vict85
Sì certo, ho commentato solo perché è qualcosa che un principiante, in questo caso ilsaggio, non impari a fare. Per lo meno finché non comprende a pieno i concetti base.

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