2015-04-28 1 views
1
#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <string.h> 

typedef int bool; 
#define true 1 
#define false 0 

#define A 65 
#define Z 90 
#define a 97 
#define z 122 
#define NEWLINE 10 

int main(int argc, char* argv[]) 
{ 
    int noArgReverse(); 
    int argReverse(int i, char* c[]); 
    if (argc == 1){ 
     if (noArgReverse() == 0) 
      return 0; 
     else 
      return 1; 
    } 
    if (argc > 1){ 
     if (argReverse(argc, argv) == 0) 
      return 0; 
     else 
      return 1; 
    } 
    else{ 
     fprintf(stderr, "unknown error detected.\n"); 
     return 1; 
    } 
} 

int noArgReverse() 
{ 
    char charInput[10000]; 
    int pointerArray[5000]; 
    int pointerCount = 0; 
    bool wordStart = false; 
    int indexer; 
    int lineLength; 
    int parser; 
    char currInput; 

    pointerArray[0] = 0; // first word would start at 0 be default 

    while (currInput != EOF){ 
     lineLength = 0; 
     indexer = 0; 
     pointerCount = 0; 
     while ((currInput = getc(stdin)) != NEWLINE){ 
      /* 
      * I am implementing a 10,000 char limit, as this seems an 
      * unreasonable length. 
      */ 
      if (lineLength == 9999){ 
       fprintf(stderr, "Line length exceeded 10,000 chars. " 
         "This line and, if in the middle of a word," 
         "will be split.\n"); 
       break; 
      } 

      if (!wordStart){ 
       if ((currInput >= A && currInput <= Z) || (currInput >= a && currInput <= z)){ 
        wordStart = true; 
       } 
      } 

      while (wordStart){ 
       charInput[lineLength++] = currInput; 
       currInput = getc(stdin); 
       //if the word has ended 
       if ((currInput < A || currInput > Z) && (currInput < a || currInput > z)){ 
        wordStart = false; 
        charInput[lineLength++] = '\0'; 
        if (pointerCount != 0){ // at least one word has been added 
         ++indexer; 
         pointerArray[indexer] = pointerCount; 
         pointerCount = lineLength; 
        } 
        else //first word of the line to be added 
         pointerCount = lineLength; 
       } 
      } 
     } 

     while (indexer >= 0){ 
      parser = pointerArray[indexer--]; 
      while (charInput[parser] != '\0') 
       fprintf (stdout, "%c", charInput[parser++]); 
      fprintf (stdout, " "); 
     } 
     fprintf (stdout, "\r\n"); 

     if (lineLength == 0){ 
      currInput = EOF; 
     } 
    } 
    return 0; 
} 

int argReverse (int argc, char* argv[]) 
{ 
    char charInput[10000]; 
    int pointerArray[5000]; 
    int pointerCount = 0; 
    bool wordStart = false; 
    int indexer; 
    int lineLength; 
    int parser; 
    char currInput; 
    FILE *currentFile; 

    while (argc > 0){ 
     currentFile = fopen(argv[argc--], "r"); 
     while ((currInput = getc(currentFile)) != EOF){ 
      lineLength = 0; 
      indexer = 0; 
      pointerCount = 0; 
      while (currInput != NEWLINE){ 
       /* 
       * I am implementing a 10,000 char limit, as this seems an 
       * unreasonable length for a single line. 
       */ 
       if (lineLength == 9999){ 
        fprintf(stderr, "Line length exceeded 10,000 chars. " 
          "This line and, if in the middle of a word, the word, " 
          "will be split.\n"); 
        break; 
       } 

       if (!wordStart){ 
        if ((currInput >= A && currInput <= Z) || (currInput >= a && currInput <= z)){ 
         wordStart = true; 
        } 
       } 

       while (wordStart){ 
        charInput[lineLength++] = currInput; 
        currInput = getc(currentFile); 
        //if the word has ended 
        if ((currInput < A || currInput > Z) && (currInput < a || currInput > z)){ 
         wordStart = false; 
         charInput[lineLength++] = '\0'; 
         if (pointerCount != 0){ // at least one word has been added 
          ++indexer; 
          pointerArray[indexer] = pointerCount; 
          pointerCount = lineLength; 
         } 
         else //first word of the line to be added 
          pointerCount = lineLength; 
        } 
       } 
      } 
     } 
     fclose(currentFile); 
    } 
    return 0; 
} 

Итак, для моей первой функции я получаю сообщение об ошибке. Кажется, я не могу добраться до нижней части до отладки или, скорее, , Я не уверен, как решить. Функция должна принимать данные от stdin и печатать слова в обратном порядке (символы должны оставаться в порядке, поэтому «Это предложение» должно быть «предложение a это»). Достаточно просто. Однако, когда я даю образец ввода, вывод, который я получаю, ошибочен.Stdin с getc, производящим дополнительный выход, и файл открытия, вызывающий ошибку сегментации в C

вход:

This is sample 
input for testing 

выход:

testing for input sample is This 

This 

вход имеет одно возвращение, но выход имеет дополнительный возврат между строк, и не расщепляется линии.

Итак, это не печать новой строки, когда она должна, и она печатает первое введенное слово снова, когда оно заканчивается.

Второй вопрос, который у меня есть, - это второй набор кода, функция argReverse. После открытия файла в этом случае я использую test.txt, который представляет собой простой текстовый файл с парами строк фраз и пустых строк, первое использование getc возвращает ошибку сегментации. Я прочитал это разрешение или неудачное открытие файла, но я не уверен, что делать, чтобы исправить это. Я пытаюсь сначала открыть последний файл и работать там, очевидно, и это должно быть способно обрабатывать несколько файлов, но я даже не могу его открыть. Я не уверен, что делать, чтобы исправить это. Я попытался переместить getc за пределы цикла while, той же проблемой. Я предполагаю, что я делаю что-то неправильно с открытием файла, но я не знаю, что это такое.

+0

1) 'символ currInput; .... while (currInput! = EOF) {'использует переменную, которая еще не была инициализирована. 2) 'char currInput;' должен быть 'int'. 3) Вероятно, другие проблемы. – chux

+1

Логика 'currInput' запутана. Похоже, что он может оставаться в цикле 'while (currInput! = NEWLINE) даже когда он становится' EOF'. Может быть, замените на 'while (currInput! = NEWLINE && currInput! = EOF) {' – chux

+0

Прошло мимо этого, хотя и проверяйте, так что это не кажется проблемой, в отношении 'while (currInput! = EOF) '. Что касается 'argv [argc]' всегда возвращающего null ... что я должен сделать, чтобы исправить это? Должен ли я просто передать другой 'int', содержащий значение' argc'? –

ответ

2

Заметки о стиле:

The bool типа и true и false определены в <stdbool.h>.

Используйте символьные константы, такие как 'A' 'Z' 'a' 'z' '\n' вместо жестко закодированных чисел, и/или используйте функции классификации символов, такие как isalpha от <ctype.h>.

«Обратные» функции просто возвращают 0, когда они заканчиваются, поэтому нет смысла возвращать что-либо. Они должны быть объявлены как возвращающиеся void. Если они вернут что-то полезное, я верну эту стоимость с main (исключая утверждения if). Например,

if (argc == 1) 
    return noArgReverse(); 

Ввод больших массивов в стек обычно плохой идеей. (Большой субъективен, но я использую 2K байта как правило.) Для нереентеративной функции вы можете объявить массивы как static, чтобы получить их из стека. Для реентерабельной функции вы можете malloc массивов и free их в конце.

Замечания по конструкции:

fgets функция будет читать строку и поместить его в буфер. Нет необходимости читать персонажа за раз.

При обработке аргументов командной строки, канонический цикл

int main(int argc, char *argv[]) 
{ 
    for (int i = 1; i < argc; i++) 
     printf("argv[%d] is \"%s\"\n", i, argv[i]); 
} 

Причина для SEG-вины в том, что вы используете argv[argc], что спецификация C гарантирует, что NULL. Итак, вы проходите NULL по номеру fopen. Кроме того, вы всегда должны проверять возвращаемое значение с fopen, потому что fopen вернет NULL, если он не может открыть файл.

На сегодняшний день самая большая проблема с дизайном в коде - повторение. У вас есть две почти идентичные функции, которые являются кошмаром для отладки и поддержки, поскольку каждое изменение нужно делать дважды и проверять дважды. Решение состоит в том, чтобы определить функцию reverse, которая принимает указатель файла как входной. Функция main должна позаботиться об открытии/закрытии файлов или передать stdin, когда нет никаких аргументов.

Пример кода:

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

#define MAXL 10000 
#define MAXW 5000 

void reverse(FILE *fp); 

int main(int argc, char *argv[]) 
{ 
    if (argc < 2) 
    { 
     reverse(stdin); 
     return 0; 
    } 

    FILE *fp; 
    for (int i = 1; i < argc; i++) 
    { 
     printf("----- %s -----\n", argv[i]); 
     if ((fp = fopen(argv[i], "r")) == NULL) 
     { 
      printf("***Error: unable to open file\n"); 
     } 
     else 
     { 
      reverse(fp); 
      fclose(fp); 
     } 
    } 

    return 0; 
} 

void reverse(FILE *fp) 
{ 
    static char line[MAXL]; // buffer for the input line 
    static char *word[MAXW]; // array of pointers to the words on the line 

    while (fgets(line, MAXL, fp) != NULL) 
    { 
     int i = -1; 
     int count = 0;  // count of words on the line 
     for (;;) 
     { 
      // skip any non-alpha characters 
      for (i++; line[i]; i++) 
       if (isalpha(line[i])) 
        break; 

      // check if we've reached the end of the line 
      if (!line[i]) 
       break; 

      // add the pointer to the word list 
      word[count++] = &line[i]; 

      // scan till we reach the end of the word 
      for (i++; line[i]; i++) 
       if (!isalpha(line[i])) 
        break; 

      // check if we've reached the end of the line 
      if (!line[i]) 
       break; 

      // terminate the word 
      line[i] = '\0'; 
     } 

     // output the words in reverse order 
     for (i = count - 1; i >= 0; i--) 
      printf("%s ", word[i]); 
     printf("\n"); 
    } 
} 
+0

Спасибо за помощь, но мой профессор сказал, что я должен использовать 'getc'. Он также сказал мне, что ему все равно, сколько памяти или насколько эффективен код, хотя ваши комментарии вполне допустимы. Кроме того, я должен уметь обрабатывать тот факт, что 'stdin' будет использоваться, если он не передает файлы в качестве аргументов. Кроме того, все вещи должны быть напечатаны на 'stdout' или' stderr'. –

+0

Первый оператор 'if' в' main' обрабатывает случай no-arguments, передавая 'stdin' функции' reverse'. Обратите внимание, что 'stdin' - это указатель на файл' FILE * ', как и любой другой. Что касается использования 'getc', то в этом случае решение состоит в том, чтобы написать собственную функцию' fgets', которая считывает строку в буфер. Одна из проблем вашего кода заключается в том, что вы смешиваете код, который читает строку в коде, который анализирует строку. Полученный код имеет 'getc' на трех разных уровнях вложенных циклов, которые вам трудно найти. – user3386109

+0

Хорошо, спасибо вам за помощь. Я перейду к написанию функции 'fgets'. –