2010-11-23 5 views
1

Bonjour à tous les utilisateurs de stackoverflow. J'essaye de construire un code simple (en tant qu'exercice) qui lira à partir d'un fichier et stockera les mots d'un fichier dans un tableau alloué dynamiquement. Je pense que je me trompe. Est-ce que quelqu'un voit ce que je fais mal?mémoire dynamique et fgets

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

#define ARRSIZE 10 

int main(){ 
    char * myArray = malloc(ARRSIZE*sizeof(char*)); 
    FILE * p1File; 
    char mystring1 [100]; 
    char word [100]; 
    int j = 0; 
    p1File = fopen ("my1file.txt","r"); 
    if (p1File == NULL) perror ("Error opening file"); 
    else{ 
     while(fgets(mystring1, 100, p1File)){ 
      int nuRead = sscanf(mystring1, "%s", word);\ 
      printf("lepo ani magia\n\n"); 
      if (nuRead > 0){ 
       strncpy (*myArray[j], mystring1, 100); 
       //*myArray[j] = mystring1; 
      } 
      j += 1; 
     } 
    } 
} 

///////////////////////////////////

my text file is 

this 
will 
probably 
work 
but 
I 
am 
+1

Quel comportement voyez-vous? – nmichaels

+0

Je reçois un segfault. –

Répondre

1

Vous n'allouez pas d'espace pour vos chaînes, juste le tableau de chaînes. myArray[j] est juste un pointeur non initialisé. Au lieu de cela, allouer de l'espace pour chaque chaîne dans myArray comme ceci:

char *myArray[ARRSIZE]; // No reason for this to be dynamic. 
// ... 
if (nuRead > 0) 
{ 
    myArray[j] = malloc((strnlen(mystring, 100) + 1) * sizeof(char)); 
    strncpy (myArray[j], mystring1, nuRead + 1); 
} 

Comme user411313 a souligné, sscanf ne renvoie pas le nombre de caractères correspondants, mais le nombre d'éléments d'entrée correspondants. Utilisez strnlen (ou strlen si vous n'avez pas strnlen) pour obtenir la taille de la chaîne (et n'oubliez pas d'ajouter 1 pour le terminateur null).

+0

le plus apprécié. :) –

+0

-1 grosse erreur. sscanf ne renvoie PAS le nombre de caractères (pour votre malloc). sizeof (char) est toujours 1. – user411313

+0

@ user411313: Merci, je suis habitué à une bibliothèque wonkified qui renvoie le nombre de caractères correspondants. sizeof (char) peut toujours être 1, mais j'aime être explicite. Il est évident que j'alloue des octets au lieu de mots et qu'il est plus rapide pour moi de lire si mes appels malloc suivent tous le même schéma. – nmichaels

0
char * myArray = malloc(ARRSIZE*sizeof(char*)); 

Vous avez affecté un emplacement pour stocker dix pointeurs de chaîne. Mais vous n'avez alloué aucun espace pour copier les caractères dans des chaînes persistantes.

Si vous voulez mettre en place que le stockage au début, vous pourriez faire

#define MAX_STR_SIZE 100 

char * myArray = malloc(ARRSIZE*sizeof(char*)); 
if (!myArray) exit(1); 
for (j=0; j<ARRSIZE; j++) { 
    myArray[j] = malloc(MAX_STR_SIZE); 
    if (!myArray[j]) exit(1); 
} 

Ou, probablement mieux, vous pouvez allouer chaque chaîne au besoin. Au lieu de strncpy, utilisez strdup (qui est comme faire un malloc alors strcpy):

myArray[j] = strdup(mystring1); 
+0

J'ai compris. Merci.:) –

+1

strdup n'est pas ANSI C – user411313

0

Si vous avez seulement besoin de gérer jusqu'à 10 lignes de texte alors je le ferais plus comme ceci:

char *myArray[ARRSIZE]; 
... 
if (nuRead > 0) { 
    myArray[j++] = strdup(mystring1); 
} 
... 

ce qui se passe est que ce code alloue et des copies en une seule fois (en utilisant strdup, plutôt que malloc suivie strcpy).

+0

Je vois. Je vous remercie. :) –

3

Pour cette tâche, je voudrais d'abord définir une structure de données qui contient les mots, comme ceci:

struct wordlist { 
    char **words; /* the actual words */ 
    size_t size; /* the number of words in the list */ 
    size_t capacity; /* the number of words that would fit in the list */ 
}; 
typedef struct wordlist wordlist; 

alors je définir des fonctions d'opérer sur eux. C'est pour garder le code dans main court et lisible. Les fonctions sont les suivantes:

void * 
malloc_or_fail(size_t size) 
{ 
    void *result = malloc(size); 
    if (result == NULL) { 
    perror("malloc"); 
    exit(EXIT_FAILURE); 
    } 
    return result; 
} 

/* Creates a newly allocated copy of the given string. Later changes 
* to the given string will not have any effect on the returned string. 
*/ 
char * 
str_new(const char *str) { 
    size_t len = strlen(str); 
    char *result = malloc_or_fail(len + 1); 
    memcpy(result, str, len + 1); 
    return result; 
} 

/* Adds a copy of the given string to the word list. Later changes 
* to the given string have no effect on the word in the word list. 
*/ 
void 
wordlist_add(wordlist *wl, const char *word) 
{ 
    if (wl->size == wl->capacity) { 
    /* TODO: resize the wordlist */ 
    } 
    assert(wl->size < wl->capacity); 
    wl->words[wl->size++] = str_new(word); 
} 

/* Creates a new word list that can hold 10 words before it will be 
* resized for the first time. 
*/ 
wordlist * 
wordlist_new(void) 
{ 
    wordlist *result = malloc_or_fail(sizeof wordlist); 
    result->size = 0; 
    result->capacity = 10; 
    result->words = malloc_or_fail(result->capacity * sizeof result->words[0]); 
    return result; 
} 

L'utilisation de ces fonctions ne devrait pas compliquer la tâche d'origine.

+0

Merci pour l'exemple détaillé Roland. Le plus apprécié. :) –