2010-11-27 12 views
2

Je lis une ligne d'un fichier (char by char, en utilisant fgetc()), où tous les champs (prénom, nom, ...) sont séparés par un ;. Qu'est-ce que je veux maintenant faire est de créer un char**, ajouter tous les caractères à cela et remplacer le ; par \0 de sorte que je reçois effectivement une liste de tous les champs.c scinder un char * en un char **

Est-ce réellement possible? Et quand je crée un char **, par ex. char ** buf = malloc(80) puis-je le traiter comme un tableau à une dimension? Si la mémoire retournée par malloc est contiguë?

EDIT

Sry, destiné à remplacer ; par \0, bot \n.

EDIT 2

Ce code doit démontrer ce que je compte faire (peut clarifier les choses un peu):

int length = 80; // initial length char *buf = malloc(length); int num_chars = 0; 

// handle malloc returning NULL 

// suppose we already have a FILE pointer fp for (int ch = fgetc(fp); ch != EOF && ferror(fp) == 0; ch = fgetc(fp)) { 
    if (length == size) { // expand array if necessary 
     length += 80; 
     buf = realloc(buf, length); 
     // handle realloc failure 
    } 

    if (ch == ';') { 
     buf[num_chars] = '\0'; // replace delimiter by null-terminator 
    } else { 
     buf[num_chars] = ch; // else put char in buf 
    } } 

// resize the buffer to chars read buf 
= realloc(buf, num_chars); 

// now comes the part where I'm quite unsure if it works/is possible 

char **list = (char **)buf; // and now I should be able to handle it like a list of strings? 

Répondre

1

Il est pas tout à fait possible que vous décrivez, mais quelque chose de similaire est possible. Plus précisément, la dernière ligne de votre exemple char **list = (char **)buf; ne fera pas ce que vous croyez. char **list signifie que les éléments pointés par * list seront du type char*, mais le contenu de *buf correspond à des caractères. Il ne sera donc pas possible de changer l'un dans l'autre.

Vous devez comprendre qu'un char ** est juste un pointeur, il ne peut rien contenir par lui-même. Mais le char ** peut être l'adresse de début d'un tableau de char *, chaque char * pointant vers un champ.

Vous devrez allouer de l'espace pour le tableau char * en utilisant une première malloc (ou vous pouvez également utiliser un tableau statique de char * au lieu d'un char**. Vous devrez aussi trouver de l'espace pour chaque champ individuel, effectuer probablement un malloc Si le tampon initial n'est pas modifié après la lecture, il est également possible de l'utiliser pour conserver les noms de champs, mais si vous remplacez simplement le ; par un \n, vous serez manquant le terminateur de chaîne de fin 0, vous ne pouvez pas remplacer un char par inplace par deux char

Ci-dessous un exemple simplifié de ce qui peut être fait (partie malloc enlevée car elle n'ajoute pas beaucoup à l'exemple, et le rend complexe inutilement, c'est une autre histoire):

#include <stdio.h> 
#include <string.h> 

main(){ 
    // let's define a buffer with space enough for 100 chars 
    // no need to perform dynamic allocation for a small example like this 
    char buf[100]; 
    const char * data = "one;two;three;four;"; 

    // now we want an array of pointer to fields, 
    // here again we use a static buffer for simplicity, 
    // instead of a char** with a malloc 
    char * fields[10]; 
    int nbfields = 0; 
    int i = 0; 
    char * start_of_field; 

    // let's initialize buf with some data, 
    // a semi-colon terminated list of strings 
    strcpy(buf, data); 

    start_of_field = buf; 
    // seek end of each field and 
    // copy addresses of field to fields (array of char*) 
    for (i = 0; buf[i] != 0; i++){ 
     if (buf[i] == ';'){ 
      buf[i] = 0; 
      fields[nbfields] = start_of_field; 
      nbfields++; 
      start_of_field = buf+i+1; 
     } 
    } 

    // Now I can address fields individually 
    printf("total number of fields = %d\n" 
      "third field is = \"%s\"\n", 
      nbfields, fields[2]); 
} 
2

Oui, il est possible. Oui, vous pouvez le traiter comme un tableau à une dimension. Oui, la mémoire est contiguë.

Mais vous voulez probablement:

char ** fields = malloc(sizeof(char *) * numFields); 

Ensuite, vous pouvez faire:

// assuming `field` is a `char *` 
fields[i++] = field; 
1

Je veux maintenant faire est de créer un char **, ajouter tous les caractères que

Vous devez allouer un tableau de char (char *) pour stocker les caractères, pas un tableau de char * (char **).

Et quand je crée un char * , par ex. char * buf = malloc (80) Puis-je le traiter comme un tableau unidimensionnel? Si la mémoire retournée par malloc est contiguë?

Oui, malloc renvoie toujours des blocs contingents. Oui, vous pouvez le traiter comme un tableau unidimensionnel de char* (avec 80/sizeof char* éléments). Mais vous devrez allouer séparément de la mémoire pour chaque chaîne que vous stockez dans ce tableau, ou créer un autre bloc pour stocker les données de chaîne, puis utiliser votre premier tableau pour stocker des pointeurs dans ce bloc.

(ou quelque chose d'autre, beaucoup de façons de la peau ce chat)

1

Il se peut que la méthode Helper veut que chacun des « champs » par écrit à une chaîne terminée par NUL. Je ne peux pas dire. Vous pouvez le faire avec strtok(). Cependant strtok() a des problèmes - il détruit la chaîne d'origine "nourri" à lui.

#define SPLIT_ARRSZ 20 /* max possible number of fields */ 
char ** 
split(char *result[], char *w, const char *delim) 
{ 
    int i=0; 
    char *p=NULL; 
    for(i=0, result[0]=NULL, p=strtok(w, delim); p!=NULL; p=strtok(NULL, delim), i++) 
    { 
      result[i]=p; 
      result[i+1]=NULL; 
    } 
    return result; 
} 

void 
usage_for_split(void) 
{ 
    char *result[SPLIT_ARRSZ]={NULL}; 
    char str[]="1;2;3;4;5;6;7;8;9;This is the last field\n"; 
    char *w=strdup(str); 
    int i=0; 
    split(result, w, ";\n"); 
    for(i=0; result[i]!=NULL; i++) 
     printf("Field #%d = '%s'\n", i, result[i]); 
    free(w); 
}