Ошибка памяти при чтении аргументов командной строки в программе на C ++

0

Я писал проект кода C++ для школы, который хочет, чтобы я прочитал текстовый файл из аргумента командной строки и вывел его вместе с добавлением прилагательных, объявленных в командной строке после любых статей [a, an, the]. Это первый раз, когда я должен использовать командную строку для любого проекта.

Мне удалось получить и прочитать текстовый файл из командной строки, но моя проблема в том, что когда я хочу получить строку в качестве параметра функции isArticle(), я продолжаю получать следующее сообщение в оболочке UNIX:

./test-program1[38]: eval: line 1: 7704: Memory fault
0a1,4

Я не подозреваю, что проблема isArticle() функцией isArticle() но вот она:

bool isArticle(string n)
{
    string article[]={"a","an","the","A","An","aN","AN","The","tHe","thE","THe","tHE","ThE","THE"};

    for(int i=0;i<sizeof(article);i++)
    {
        if(n.compare(article[i])==0)
            return true;
    }

    return false;
}

Хотя он не завершен, вот какой-то тестовый код, который я использую, чтобы увидеть, работает ли функция isArticle():

int main(int argc, char *argv[])
{ 
    istream *br;
    ifstream file;

    if(argc == 1)
        br = &cin;
    else if(argc==3)
    {
        file.open(argv[2]);
        if(file.is_open())//put work here
        {
            br=&file;
            string word;
            string output[sizeof(file)];
            while(file>>word)
            {
                if(isArticle(word)==true)
                {
                    cout<<word;
                }
            }
        }
        else
        {
            usage(argv[2],"Cannot open "+string(argv[2]));
            return 1;
        }
    }
    else
    {
        usage(argv[1], "More than one filename was given");
        return 1;
    }
    return 0;
}
  • 2
    Вы должны проверить, что делают sizeof(article) и sizeof(file) (а не то, что вы думаете.)
  • 0
    Чтобы подчеркнуть то, что сказал juanchopanza, sizeof(article) будет намного больше 14, но именно столько строк определено в массиве. Хорошо, что вы включили isArticle() так как это является источником проблемы, так что спасибо, что включили ее. Когда у вас есть определение массива в подобной функции, количество элементов в массиве равно sizeof(article) / sizeof(article[0]) . Это не работает для параметров массива для функций; тогда вызывающему коду необходимо явно передать размер.
Показать ещё 4 комментария
Теги:
memory

2 ответа

0
Лучший ответ

Оператор sizeof не возвращает количество элементов в массиве. Он возвращает пространство памяти, занимаемое массивом. Массив char будет иметь другой sizeof чем массив int.

Для вашего массива вы можете определить количество элементов во время компиляции:

const unsigned int elements_in_array =
    sizeof(article) / sizeof(article[0]);
  • 0
    Будьте очень осторожны, используя sizeof(array) / sizeof(array[0]) ; это опасно. Если массив распался на указатель, он все равно скомпилируется, но не будет делать то, что вы хотите. C ++ 11 имеет std::begin и std::end для этого; до C ++ 11, конечно, у всех нас было что-то эквивалентное в нашем наборе инструментов.
1

Как уже указывали другие, sizeof не дает количество элементов в массиве; идиоматический способ сделать это - использовать std::end( article ) - std::begin( article ). В pre- C++ 11 большинство опытных программистов C++ сделали бы то же самое, используя версии begin и end своего инструментария.

Вся isArticle функция весьма unidiomatic. В C++ 11 вся функция будет одним вызовом библиотеки:

bool
isArticle( std::string const& word )
{
    static std::string const articles[] = {
        "a", "an", "the", "A", "An", "aN", "AN",
        "The", "tHe", "thE", "THe", "tHE", "ThE", "THE",
    };
    return std::any_of(
            std::begin( articles ), std::end( articles ),
            [=]( std::string const& target ) { return word == target; } );
}

В предыдущем C++ мы бы написали:

return std::find( begin( articles ), end( articles ), word )
        != end( articles );

(с самого begin и end нашего обычного инструментария). И если бы мы хотели (по педагогическим причинам) написать цикл самим, это было бы что-то вроде:

std::string::const_iterator current = std::begin( articles );
std::string::const_iterator end = std::end( articles );
while ( current != end && *current != word ) {
    ++ current;
}
return current != end;

Несколько вопросов, которые не связаны с вашей непосредственной проблемой, вероятно, заслуживают упоминания:

  • Типы классов обычно передаются по ссылке на const, а не по значению. Это, возможно, преждевременная оптимизация, но это настолько повсеместно, что все остальное заставляет задуматься, почему.

  • Значения, которые не изменяются в функции, должны быть объявлены как const и static.

  • std::string поддерживает == и !=; если вы ищете равенство, то что вы должны использовать. Функция compare действительно должна использоваться только для лексикографического упорядочения.

  • Возвращение из середины цикла - это то, чего вы обычно хотите избежать. Конечно, когда функции просты, это действительно не имеет значения, но это плохая привычка.

Это касается только рассматриваемой функции. В main вас также есть проблема с sizeof. В этом случае, похоже, вы пытаетесь использовать его для определения количества слов в файле. Это невозможно сделать без фактического чтения файла. Здесь вам понадобится std::vector<std::string>, а не массив стиля C (размер которого должен быть известен во время компиляции).

И, конечно же, тип, необходимый для if является bool. isArticle возвращает bool, поэтому больше ничего не нужно. Написание isArtile( word ) == true настоятельно указывает на то, что вы не знаете, что такое тип bool. (Подсказка: тип выражения isArtile( word ) == true также bool.)

И одно последнее предложение: если в программе нет аргументов, вы ничего не делаете. Я не думаю, что это намерение. Обычное решение для процессов командной строки под Unix (а также широко распространенное под Windows) заключается в том, чтобы поместить всю фактическую работу в функцию и написать что-то вроде:

int
main( int argc, char** argv )
{
    if ( argc == 1 ) {
        process( std::cin );
    } else {
        for ( int i = 1; i != argc; ++ i ) {
            std::ifstream in( argv[i] );
            if ( ! in ) {
                //  Output error message and set global flag for
                //  return value...
            } else {
                process( in );
            }
        }
    }
    return globalFlagWithReturnValue;
}

Функция process занимает std::istream& в качестве аргумента, что позволяет ему читать либо std::cin или открыт std::istream.

  • 0
    Я не понимаю Код, который вы разместили, имеет производные от ostream , но в последующем предложении говорится об istream . Что это?
  • 0
    @ThomasMatthews Я не знаю, о чем я думал. Очевидно, это должны быть istream производные std::cin и std::ifstream (так как это входные данные). Я исправил это. Благодарю.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню