Newsgroup: it.comp.lang.c
Titolo: array di stringhe in cui copio le stringhe che passo al main

Ciao a tutti,
devo allocare un array di stringhe copiandoci le stringhe che passo al main, 
da argv[1] fino alla fine dei parametri, ovvero fino a argv[argc-1]
Chiaramente non soi a prioni quanto sono lunghe le stringhe!
 Una cosa cosi' puo' andar bene?
int main(int argc, *argv[]) {
  int i;
  char **prova;
  prova = malloc(argc*sizeof(char *));
  for( i=1; i<argv; i++ ) {
    prova[i] = malloc(sizeof([argv[i])*sizeof(char)));
      strcpy(prova[i],argv[i]);
  }
  return 0;
}

OPS! :) scusate, ora ho riscritto una versione senza errori.. ma che mi da 
un problema strano pero':
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
  int i;
  char **prova;
  prova = malloc(argc*sizeof(char *));
  for( i=1; i<argc; i++ ) {
    prova[i] = malloc( sizeof(argv[i]) * sizeof(char));
      strcpy(prova[i],argv[i]);
  }
  for( i=1; i<argc; i++ ) {
    printf("%s\n",prova[i]);
  }
  return 0;
}
ATTENZIONE ALL'OUTUP, I PATH LUNGHI VENGONO TAGLIATI!
~$./a.out    /etc/hardwareclock
/etc/hardwareclock
~$ ./a.out  /etc/hardwareclock    /etc/hardwareclock
/etc/hardwar
/etc/hardwareclock
~$ ./a.out /etc/hardwareclock    /etc/hardwareclock    /etc/hardwareclock
/etc/hardwar
/etc/hardwar
/etc/hardwareclock

   }
1) gli indici generalmente partono da 0
2) le stringhe sono terminate con lo 0, che occupa spazio
ma non viene conteggiato da strlen
3) sizeof(char) e' inutile perche' per definizionie sizeof(char) vale 1
4) sizeof(stringa) non ha senso per calcolare la lunghezza di una
stringa, devi usare strlen.
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
int main(int argc, char *argv[]) {
   int i;
   char **prova;
   prova = malloc((argc-1)*sizeof(char *));
   for(i=1; i<argc; i++ ) {
     prova[i-1] = malloc( strlen(argv[i]) + 1);
       strcpy(prova[i-1],argv[i]);
   }
   for(i=1; i<argc; i++) printf("%s\n",prova[i-1]);
   return 0;
}
ciao,
g.

   }
for(i=1; i<argc; i++ )
   prova[i-1] = strdup( argv[i] );
dovrebbe essere più leggibile

 main, da argv[1] fino alla fine dei parametri, ovvero fino a argv[argc-1]
[..]
una cosa del genere non va bene?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (int argc, char *args[])
{
    int i, argc_copy = argc;
    char *args_copy[argc_copy];
    for (i = 0; i < argc_copy; i++) {
        args_copy[i] = (char *) malloc(strlen(args[i]));
        strcpy(args_copy[i], args[i]);
    }
}
quindi senza il primo paramentro..
int i, argc_copy = argc-1;
char *args_copy[argc_copy];
for (i = 0; i < argc_copy; i++) {
    args_copy[i] = (char *) malloc(strlen(args[i+1]));
    strcpy(args_copy[i], args[i+1]);
}
-- 
www.iuz-lab.info

         strcpy(args_copy[i], args[i]);
una stringa occupa 1 char (per il terminatore) in piu'
della sua lunghezza. quindi devi allocare strlen(args[i])+1
ciao,
g.

Siete stato gentilissimi ad aiutarmi e vi ringrazio molto.
Abusto ancora una volta della vostra pazienza per chiedervi una cosa piu' 
difficile ancora.
Dato il solito array dinamico (il nostro "char **prova") come si possono 
definire due metodi, mettiamo ad esempio (ma modificabile a vostro piacere 
semmai)
- "inserisci(char str)"
- "elimina(int i)"
la prima che inserisce una nuova stringa nell'array (bel casino! deve 
copiare il vecchio array e fare spazio per una nuova strigna. e se chiamo 
inserisci sull'array vuoto?) e la seconda che elimina l'elemento i_esimo 
dell'array ("prova[i]")

