n° 154
Settembre 2010
Settembre 03, 2010, 04:22:30 am *
Benvenuto! Accedi o registrati.
Hai dimenticato l'e-mail di attivazione?

Accesso con nome utente, password e durata della sessione
Notizia: Usi il PC già da qualche anno? partecipa alla discussione nell'area Retrocomputing
 
   Indice   Linux Windows Internet videogame hardware Aiuto Ricerca Agenda Downloads Accedi Registrati  


 SONDAGGIO
Saresti interessato a seguire online dei videocorsi?
Sì | No
Se sì, quali di questi argomenti sarebbero di tuo gradimento?

.NET Framework   PHP
ASP.NET Python
Attività SEO Ruby
C# Silverlight
C/C++ Visual Basic .NET
Java Windows Azure
Java per Android Windows Phone 7
Objective-C (iPhone / iPad) Altri

Attenzione! Per partecipare al sondaggio bisogna essere registrati al forum




* Messaggi recenti
Messaggi recenti
Pagine: [1]   Vai giù
  Stampa  
Autore Discussione: [C] Funzione strncpy con vettori di stringhe  (Letto 831 volte)
0 utenti e 1 Utente non registrato stanno visualizzando questa discussione.
C0ld
Newbie
*

Karma: +0/-0
Scollegato Scollegato

Messaggi: 8


Mostra profilo E-mail
« inserita:: Novembre 21, 2009, 02:02:58 pm »

Buon giorno a tutti. Ho un piccolo problema nella gestione di stringhe multidimensionali. Vorrei utilizzare la funzione "strncpy" per copiare parte del contenuto di un'altra stringa monodimensionale. Posso utilizzare la funzione in questa maniera:

Codice:
strncpy(alfa[k][20], &beta[j], (i-j));

Purtroppo il programma crasha e credo che un probabile problema sia proprio questo...
Grazie dell'attenzione e buon week-end  Occhiolino
Registrato
M.A.W. 1968
** LEGGETE IL REGOLAMENTO ! **
Global Moderator
Hero Member
*****

Karma: +126/-3
Scollegato Scollegato

Messaggi: 2115


Discrete And Combinatorial Mathematics


Mostra profilo WWW
« Risposta #1 inserita:: Novembre 21, 2009, 11:39:25 pm »

Sfortunatamente la singola linea di codice riportata non è particolarmente significativa.

La scelta sintattica, a prima vista, non sembra del tutto felice.
Un array unidimensionale - unico di tipo di array implementato under the hood dal C - è referenziato unicamente dal proprio nome, privo di parentesi quadre, il quale è perfettamente intercambiabile con un puntatore (dal contenuto non modificabile) alla locazione del primo elemento dell'array stesso, ed è lecito ovunque possa apparire in genere un puntatore, tranne che come lvalue.

Il tipo array è inoltre l'unico per il quale l'espressione
Codice:
array == &array
risulta vera.

La copia con offset in array multidimensionali è realizzata con facilità tramite l'aritmetica dei puntatori.

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

/* Numero di stringhe nell'array */
#define LIST_ELEM 5

/* Dimensione delle stringhe */
#define STR_SIZE 11

/* Abilitare questa linea per allocazione dinamica */
#define DYNAMIC

int main(void)
{
   int  x;
   char dest[] = "supercalifragilistic";

#ifdef DYNAMIC
   char **list;

   list = (char **)malloc(LIST_ELEM * sizeof(char *));
   if (NULL == list)
   {
     fputs("Errore di allocazione !", stderr);
     return(1);
   }

   for (x = 0; x < LIST_ELEM; x++)
   {
      list[x] = (char *)malloc(STR_SIZE * sizeof(char));
      if (NULL == list[x])
      {
        fputs("Errore di allocazione !", stderr);
        return(2);
      }
      memset(list[x], 'a' + x, 10);
      list[x][10] = '\0';
      printf(". %s\n", list[x]);
   }
#else
   char list[LIST_ELEM][STR_SIZE] = {"aaaaaaaaaa",
                                     "bbbbbbbbbb",
                                     "cccccccccc",
                                     "dddddddddd",
                                     "eeeeeeeeee"};

   for (x = 0; x < LIST_ELEM; x++)
   {
      printf(". %s\n", list[x]);
   }
#endif

   strncpy(list[3], dest, 5);
   printf("-> %s\n", list[3]);
   /* Risultato atteso: "-> superddddd" */

   strncpy(4 + list[2], dest, 4);
   printf("-> %s\n", list[2]);
   /* Risultato atteso: "-> ccccsupecc" */

   strncpy(3 + list[1], dest +5, 6);
   printf("-> %s\n", list[1]);
   /* Risultato atteso: "-> bbbcalifrb" */

   return 0;
}

