2013-06-01 1 views
2

A l'origine, cette fonction était intégrée dans la fonction principale, créant une fonction principale très encombrée. Le programme remplace les onglets par le nombre d'espaces. Je suis toujours confus quant à ce qui se passe dans les listes d'arguments pour mes fonctions et comment passer argc/argv de main dans ces fonctions. Est-ce que je l'ai fait bien?J'ai essayé de décomposer ma fonction, mais je ne suis pas sûr si je l'ai fait correctement

Il y a des variables définies en haut du fichier:

#define OUTFILE_NAME "detabbed" 
#define TAB_STOP_SIZE 8 
#define NUM_ARGS 2 
#define FILE_ARG_IDX 1 

Voici mon deuxième tentative il:

void open_file(FILE *inf, FILE *outf, char *in[]) /*I feel like the arguments aren't right 
{             and this function is just opening 
                and reading files*/ 
    inf = fopen(in[1], "r"); 
    outf = fopen(OUTFILE_NAME, "w"); 

    if (inf == NULL) 
    { 
     perror(in[1]); 
     exit(1); 
    } 

    else if (outf == NULL) 
    { 
     perror(OUTFILE_NAME); 
     exit(1); 
    } 

    fclose(inf); 
    fclose(outf); 
} 

void detab(FILE *infile, FILE *outfile, char *argument[]) /* Confused about argument list 
{               and this function actually 
    char c;             does the detabbing */ 
    int character_count = 0, i, num_spaces; 

    open_file(infile, outfile, argument);     /* I want to call the previous 
                  function but again, confused 
    while (fscanf(infile, "%c", &c) != EOF)    about the argument list */ 
    { 
     if (c == '\t') 
     { 
     num_spaces = TAB_STOP_SIZE - (character_count % TAB_STOP_SIZE); 

     for (i = 0; i < num_spaces; i++) 
     { 
      fprintf(outfile, " "); 
     } 

     character_count += num_spaces; 
     } 
     else if (c == '\n') 
     { 

     fprintf(outfile, "\n"); 
     character_count = 0; 
     } 
     else 
     { 
     fprintf(outfile, "%c", c); 
     character_count++; 
     } 
    } 

} 

int main(int argc, char *argv[]) 
{ 
    if (argc < 1) 
    { 
     fprintf(stderr, "usage: prog file\n"); 
     exit(1); 
    } 

    else if (argc < NUM_ARGS) 
    { 
     fprintf(stderr, "usage: %s file\n", argv[0]); 
     exit(1); 
    } 

    detab(argc, argv); /* I want to pass argc and argv to the detab function, but I'm 
          having trouble with the argument list */ 
    return 0; 
} 

Ce que je besoin d'aide, est de trouver ce qui se passe dans la listes d'arguments des fonctions. Je pense que ce qui m'embrouille, c'est comment faire correspondre mes types d'arguments, de sorte que je puisse passer des variables d'une fonction à l'autre.

+0

L'existence de la fonction est de réutiliser des extraits de code plus tard. Si votre fonction n'est invoquée qu'une seule fois, je pense que cela peut être une optimisation prématurée. –

+5

@Summer_More_More_Tea [No.] (http://blog.regehr.org/archives/942) –

+0

@ H2CO3 Merci, y jeter un coup d'œil. –

Répondre

3

La décomposition n'est pas votre plus gros problème ici. Vérification d'erreur plutôt négligente, l'utilisation de vieilles surpondérées fscanf() et fprintf() et les variables globales sont. En outre, le manque de const constance dans les noms de fichiers en entrée, les noms de variables trop longs et verbeux et votre ignorance des opérateurs += et ++ sont juste le bonus. Je suppose que c'est pour ça que ton code a l'air gonflé (et c'est, en fait).

Je réécris la fonction comme ceci:

