没有Goto的更好方式?

时间:2015-09-17 21:20:42

标签: c goto

我有一个程序,我的代码使用goto语句,我希望以一种很好的方式摆脱它,但我似乎无法找到解决方案。如果goto是最好的方式,请告诉我。以下是代码摘要:

//Counts how many times every word appears in a file
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define NUMWORDS 1000
#define WORDLEN 50

typedef struct
{
  char word[WORDLEN + 1];
  int num;
} Appearance;

int main(int argc, char *argv[]) {
  FILE *readfile;
  Appearance *appearlist[NUMWORDS] = {NULL};
  char word[WORDLEN + 1];
  int i;
  //Get a valid filename and open the file, store pointer into readfile
  ...

  char c;

  while (c != EOF) {
    skip:  //Annoying label
    //Get a word from readfile, store into word
    ...

    if (word[0] != '\0') {
      for (i = 0; i < NUMWORDS && appearlist[i]; i++) {
        if (strcmp(appearlist[i] -> word, word) == 0) {
          appearlist[i] -> num++;
          goto skip; //Annoying goto
        }
      }
      appearlist[i] = (Appearance *) malloc(sizeof(Appearance));
      appearlist[i] -> num = 1;
      strcpy(appearlist[i] -> word, word);
    }
  }

  //Display results, free memory
  ...

  return 0;
}

问题是,我想跳过我想跳过的循环之外的代码。我想不创建另一个仅为此设计的变量。如果您需要完整代码,请单击&#34;显示代码段。&#34;

&#13;
&#13;
//Counts how many times every word appears in a file
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define NUMWORDS 1000
#define WORDLEN 50
#define FILENAMELEN 50

typedef struct
{
  char word[WORDLEN + 1];
  int num;
} Appearance;

int main(int argc, char *argv[])
{
  char filename[FILENAMELEN];
  FILE *readfile;
  Appearance *appearlist[NUMWORDS] = {NULL};
  char word[WORDLEN + 1];
  size_t ln;
  int i;

  if (argc == 2)
    strncpy(filename, argv[1], sizeof(filename));
  else {
    printf("Enter a filename to count appearances from, or just press enter to quit: ");
    fgets(filename, FILENAMELEN, stdin);
    ln = strlen(filename) - 1;
    if (filename[ln] == '\n')
      filename[ln] = '\0';
  }

  while((readfile = fopen(filename, "r")) == NULL) {
    if (filename[0] == '\0')
      return 0;
    printf("Invalid file! Please enter another filename, or just press enter to quit: ");
    fgets(filename, FILENAMELEN, stdin);
    ln = strlen(filename) - 1;
    if (filename[ln] == '\n') filename[ln] = '\0';
  }

  char c;

  while (c != EOF) {
    skip:
    for (i = 0; (c = getc(readfile)) != EOF && (isalnum(c) || c == '\''); i++) {
      if (i >= WORDLEN) {
        word[i] = '\0';
        printf("\nWarning: word too long (over %d characters), trimming to: %s\n", WORDLEN, word);
        while ((c = getc(readfile)) != EOF && (isalnum(c) || c == '\'')) ;
      } else {
        word[i] = tolower(c);
      }
    }
    word[i] = '\0';

    if (word[0] != '\0') {
      for (i = 0; i < NUMWORDS && appearlist[i]; i++) {
        if (strcmp(appearlist[i] -> word, word) == 0) {
          appearlist[i] -> num++;
          goto skip;
        }
      }
      appearlist[i] = (Appearance *) malloc(sizeof(Appearance));
      appearlist[i] -> num = 1;
      strcpy(appearlist[i] -> word, word);
    }
  }

  for (i = 0; i < NUMWORDS && appearlist[i]; i++) {
    printf("Word: %s, Appearances: %d\n", appearlist[i] -> word, appearlist[i] -> num);
    free(appearlist[i]);
  }

  return 0;
}
&#13;
&#13;
&#13;

3 个答案:

答案 0 :(得分:1)

在这种情况下使用goto通常被认为是可以接受的。

替代方法是设置一个变量,以便在continue内部循环之后可以在外循环中break,或者将要逃离的整个段转换为单独的函数,并从中返回,而不是使用goto

我忽略了与问题无关的代码可能存在的任何其他问题!

答案 1 :(得分:1)

将以“if”语句开头的所有内容放入单独的方法中(让我们将其称为“进程”并将goto替换为return。然后while循环变为:

  while (c != EOF) {
    //Get a word from readfile, store into word
    ...
    process(...);
  }

答案 2 :(得分:0)

有时候使用goto提示代码应该使用辅助函数

static bool findword(Appearance *appearlist, size_t size, const char *word) {
  for (size_t i = 0; i < size && appearlist[i]; i++) {
    if (strcmp(appearlist[i]->word, word) == 0) {
      appearlist[i]->num++;
      return true;
    }
  }
  return false;
}


while (c != EOF) {
  //Get a word from readfile, store into word
  ...
  if (word[0] != '\0') {
    if (findword(appearlist, NUMWORDS, word)) {
      continue;
    }
    appearlist[i] = (Appearance *) malloc(sizeof(Appearance));
    appearlist[i] -> num = 1;
    strcpy(appearlist[i] -> word, word);
  }
}