2017-03-06 3 views
1

j'ai écrit un programme utilisant le concept suivant:passe par adresse, scanf, de-référencement

Je crée un entier x passe par adresse à une fonction, avec un nom de fichier, ladite fonction ouvre le fichier si elle est disponible, balaye la première ligne et définit la valeur que pX points égal à la ligne analysée.

Seulement ça ne marche pas, et je ne vois pas ce que je fais de mal. Pour autant que je peux dire le code ci-dessous est généralement comment on pourrait l'accomplir, mais je ne suis pas sûr si je n'utilise pas scanf() correctement avec le pointeur ou quoi.

void foo() { 
    char input[20] = "test.txt"; 
    int x = 1; 
    bar(input, &x); 
} 

void bar(char *fileName, int *pX) { 
    FILE *fp = fopen(fileName, "r"); 
    char *buffer = malloc(15 * sizeof(int)); 
    fgets(buffer, 15, fp); 
    scanf(buffer, "%d", *pX); 
    free(buffer); 
    fclose(fp); 
} 
+0

La fonction 'scanf' veut des pointeurs pour les arguments. 'pX' est un pointeur. '* pX' n'est * pas * un pointeur. –

+1

'scanf (buffer,"% d ", * pX);' .... que dit le compilateur? –

+0

@SouravGhosh compile. – wanderbread

Répondre

3

ligne de changement:

scanf(buffer, "%d", *pX); 

à:

sscanf(buffer, "%d", pX); 

Vous devez fonction sscanf pour ce que vous essayez de faire. Les deux scanf et sscanf prennent un pointeur comme argument. pX est de type int *, donc un pointeur sur un int et devrait fonctionner pour vous. Ce que vous passez, *pX, est le contenu de ce pointeur, en d'autres termes un int.

En outre, la ligne de changement:

char *buffer = malloc(15 * sizeof(int)); 

à:

char *buffer = malloc(15 * sizeof(char)); 

ou simplement:

char *buffer = malloc(15); 

et toujours check the result of malloc:

if (buffer == NULL){ 
    ... 
} 
+0

Cela ne devrait pas être: scanf (buffer, "% d", pX); ?? – scorpGoku

+0

@scorpGoku oui j'écrivais rapidement, merci. – Marievi

+0

Cela n'a pas fonctionné. J'ai déjà essayé. – wanderbread

2

Tout d'abord, il n'y a pas de passage par référence en C, les paramètres de fonction sont tous passés par valeur. En passant un pointeur sur des données, nous faisons la simulation de l'obtention du même effet que le passage par référence, mais cela ne signifie pas que C a un concept de passage par référence.

Cela dit, le problème semble être

scanf(buffer, "%d", *pX); 
        ^^^^ 

  • la syntaxe actuelle est invalide et invoque undefined behavior. Vous avez probablement besoin de sscanf().

  • px est déjà un pointeur vers int. Passer px sera correct et suffisant.

Morale de l'histoire: activer les avertissements du compilateur et y tenir compte. Ils sont là pour une raison.Avec les avertissements appropriés sont activés, vous devriez voir quelque chose comme

avertissement: le format %d attend un argument de type int *, mais l'argument 3 a le type int [-Wformat=]

Enfin,

  • Toujours vérifiez la valeur de retour de fopen() pour réussir avant d'utiliser le pointeur de fichier.
  • Vérifiez la valeur de retour de scanf() pour garantir une numérisation réussie.
  • Vérifier la valeur de retour de fgets() pour assurer le succès

... en gros, vérifier la valeur de retour de tous les appels de bibliothèque pour vous assurer qu'ils ont travaillé comme prévu.

+0

J'ai essayé ça. Cela ne semble pas fonctionner. Au moins dans le programme actuel, j'écris. – wanderbread

+0

@wanderbread vous avez un bug dans votre programme actuel quelque part –

+0

'scanf' devrait être' sscanf' ici –

2

Vous utilisez scanf() correctement: soit utiliser directement scanf pour analyser l'entrée standard ou utiliser sscanf() pour analyser la chaîne lue par fgets(). En outre, pX est déjà un pointeur vers int, qui est ce que sscanf() attend pour stocker la valeur int il convertit, passez directement: sscanf(buffer, "%d", pX);

Voici une version modifiée:

int bar(const char *fileName, int *pX) { 
    char buffer[15]; 
    FILE *fp = fopen(fileName, "r"); 
    int success = 0; 

    if (fp != NULL) { 
     fgets(buffer, sizeof buffer, fp); 
     if (sscanf(buffer, "%d", pX) == 1) 
      success = 1; 
     fclose(fp); 
    } 
    return success; 
} 

void foo(void) { 
    int x = 1; 
    bar("test.txt", &x); 
    /* do something with x */ 
} 

Notes:

  • allocation buf est inutile, juste en faire un tableau local avec stockage automatique.
  • char *buffer = malloc(15 * sizeof(int)); est incorrect: vous allouez de l'espace pour 15 int au lieu de 15 caractères, qui ont une taille de 1 par définition. Utilisez la taille du type de destination afin d'éviter toute incohérence:

    char *buffer = malloc(15 * sizeof(*buffer)); 
    
  • toujours vérifier la valeur de retour de malloc() pour éviter un comportement non défini potentiel.

  • lecture de fp sans vérifier si fopen réussi a un comportement potentiel indéfini.
  • le contenu du tableau pointé par filename n'est pas modifié, en fait un const char *.
  • il peut être utile pour bar de renvoyer un indicateur de réussite.
  • activer plus d'avertissements au moment de la compilation: gcc -Wall -Wextra -Werror ou clang -Weverything -Werror aurait pu attraper les erreurs dans scanf.
+0

Que voulez-vous dire par stockage automatique? Dans mon application actuelle, je dois être capable de gérer des fichiers potentiellement très volumineux. L'allocation basée sur la taille totale du fichier semblait redondante mais un moyen efficace de s'assurer que c'était possible. – wanderbread

+1

Merci également pour la suggestion d'inclure les arguments "-Weverything" et "-Werror". C'est génial, et aidera énormément dans le futur. Y at-il de toute façon que je peux activer ces options de façon permanente? – wanderbread

+0

@wanderbread: le stockage automatique est la valeur par défaut pour les variables locales dans la portée de la fonction, par opposition au stockage statique avec le mot clé 'static'. Un petit tampon, jusqu'à quelques kilooctets, convient pour le stockage automatique, les tableaux plus grands devraient être alloués à partir du tas et libérés après utilisation. – chqrlie