Newsgroup: it.comp.lang.c
Titolo: ritornare un array di puntatori a char

Ciao al NG
Ho un problema dal quale non riesco a venir fuori nonostante abbia 
provato in 1k modi diversi.
Devo realizzare una funzione i cui paramentri di ingresso sono:
char *s="pippo|pluto"
e un separatore che potrebbe cambiare di volta in volta.
(per chi la conosce la funzione explode/inplode del PHP)
- Il compito della funzione e di separare la stringa in base al separatore
- infilare i vari token in un elemento di un vettore.
-il puntatore a questo vettore deve essere ritornato al chiamante.
di seguito c'e il codice.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
char ** explode(char*,char*);
int main(){
	char *v="pippo|pluto";
	int i=0;
	char **pp;
	pp=explode(v,"|");
	for(i=0;i<2;i++){
		printf("%s\n",pp[0]);
 
	}
	free(pp);
	return 0;
}
char ** explode(char *valori, char *sep) {
	int j=0;
	char **cp=NULL;
	cp=(char **)calloc(2,sizeof(char *)); /*alloco lo spazio per il vettore 
di puntatori
	char *p,*token;
	token=strtok(valori,sep);
	p=(char *)malloc(strlen(token)+1); alloco lo spazio per il primo token
	strcpy(p,token);
	cp[j]=p; associo l'indirizzo del primo token al primo elemento del 
vettore di puntatori
	j++;
.. come sopra fino alla fine dela stringa
	while ((token = strtok (NULL, sep) )){
		p=malloc(strlen(token)+1);
		strcpy(p,token);
		cp[j]=p;
		j++;
	}
	return cp; ritorna il puntatore al vettore di puntatori
}
ho fatto 5-6 varianti di questo codice ma tutti produco lo stesso errore.
Premetto che compilo con gcc -c -Wall -ggdb e non ho nessun tipo di 
segnalazione di errore. Inoltre, durante al fase di debug usando GDB, 
tutto fila liscio come l'olio.
La cosa allucinante è che in tutti i casi quando lancio il programma da 
linea di comando viene prodotto il solito Segmentation Fault.
Sicuramente si tratta di qualcosa inerente gli indirizzi dei puntatori 
ma sinceramente non riesco ad individuare l'inconveniente.
Grazie a tutti

 	token=strtok(valori,sep);
Non ho guardato a fondo il tuo codice, ma ti do alcuni suggerimenti su come
farei io. 
- Non userei la strtok (non è reentrant, e perciò tendo a evitarla)
- Invece strchr o strstr per trovare l'indice della prima occorrenza del
separatore nella stringa da tokenizzare
- strncpy per copiare solo la parte della stringa prima del token
- attenzione ad aggiungere \0 al fondo
ciao domenico

 da linea di comando viene prodotto il solito Segmentation Fault.
Non  ho  letto accuratamente  il  tuo  codice,  tuttavia mi  sembra  che
utilizzi la strtok(3) su di un puntatore, v, dichiarato come:
char *v="pippo|pluto";
Il SIGSEGV  deriva da questo  (se il resto  del tuo codice  e` corretto,
come dicevo sopra non l'ho guardato attentamente); cerca nei vecchi post
(non miei, io scrivo  molto di rado qui) se vuoi  una spiegazione piu` o
meno dettagliata.
Ti allego una possibile soluzione al  tuo problema (scritta in fretta in
attesa della cena).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef MAX_OFFSETS
# define MAX_OFFSETS    10
#endif
struct offsets
{
  int so;       /* start offset */
  int eo;       /* end   offset */
};
typedef struct offsets offset_t;
static int set_offsets(const char *str, int token, offset_t *offset)
{
  int i = 0, nitems = 0, next_soff = 0;
 
  /* initialize memory */
  memset (offset, -1, MAX_OFFSETS * sizeof(offset_t));
 
  while (str[i] != '\0' && nitems < MAX_OFFSETS)
  {
    /* new token found - set offsets and counters */
    if (str[i] == token)
    {
      offset[nitems].so = next_soff;
      offset[nitems].eo = i - 1;
 
      next_soff = i + 1;
      nitems += 1;
    }
 
    i++;
  }
 
  /* check last group (if no empty string was found) */
  if (i > 0 && nitems < MAX_OFFSETS && offset[nitems].eo == -1)
  {
    offset[nitems].so = next_soff;
    offset[nitems].eo = i - 1;
 
    nitems += 1;
  }
 
  return nitems;
}
static int my_strdup(char *str, offset_t offset, char **field)
{
  int nbytes = offset.eo - offset.so + 1;
  int ret = 0;
 
  /* allocate memory for the new string */
  if ((*field = malloc (nbytes + 1)) != NULL)
  {
    if (nbytes)
      (void)strncpy(*field, (str + offset.so), nbytes);
 
    /* terminate the string */
    *(*field + nbytes) = '\0';
    ret = 1;
  }
 
  return ret;
}
static void free_list (char ***str)
{
  int i = 0;
 
  if (*str != NULL)
  {
    /* free sub strings */
    for (i = 0; (*str)[i] != NULL; i++)
    {
      free ((*str)[i]);
      (*str)[i] = NULL;
    }
 
    /* free the list */
    free (*str);
    *str = NULL;
  }
}
char **explode (char *valori, int sep)
{
  offset_t offset[MAX_OFFSETS];
  int i = 0, nfields = 0;
  char **ptr = NULL;
 
  if (valori != NULL)
  {
    if ((nfields = set_offsets(valori, sep, offset)) > 0)
    {
      /*
       * allocate memory for nfield + 1 members (last member will be
       * used like a sentinel (NULL pointer to scan the list without
       * a "member counter"
       */
      if ((ptr = malloc ((nfields + 1) * sizeof (char *))) != NULL)
      {
        /* sentinel */
        ptr[nfields] = NULL;
 
        /* save fields */
        for (i = 0; i < nfields && offset[i].so != -1; i++)
        {
          if (!my_strdup(valori, offset[i], &ptr[i]))
          {
            free_list(&ptr);
            break;
          }
        }
      }
    }
  }
 
  return ptr;
}
/* test main */
int main(int argc, char *argv[])
{
  char buff[256];
  char **p = NULL;
  int lineno = 0, i;
  FILE *fp = stdin;
 
  if (argc < 3)
    exit (1);
 
  if (strcmp (argv[1], "-"))
  {
    if ((fp = fopen (argv[1], "r")) == NULL)
      exit(2);
  }
 
  while (fgets (buff, sizeof(buff), fp) != NULL)
  {
    if (buff[strlen(buff) - 1] == '\n')
      buff[strlen(buff) - 1] = '\0';
 
    printf ("\nLineno %02d: [%s] (%d bytes long)\n           ",
            ++lineno, buff, strlen(buff));
 
    if ((p = explode (buff, *argv[2])) != NULL)
    {
      for (i = 0; p[i] != NULL; i++)
        printf ("[%s] ", p[i]);
 
      printf ("\n");
      free_list(&p);
    }
  }
 
  if (strcmp (argv[1], "-"))
    fclose(fp);
 
  return 0;
}
Devi  lanciarlo specificando  come primo  parametro un  file (usa  - per
stdin) seguito dal token che ti interessa (ad esempio |).
Usage: ./explode /etc/passwd :
Ciao.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it