void detab(const char *in, const char *out, int tabstop) 
{ 
    FILE *inf = fopen(in, "r"); 
    if (!inf) return; 

    FILE *outf = fopen(out, "w"); 
    if (!outf) { 
     fclose(inf); 
     return; 
    } 

    int n = 0; 
    int c; 
    while ((c = fgetc(inf)) != EOF) { 
     if (c == '\t') { 
      int pad = tabstop - n % tabstop; 

      for (int i = 0; i < pad; i++) 
       fputc(' ', outf); 

      n += pad; 
     } else if (c == '\n') { 
      fputc('\n', outf); 
      n = 0; 
     } else { 
      fputc(c, outf); 
      n++; 
     } 
    } 

    fclose(inf); 
    fclose(outf); 
} 

Si vous voulez décomposer encore plus loin, alors vous pouvez écrire une fonction prenant deux FILE * et l'arrêt de l'onglet comme ses arguments et Shall contient la boucle while seulement - faire cela vous est laissé comme exercice.

+0

Donc, si je fais cela, alors dans la fonction principale, comment je passerais argc et argv à la fonction detab? (Puisque les types d'arguments ne correspondent pas/detab a trois arguments) – Karen

+0

@Karen 'void other_function (FICHIER * inf, FICHIER * outf, int tabstop)' –

+0

Alors que cette autre fonction ne contiendrait que la boucle while droite? Mais ce qui me dérange, c'est que main n'a que argc et argv dans sa liste d'arguments. Donc, à l'intérieur de la fonction principale, quand j'appelle cette autre fonction, comment puis-je traiter les trois arguments de la liste d'arguments d'une autre fonction? – Karen

3

Note: Cette réponse a été donnée à une édition antérieure de la question. Il a changé entre-temps, donc cette réponse peut ne plus sembler pertinente.

Venant d'un arrière-plan de la POO, je vais me concentrer sur un seul problème qui est là connu sous le nom Single Responsibility Principle (SRP). Je fais valoir que detab (et toutes les autres fonctions) devrait faire seulement une chose spécifique, mais faites bien cette chose.

Mais il ne se contente pas de "detab", comme son nom l'indique; elle a aussi d'extraire ses réels arguments à partir des variables de ligne de commande argc et argv, qui ont été Imposé par main:

detab(argc, argv); 

main a fait une validation avant, mais parce que la ligne de commande est puis tout simplement passé à la fonction, on se sentait de toute évidence comme la validation continue à detab (je fais aussi quelques remarques supplémentaires sur la violation de SRP ci-dessous):

void detab(int arg_list, char *array[]) // why ask for arg_list if you don't need it? 
{ 
    … 
    infile = fopen(array[1], "r"); // not obvious to caller that only array[1] is relevant 
    … 
    if (infile == NULL) 
    { 
     perror(array[1]); 
     exit(1); // should your function really have the power to terminate the program? 
    } 
    … 
} 

Il semblerait beaucoup plus reaso pouvoir concentrer toute la logique de validation de la ligne de commande et d'extraction de valeur dans un endroit, et la détacher dans une autre; c'est-à-dire, dessiner des limites claires de responsabilité. Ne laissez pas la logique d'une fonction déborder dans une autre!

Pour moi, la signature de detab devrait ressembler plus par ex. ceci:

void detab(FILE *in, FILE *out); 
+0

Si j'ai deux fonctions (comme je l'ai dit plus haut), et que je veux appeler la première fonction de la deuxième fonction, comment pourrais-je structurer la liste des arguments? J'ai du mal à essayer de faire correspondre les types d'arguments et comment mon code changerait si j'avais ces variables définies en haut? Merci! – Karen

+0

Vous avez changé votre question initiale en une question différente. Cela conduit souvent à des réponses antérieures devenues obsolètes, et à démarrer un ping-pong Q & A ouvert, ce qui n'est pas le cas pour Stack Overflow. Si vous avez un problème de suivi, posez-le comme une nouvelle question, afin que les gens n'aient pas à réviser leurs réponses ici et là encore et encore. Merci! – stakx

Questions connexes