Questa sintassi è comunque eccessivamente geek per essere accettata in ambiente produttivo, e molti cloni lint la deprecano.
 
Meglio comunque chiarire le intenzioni e mostrare qualche linea di codice in più: in genere simili problemi sono risolvibili con una sprintf() o con l'uso di puntatori ausiliari.
Codice:
    char *pt;
    ...
    pt = list[4];

   strncpy(pt + 4, dest, 4);
   printf("-> %s\n", list[4]);

In generale, peraltro, è preferibile utilizzare la memcopy per duplicare sezioni di array non necessariamente terminanti con uno '\0', sulla cui presenza come terminatore di stringa è basato l'intero set di funzioni str*() della libreria standard.
Registrato

I Moderatori invitano tutti gli utenti a prendere visione del REGOLAMENTO e a rispettarlo.

Un blog? Io?
C0ld
Newbie
*

Karma: +0/-0
Scollegato Scollegato

Messaggi: 8


Mostra profilo E-mail
« Risposta #2 inserita:: Novembre 22, 2009, 03:49:16 pm »

Allora, io dovrei copiare i-j elementi della stringa alfa (a partire dall'elemento j-simo) nella riga k della tabella beta.

Dovrei usare la funzione strncpy (sempre se si può utilizzare con le tabelle) evitando di usare l'allocazione dinamica. Infatti ho definito la tabella beta[80][20]. Il mio scopo è leggere una stringa alfa (utilizzando la gets, in quanto mi servono anche i blanks) e memorizzare le parole (eliminando gli spazi) in ciascuna riga della tabella. Ho creato questa funzione, solo che non funziona, e credo che l'errore sia proprio dovuto alla sintassi della strncpy:


Codice:
int
separaFrase (char alfa [], char beta [][20])
{
    int i, k, j, l;
    int c;
    l=strlen(alfa);
    k=0;
    j=0;
    for(i=0; i<l; i++){
        if (i==0){
            if((alfa[i]==' ')){
                strncpy(beta[k][20], alfa, i);
                k++;
                j=i+1;
            }
        }
        else if((alfa[i]==' ')){
            strncpy(&beta[k][20], &alfa[i], i-j);
            k++;
            j=i+1;
        }
    }
}
 
Registrato
marte
Newbie
*

Karma: +0/-0
Scollegato Scollegato

Messaggi: 40


Mostra profilo
« Risposta #3 inserita:: Novembre 22, 2009, 08:03:46 pm »

if (i=0) Che?!?
con questo if alla i viene assegnato il valore 0 a ogni iterazione e ti provoca il ciclo infinito
Registrato
C0ld
Newbie
*

Karma: +0/-0
Scollegato Scollegato

Messaggi: 8


Mostra profilo E-mail
« Risposta #4 inserita:: Novembre 22, 2009, 10:22:47 pm »

sisi, hai ragione. Fatto stà che la funzione non funziona anche correggendo l'errore  Che?!?
Registrato
M.A.W. 1968
** LEGGETE IL REGOLAMENTO ! **
Global Moderator
Hero Member
*****

Karma: +126/-3
Scollegato Scollegato

Messaggi: 2115


Discrete And Combinatorial Mathematics


Mostra profilo WWW
« Risposta #5 inserita:: Novembre 22, 2009, 11:50:22 pm »

Purtroppo nel tuo codice si sovrappongono numerosi errori sintattici e di progetto.

Cominciamo dagli aspetti più banali. Ecco cosa diventa il tuo codice dopo una passatina in mani esperte:
Codice:
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define MAX_PAROLE 10

#define SIZE_PAROLA 20

void separaFrase (char alfa[], char beta[][SIZE_PAROLA])
{
    int i, j, k;
    int len;

    len = strlen(alfa);

    for(i = 0, j = 0, k = 0; i < len; ++i)
    {
        if (isspace(alfa[i]))
        {
            strncpy(beta[k], alfa + j, i - j);
            ++k;
            j = i + 1;
        }
    }
}

int main (void)
{
    int i;
    char parsed[MAX_PAROLE][SIZE_PAROLA];
    char frase[] = "Alle dame del castello piace molto fare quello ";

    for (i = 0; i < MAX_PAROLE; ++i)
    {
        memset(parsed[i], '\0', SIZE_PAROLA * sizeof(char));
    }

    separaFrase(frase, parsed);

    for (i = 0; i < MAX_PAROLE; ++i)
    {
        if (strlen(parsed[i]))
        {
            printf("[%s]\n", parsed[i]);
        }
    }

    return (0);
}

Il codice, così modificato, compila senza warning con il mitico BCC 5.5.1 (e quindi con qualsiasi compilatore INCITS C'89 decente).

Inoltre, funziona perfettamente con la semplice frase di test appositamente confezionata.(1)

Tuttavia, quel codice - pur se in qualche modo funzionante - non è assolutamente robusto rispetto all'input.

Giusto per limitarci alle magagne più macroscopiche, il codice così concepito non gestisce sequenze di spazi multipli e/o tabulazioni, e non controlla in alcun modo i boundaries sul buffer-matrice "beta": né sulla singola stringa (nonostante la presenza di strncopy, la differenza tra "i" e "j" cresce incontrollatamente), né sul numero totale di stringhe.
Tali limiti arbitrari possono essere bellamente sorpassati con input appositamente malformati, con tutte le più ovvie conseguenze del caso.

E' infatti sufficiente dare in pasto una banalissima frase del tipo
Codice:
"Ciao,  sono una    bella frase di test ma con         troppi    spazi"
per vedere crollare miseramente la qualità del parsing. Per non parlare dell'overflow, fin troppo facile da provocare.

Le uniche opzioni seriamente spendibili, anche limitatamente all'ambito didattico, sono:

- L'implementazione di un vero automa a stati finiti, che ruoti attorno ai due stati fondamentali "inword" e "blank";
Codice:
#include <string.h>
#include <stdio.h>
#include <ctype.h>

/*
** Per i nostri scopi, si definisce qui la stringa
** dei separatori: caratteri che delimitano cio' che
** consideriamo "parole"
*/
#define DELIM_STR     " \t\n\r"


typedef enum {ST_BLANK, ST_INWORD} Status_t;

int main(void)
{
    Status_t FSM_Status = ST_BLANK;

    const char input[] = "Alle dame  del Castello piace   molto fare   quello";
    char *inizio, *fine;

    inizio = input;
    fine = inizio;

    printf("Input da elaborare: \n[%s]\n\n", input);

    while('\0' != *fine)
    {
        switch (FSM_Status)
        {
            case ST_INWORD:
                if (NULL != strchr(DELIM_STR, *fine))
                {
                    char c;

                    FSM_Status = ST_BLANK;
                    c = *fine;
                    *fine = '\0';
                    puts(inizio);
                    *fine = c;
                }
                break;

            case ST_BLANK:
                if (NULL == strchr(DELIM_STR, *fine))
                {
                    FSM_Status = ST_INWORD;
                    inizio = fine;
                }
                break;

           default: break;
        }
        ++fine;
    }

    if (ST_INWORD == FSM_Status)
    {
        puts(inizio);
    }

    return(0);
}

- L'uso della sempreverde strtok().
Codice:
#include <string.h>
#include <stdio.h>
#include <ctype.h>

/*
** Per la nostra strtok(), si definisce qui la stringa
** dei separatori: caratteri che delimitano cio' che
** consideriamo "parole"
*/
#define DELIM_STR     " \t\n\r"

/*
** Si stabilisce un limite arbitrario per la lunghezza dell'array
** presente nell'esercizio (qui non esplicitato).
** Il limite e' volutamente basso per evidenziarne l'effetto
** nell'esempio.
*/
#define MAX_WORDS     6

/*
** Dimensione statica della singola parola (stringa della matrice),
** sempre in riferimento all'esercizio originale.
*/
#define MAX_WORD_SIZE 16

/*
** Queste macro avanzate di preprocessore consentono l'utilizzo
** della costante MAX_WORD_SIZE entro una stringa di formato
** della printf().
** Ottima occasione per imparare un "trucco" poco noto e molto utile.
**
** In alternativa, si può assegnare il valore definito tramite
** detta macro MAX_WORD_SIZE ad una variabile qualificata come segue:
**
** const unsigned int MaxWordSize = MAX_WORD_SIZE;
**
** Usando poi tale variabile nei modi più consueti entro la printf().
*/
#ifdef ADVANCED_PREPROC
#define str(x) # x
#define xstr(x) str(x)
#endif

 int main(void)
 {
    char input[] = "supercalifragilistic-espiralidoso: "
                   "Alle dame  del Castello piace   molto fare   quello";
    char *p;
    int len;
    int i = 0;

    /* Vedi commenti a str() e xstr() tra le defines soprastanti */
#ifndef ADVANCED_PREPROC
    const unsigned int MaxWordSize = MAX_WORD_SIZE;
#endif

    p = strtok(input, DELIM_STR);
    while (NULL != p)
    {
        len = strlen(p);

#ifdef ADVANCED_PREPROC
        printf("%2d) [%-" xstr(MAX_WORD_SIZE)
               "s] size = %d  ** %s **\n",
               ++i, p, len,
               len < MAX_WORD_SIZE ? "OK" : "TRONCAMENTO");
#else
        printf("%2d) [%-*s] size = %d  ** %s **\n",
               ++i, MaxWordSize, p, len,
               len < MAX_WORD_SIZE ? "OK" : "TRONCAMENTO");

#endif

        p = strtok(NULL, DELIM_STR);

        if (MAX_WORDS == i)
        {
            p = NULL;
            puts("\n** Spazio esaurito ! **\n");
        }
    }

    return 0;
 }

Ricordo inoltre per l'ennesima volta che nel confronto tra una espressione variabile (potenzialmente un lvalue, ossia assegnabile, ovvero sintatticamente ammessa a sinistra di un operatore di assegnazione) e una costante, è buona norma anteporre sempre l'espressione costante, come segue:
Codice:
    if (69 == static_pos)

In questo modo, nel caso fin troppo comune di omissione di uno dei due simboli '=', si scarica comunque sul banale controllo sintattico del compilatore la rivelazione di un errore semantico (assegnazione in luogo di confronto), dal momento che l'espressione posta a sinistra è non assegnabile, dunque non può essere un lvalue valido.



(1) Si tratta del titolo ufficiale (ma in circolazione vi sono vari errori, perfino sulle copertine dei DVD ristampati di recente) di uno dei primissimi film della splendida Edwige nazionale: forse il primo in assoluto, relativamente alla circolazione commerciale.
Si tratta di un capolavoro visto da pochissimi intenditori, nel quale peraltro la famosa e formosa attrice, decisamente agli esordi della sua carriera, viene vistosamente doppiata anche nell'originale tedesco. Tuttavia, in questi casi non sta esattamente nei dialoghi la forza icastica del messaggio filmico, l'estasi e il tormento del cineasta... Ghigno
Registrato

I Moderatori invitano tutti gli utenti a prendere visione del REGOLAMENTO e a rispettarlo.

Un blog? Io?
C0ld
Newbie
*

Karma: +0/-0
Scollegato Scollegato

Messaggi: 8


Mostra profilo E-mail
« Risposta #6 inserita:: Novembre 23, 2009, 04:45:53 pm »

Ho capito (la prima parte almeno  Ghigno).

Come avrai capito la mia conoscenza del C è al livello didattico, e purtroppo non ho ancora studiato molte funzionalità e funzioni un po' più complesse...

Comunque grazie lo stesso !!!

Registrato
Pagine: [1]   Vai su
  Stampa  
 
Vai a:  

Copyright © 2009 Edizioni Master SpA. p.iva : 02105820787

Tutti i diritti di proprietà letteraria e artistica riservati. - Privacy



Links to Page