vanvera wrote:

vero, scusate..
-- 
www.iuz-lab.info

Sotto Linux me la compila senza problema (col comando gcc -c data.c)
ma io ho il dubbio che possa dare memory leck perche' quando restituisco 
l'indirizzo del nuovo array non ricordo se in C devo liberare lo spazio 
occupato dal precedente array! (**arr)
NB: la funzione da per scontato che l'array non sia vuoto (poi devo 
implementare un controllo anche per quello..)
__________________________
#ifndef DATA_C
#define DATA_C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **inserisci(char **arr, int *dim, char *path) {
  int new_dim = *dim + 1 ; // la nuova dimensione dell'array
  /* Creare un nuovo array, in cui alloco spazio adeguato
   * per copiare l'array vecchio con l'aggiunta del muovo path
   */
  char **tmp = malloc((new_dim)*sizeof(char*)) ;
  // COPIA VALORE VECCHI ARRAY
  int i ;
  for( i=0; i<*dim; i++) {
    tmp[i] = strdup(arr[i]);
  }
  // AGGIUNTA DEL NUOVO PATH ALL'ARRAY
  tmp[*dim] = strdup(path) ;
  return tmp;
}
#endif
________________________
E se volessi usae una funzione per rimuovere un elemento arbitrario 
dell'array invece? Per esempio l'elemento i_esimo, c'e' modo di scrivere un 
tale funzione in c sempre usando gli array dinamici?

 occupato dal precedente array! (**arr)
In generale stai sprecando un sacco di spazio, perche' ogni volta
riallochi un array piu' lungo di puntatori senza liberare il precedente
e inoltre riallochi spazio per tutte le stringhe.
Questa seconda cosa e' inutile, visto che basterebbe copiare i puntatori.
Anche la prima e' inutile, visto che esiste la funzione realloc
che rialloca un array cambiandone le dimensioni e copiando il
contenuto fino a dove possibile.
Quindi nel tuo caso dovrebbe diventare una cosa tipo:
char **inserisci(char **arr, int *dim, char *path) {
  int new_dim = *dim + 1 ; // la nuova dimensione dell'array
  char **tmp = realloc(arr, (new_dim)*sizeof(char*)) ;
  tmp[*dim] = strdup(path) ;
  return tmp;
}
dove non sprechi memoria perche' non copi inutilmente
le stringhe e del free del vecchio arr se ne occupa la realloc.
ciao,
g.


Stupendo..
grazie mille!
Ho appena finito di scrivere anche la funzione che elimina un elemento 
arbitrario... e quindi avro' gli stesso problemi!
In questo caso realloc ce la faccio ad usarla??
Ti incollo quella che ho scritto io:
char **rimuovi(char **arr, int *dim, int item) {
  int new_dim = *dim -1 ;
  if( *dim == 0 ) {
    exit(0) ; /* non c'e' nulla da togliere */
  }
  else {
    int i;
    int j;
    int found = 0;
    char **tmp = malloc((new_dim)*sizeof(char*)) ;
    for( i=0, j=0; i<new_dim; i++, j++) {
      if( i == item ) {
           j++ ;
      }
      tmp[i] = strdup(arr[j]);
    }
    return tmp ;
  }
}


Ho letto che se si passa dimesione zero a realloc al funzione libera lo 
spazio che si voleva ridimensionare...
Quindi posso tenere la mia funzione "rimuovi" e poi chiamare realloc(arr,0) 
alla fine
GIUSTO? :)
Grazie ancora per i preziosissimi consigli..


 dovrebbe essere più leggibile
ma meno standard :)
strdup        = BSD 4.3
malloc/strcpy = C89/C99
-- 
sbi

   prova[i-1] = strdup( argv[i] );
strdup() non è standard.