Russian Qt Forum

Qt => Общие вопросы => Тема начата: 8Observer8 от Февраль 13, 2014, 09:47



Название: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 13, 2014, 09:47
Внимание! Эта тема перетекла, в следующую тему, в шапку которой я буду добавлять изменения/добавления. Вам достаточно будет подписаться на неё. О всех измененияx/добавленияx я буду извещать: http://www.prog.org.ru/topic_26944_0.html

Привет!

Решил для тренировки навыков быстрого программирования ежедневно уделять время решению задач с этого ресурса: http://acmp.ru/?main=tasks (http://acmp.ru/?main=tasks)

Здесь я прошу помощи в решении задач. Как решить задачу, используя STL, c минимальным количеством строк кода. Будет много вопросов. Пока я решаю только простые задачки. Позже опишу конкретные вопросы.

Как альтернативу можете предлагать свои решения с использованием C++11 и Boost. К сожалению, сервер с задачами не принимает решения C++11 и Boost. Поэтому они будут просто для демонстрации. Я буду изучать C++11 и Boost, поэтому мне это крайне интересно.

О методологии быстрой разработки я узнаю из книги: "Принципы, паттерны и методики гибкой разработки на языке C#"

Хотя там на примере C# на самом деле её поймут и джависты и приплюснутые. Книга не о языке.

Скачать:http://rutracker.org/forum/viewtopic.php?t=4295746 (http://rutracker.org/forum/viewtopic.php?t=4295746)
Исходники: http://www.objectmentor.com/PPP/ (http://www.objectmentor.com/PPP/)

Классная книжка. Правда я только по диагонали прочитал первую часть: "Часть 1. Быстрая разработка ПО"

Одно из главных мест в быстрой разработке занимает "Разработка через тестирование"

Я решаю школьные олимпиадные задачи с ресурса выше по принципу "Разработка через тестирование", чтобы отработать навыки.

Как написано здесь: http://acmp.ru/article.asp?id_text=118 (http://acmp.ru/article.asp?id_text=118)
Решение задач учит быстро программировать:
Цитировать
В отличии от обычных программ, создаваемых программистами повседневно, класс олимпиадных задач достаточно узок, но практичен с точки критериев выявления способности участников программировать за короткий срок. Как правило, олимпиадная задача представляет собой некоторую проблему, для решения которой требуется использовать свой IQ почти напределе, однако, сам текст программы может быть совсем незначительным и помещаться на одной странице.

Решаю задачи так. Сначала пишу заглушку для функции. Потом создаю тест (в среде NetBeans тесты создаются легко и быстро, поддержка CppUnit встроена в среду; NetBeans так же поддерживает разработку на Qt). Описываю весь функционал этой функции в тесте. После первого запуска тестов мы имеем красную полосу. В данном примере она почти пустая, так как функция возвращает ноль и это совпало с одним из тестов:

(http://i7.pixs.ru/storage/7/4/1/125png_2844933_10855741.png)

Теперь нужно реализовывать постепенно функционал, чтобы удовлетворить всем тестам. Как только что-то напишем в функции, то тут же запускаем тест (Alt+F6), чтобы удостовериться, что мы продвинулись дальше по красной полосе и что ничего не испортили. Когда весь функционал будет реализован, то полоса станет зелёной. На рисунке выше, кстати, решение простой задачки с разрезанием торта: http://acmp.ru/index.asp?main=task&id_task=539 (http://acmp.ru/index.asp?main=task&id_task=539)

Написал пошаговую инструкцию по разработке через тестирование на C++ в среде NetBeans на примере решения задачи с acmp.ru: http://notes.orgfree.com/tdd_cpp.php

Вот решение задачи с тортом http://acmp.ru/index.asp?main=task&id_task=539 (http://acmp.ru/index.asp?main=task&id_task=539) и тесты для неё:
main.cpp
Код:
/* 
 * File:   main.cpp
 * Author: Ivan
 *
 * Created on January 7, 2014, 2:30 PM
 */

#include <iostream>
#include <fstream>
using namespace std;

int cuttingOfCake(int nmen) {
    int result = 0;
    
    if ((nmen == 0) || (nmen == 1)) {
        result = 0;
    } else if (nmen%2 == 0) {
        result = nmen / 2;
    } else {
        result = nmen;
    }
    
    return result;
}

int main(int argc, char** argv) {
    string inFileName = "input.txt";
    ifstream in;
    in.open(inFileName.c_str());
    if (!in.is_open()) {
        cerr << "Error: could not open the file " << inFileName.c_str() << endl;
        return 1;
    }

    string outFileName = "output.txt";
    ofstream out;
    out.open(outFileName.c_str());
    if (!out.is_open()) {
        cerr << "Error: could not open the file " << outFileName.c_str() << endl;
        in.close();
        return 1;
    }

    int nmen;
    if (in >> nmen) {
        int result = cuttingOfCake(nmen);
        out << result << endl;
    } else {
        cerr << "Error: incorrect data in the file " << inFileName.c_str() << endl;
        in.close();
        out.close();
        return 1;
    }

    in.close();
    out.close();
    return 0;
}

newtestclass.cpp
Код:
/*
 * File:   newtestclass.cpp
 * Author: Ivan
 *
 * Created on Jan 7, 2014, 2:53:05 PM
 */

#include "newtestclass.h"


CPPUNIT_TEST_SUITE_REGISTRATION(newtestclass);

newtestclass::newtestclass() {
}

newtestclass::~newtestclass() {
}

void newtestclass::setUp() {
}

void newtestclass::tearDown() {
}

int cuttingOfCake(int nmen);

void newtestclass::testCuttingOfCake_001() {
    int nmen = 2;
    int actual = cuttingOfCake(nmen);
    int expected = 1;
    CPPUNIT_ASSERT_EQUAL(expected, actual);
}

void newtestclass::testCuttingOfCake_002() {
    int nmen = 3;
    int actual = cuttingOfCake(nmen);
    int expected = 3;
    CPPUNIT_ASSERT_EQUAL(expected, actual);
}

void newtestclass::testCuttingOfCake_003() {
    int nmen = 4;
    int actual = cuttingOfCake(nmen);
    int expected = 2;
    CPPUNIT_ASSERT_EQUAL(expected, actual);
}

void newtestclass::testCuttingOfCake_004() {
    int nmen = 5;
    int actual = cuttingOfCake(nmen);
    int expected = 5;

    CPPUNIT_ASSERT_EQUAL(expected, actual);
}

void newtestclass::testCuttingOfCake_005() {
    int nmen = 6;
    int actual = cuttingOfCake(nmen);
    int expected = 3;

    CPPUNIT_ASSERT_EQUAL(expected, actual);
}

void newtestclass::testCuttingOfCake_006() {
    int nmen = 7;
    int actual = cuttingOfCake(nmen);
    int expected = 7;

    CPPUNIT_ASSERT_EQUAL(expected, actual);
}

void newtestclass::testCuttingOfCake_007() {
    int nmen = 8;
    int actual = cuttingOfCake(nmen);
    int expected = 4;

    CPPUNIT_ASSERT_EQUAL(expected, actual);
}

void newtestclass::testCuttingOfCake_008() {
    int nmen = 0;
    int actual = cuttingOfCake(nmen);
    int expected = 0;

    CPPUNIT_ASSERT_EQUAL(expected, actual);
}

void newtestclass::testCuttingOfCake_009() {
    int nmen = 1;
    int actual = cuttingOfCake(nmen);
    int expected = 0;

    CPPUNIT_ASSERT_EQUAL(expected, actual);
}


Название: Re: Тренировка навыков быстрого программирования
Отправлено: kuzulis от Февраль 13, 2014, 10:18
Этот ресурс - не место для бложиков. Заведи себе аккаунт где нить еще и там пости свои философские мысли, ИМХО. :)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 13, 2014, 11:27
У меня проблема с этой задачей: http://acmp.ru/index.asp?main=task&id_task=272

В входном файле не написано сколько будет элементов в массиве.

Я в цикле while считываю значение, пока считывается и проверяю корректно ли оно:

Код:
    vector<int> arr;
    int value;
    string input;
    stringstream stream;
    while (in >> input) {
        stream << input;
        if (stream >> value) {
            cout << value << endl;
        } else {
            cerr << "Error: incorrect data in the file " << inFileName.c_str() << endl;
            in.close();
            out.close();
            return 1;
        }
    }

Вот весь код:
Код:
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;

int sumOfMaxAndMin(const vector<int>& arr) {
    int sum = 0;

    return sum;
}

int main(int argc, char** argv) {
    string inFileName = "input.txt";
    ifstream in;
    in.open(inFileName.c_str());
    if (!in.is_open()) {
        cerr << "Error: could not open the file " << inFileName.c_str() << endl;
        return 1;
    }

    string outFileName = "output.txt";
    ofstream out;
    out.open(outFileName.c_str());
    if (!out.is_open()) {
        cerr << "Error: could not open the file " << outFileName.c_str() << endl;
        in.close();
        return 1;
    }

    vector<int> arr;
    int value;
    string input;
    stringstream stream;
    while (in >> input) {
        stream << input;
        if (stream >> value) {
            cout << value << endl;
        } else {
            cerr << "Error: incorrect data in the file " << inFileName.c_str() << endl;
            in.close();
            out.close();
            return 1;
        }
    }

    int sum = sumOfMaxAndMin(arr);
    out << sum << endl;

    in.close();
    out.close();
    return 0;
}

В файле input.txt у меня это:
1 -2 3 -4 5

Но почему-то выдаётся сообщение: Error: incorrect data in the file

Скорее всего ловится перевод строки. Как считать числа в массив если неизвеcтно их количество?


Название: Re: Тренировка навыков быстрого программирования
Отправлено: OKTA от Февраль 13, 2014, 11:33
Прочитай какую-нибудь книжку по Си и поймешь, что нафиг не нужны никакие векторы, стринги и стрингстримы для реализации очень и очень многих функций, а главное код будет короче, понятнее и бысрее ;D извини, но плюнул читать уже на середине - не читается ;D


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 13, 2014, 11:43
Прочитай какую-нибудь книжку по Си и поймешь, что нафиг не нужны никакие векторы, стринги и стрингстримы для реализации очень и очень многих функций, а главное код будет короче, понятнее и бысрее ;D извини, но плюнул читать уже на середине - не читается ;D

Мне не нужен Си, а нужен C++ и STL.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Февраль 13, 2014, 12:29
Как считать числа в массив если неизвеcтно их количество?
Код
C++ (Qt)
while (in >> val)
arr.push_back(val);
 

В целом тема производит впечатление поверхности, торопливости, словом - халтура. 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Hrundel от Февраль 13, 2014, 12:47
А какое отношение имеет все это к Qt форуму???

Не стоит ли с подобными вопросами отправиться куда-нибудь типа cyberforum.ru. Там и по башке настучат как следует. И вообще, начнешь ценить время людей и приличное общение.

И что значит - "не нуежн си" ??? В первом семестре мы писали только на си. Когда си полностью освоили, что смогли проги с консольной графикой писать, только тогда уже перешли на  спп.
Я бы даже попросил модератора удалить эту тему.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 13, 2014, 13:02
А какое отношение имеет все это к Qt форуму???

Не стоит ли с подобными вопросами отправиться куда-нибудь типа cyberforum.ru. Там и по башке настучат как следует. И вообще, начнешь ценить время людей и приличное общение.

И что значит - "не нуежн си" ??? В первом семестре мы писали только на си. Когда си полностью освоили, что смогли проги с консольной графикой писать, только тогда уже перешли на  спп.
Я бы даже попросил модератора удалить эту тему.

Я знаю Си. K$R прочитан полностью и почти все задачи решил. Писал немного на WinAPI и Си, когда в КБ работал инженером-конструктором.

У меня нет времени бегать по форумам. Я выбрал этот. Он мне очень понравился. Тут классное управление, минимум рекламы (в отличае от cyberforum.ru), а самое главное, что тут много адекватных людей. Я не уйду никуда. Хочу остановиться именно на этом форуме и точка.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 13, 2014, 13:15
Как считать числа в массив если неизвеcтно их количество?
Код
C++ (Qt)
while (in >> val)
arr.push_back(val);
 

Так не пойдёт. Мне нужно проверять значение val и если оно не целое, то выдавать сообщение: Error: incorrect data in the file

В целом тема производит впечатление поверхности, торопливости, словом - халтура.  
Значит Вы не поняли. Грустно :( Лучше бы сказали, чем профи сейчас пользуются.

Я слышал, что googletest популярен. Его можно для Qt приспособить?


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 13, 2014, 13:24
Я заметил в пошаговом режиме, что вылетает на втором проходе цикла:

Код:
    vector<int> arr;
    int value;
    string input;
    stringstream stream;
    while (in >> input) {
        stream << input;
        if (stream >> value) {
            cout << value << endl;
            arr.push_back(value);
        } else {
            cerr << "Error: incorrect data in the file " << inFileName.c_str() << endl;
            in.close();
            out.close();
            return 1;
        }
    }


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 13, 2014, 13:30
Я кажется понял. Объект stream накапливает в себе элементы, поэтому на втором шаге в нём хранятся уже два элемента и операция "stream >> value" выдаёт false.

Я попробовал очистить:

Код:
stream.clear();

Всё равно не помогает :(


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Bepec от Февраль 13, 2014, 13:38
Присоединяюсь к вышеотписавшимся - переносите свою чудо тему в говорилку. И тут не блог, а форум по Qt.



Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 13, 2014, 13:43
Присоединяюсь к вышеотписавшимся - переносите свою чудо тему в говорилку. И тут не блог, а форум по Qt.

Я же просил помочь мне задачи по програмированию решать. Я просто кратко описал, как я это делаю. Думал, что кому-то это пригодиться. Что тут плохого? Если я Вас раздрожаю чем-то, то просто не открывайте мои темы.

Я нашёл решение, как считать массив и при этом проверять корректность данных:

Код:
    vector<int> arr;
    int value;
    string input;
    while (in >> input) {
        if (stringstream(input) >> value) {
            cout << value << endl;
            arr.push_back(value);
        } else {
            cerr << "Error: incorrect data in the file " << inFileName.c_str() << endl;
            in.close();
            out.close();
            return 1;
        }
    }


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Февраль 13, 2014, 13:43
Так не пойдёт. Мне нужно проверять значение val и если оно не целое, то выдавать сообщение: Error: incorrect data in the file
Тогда после цикла добавьте
Код
C++ (Qt)
if (!in.eof())
// печать ошибки
 

Я знаю Си. K$R прочитан полностью и почти все задачи решил. Писал немного на WinAPI и Си, когда в КБ работал инженером-конструктором.
В базовых вещах "плаваете" капитально, опыта/кладки почти нет. Ну не пишет программист 3 раза in.close(), не валит все в main и.т.д.

Я не уйду никуда. Хочу остановиться именно на этом форуме и точка.
Вас никто не гонит :)  Но тренировки "на скорость" явно преждевременны


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 13, 2014, 13:52
Так не пойдёт. Мне нужно проверять значение val и если оно не целое, то выдавать сообщение: Error: incorrect data in the file
Тогда после цикла добавьте
Код
C++ (Qt)
if (!in.eof())
// печать ошибки
 

А как я написал выше пойдёт?

Я знаю Си. K$R прочитан полностью и почти все задачи решил. Писал немного на WinAPI и Си, когда в КБ работал инженером-конструктором.
В базовых вещах "плаваете" капитально, опыта/кладки почти нет. Ну не пишет программист 3 раза in.close(), не валит все в main и.т.д.
Я валю всё в main.cpp, потому что сервер принимает только один файл - main.cpp.

Как мне не писать in.close() 3 раза. Покажите, пожалуйста:

Код:
/* 
 * File:   main.cpp
 * Author: Ivan
 *
 * Created on January 7, 2014, 10:33 AM
 */

#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;

int sumOfMaxAndMin(const vector<int>& arr) {
    int sum = 0;

    return sum;
}

int main(int argc, char** argv) {
    string inFileName = "input.txt";
    ifstream in;
    in.open(inFileName.c_str());
    if (!in.is_open()) {
        cerr << "Error: could not open the file " << inFileName.c_str() << endl;
        return 1;
    }

    string outFileName = "output.txt";
    ofstream out;
    out.open(outFileName.c_str());
    if (!out.is_open()) {
        cerr << "Error: could not open the file " << outFileName.c_str() << endl;
        in.close();
        return 1;
    }

    vector<int> arr;
    int value;
    string input;
    while (in >> input) {
        if (stringstream(input) >> value) {
            arr.push_back(value);
        } else {
            cerr << "Error: incorrect data in the file " << inFileName.c_str() << endl;
            in.close();
            out.close();
            return 1;
        }
    }

    int sum = sumOfMaxAndMin(arr);
    out << sum << endl;

    in.close();
    out.close();
    return 0;
}

Я не уйду никуда. Хочу остановиться именно на этом форуме и точка.
Вас никто не гонит :)  Но тренировки "на скорость" явно преждевременны

Я не на скорость решаю, а чтобы правильно задачи научиться решать, используя для этого STL.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Hrundel от Февраль 13, 2014, 14:23
В целом тема производит впечатление поверхности, торопливости, словом - халтура.  
Значит Вы не поняли. Грустно :( Лучше бы сказали, чем профи сейчас пользуются.

Я слышал, что googletest популярен. Его можно для Qt приспособить?

Профи пишут Unit-тесты с использованием QTest и QTestLib http://qt-project.org/doc/qt-4.8/qtestlib-manual.html#qtestlib (http://qt-project.org/doc/qt-4.8/qtestlib-manual.html#qtestlib)
Хотя, чистым CPPUnit тоже не плохо http://sourceforge.net/apps/mediawiki/cppunit/index.php?title=Main_Page (http://sourceforge.net/apps/mediawiki/cppunit/index.php?title=Main_Page)

Я так понимаю ты пытаешься сразу по концепции Extrem программирования писать? Только без знаний разработки архитектуры это будет очень болезненно.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Февраль 13, 2014, 14:48
А как я написал выше пойдёт?
Ну как в старом мультике "а так сойдет?"  :). Ну вот зачем создавать еще один поток, что Вы хотели этим выразить? Если ничего, то зачем говнокодить?

Я валю всё в main.cpp, потому что сервер принимает только один файл - main.cpp.

Как мне не писать in.close() 3 раза. Покажите, пожалуйста:
А я не о файле, а о ф-ции main. Она должна выглядеть примерно так

Код
C++ (Qt)
int main(int argc, char** argv)
{
 std::vector <int> vec;
 
// получаем имя файла из командной строки, если там пусто, то input.txt (по умолчанию)
 std::string iFileName = GetInName(argc, argv);
 
// читаем данные из файла
 int err = ReadData(iFileName, vec);
 if (err) return ShowError(err, &iFileName);
 
// выполняем содержательную часть
 int result;
 err = sumOfMaxAndMin(arr, &result);
 if (err) return ShowError(err, &iFileName);
 
// записываем выходной файл
 std::string oFileName = GetOutName(argc, argv);
 err = WriteResult(oFileName, result);
 if (err) return ShowError(err, &oFileName);
 
 return 0;
}
Теперь начинаем парить ReadData и др ф-ции, там тоже выделяем ф-ции, их будет уже меньше - и так до тех пор пока не напишем все. Когда Вы все это сделаете (аккуратно, с любовью а не абы как) - Вы с удивлением обнаружите что in.close() не понадобился ни разу  :)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 13, 2014, 15:03
Профи пишут Unit-тесты с использованием QTest и QTestLib http://qt-project.org/doc/qt-4.8/qtestlib-manual.html#qtestlib (http://qt-project.org/doc/qt-4.8/qtestlib-manual.html#qtestlib)
Хотя, чистым CPPUnit тоже не плохо http://sourceforge.net/apps/mediawiki/cppunit/index.php?title=Main_Page (http://sourceforge.net/apps/mediawiki/cppunit/index.php?title=Main_Page)

Я так понимаю ты пытаешься сразу по концепции Extrem программирования писать? Только без знаний разработки архитектуры это будет очень болезненно.

Я только начал разбираться, вот инсткрукции даже написал, для таких же новичков, как и я:
- QTestLib: http://www.prog.org.ru/topic_26413_0.html
- CppUnit: http://notes.orgfree.com/tdd_cpp.php

CppUnit, к сожалению, уже не поддерживается много лет. Он безнадёжно устарел. Я его буду использовать только для решения задач. Ибо с ним удобно работать в среде NetBeans (так как поддержка CppUnit встроена в NetBeans, так же NetBeans поддерживает Qt). Да и задачи удобно протестить, а потом уже сдавать на проверку серверу. Других фреймворков я ещё не рассматривал. Их очень много, но никто не рассказывает, какой лучше :(

Почему QTestLib настолько беден по сравнению с googletest (судя по отзывам на форумах)? Почему в нём нет поддержки mock-объектов?

Я в любом случае продолжу изучение QTestLib, но мне нужна более мощная альтернатива.

Стоит ли изучать googletest? Так ли он популярен среди профи? И популярен ли он среди Qt-разработчиков?

Mock-объекты: http://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D1%87%D0%B5%D1%80%D0%B5%D0%B7_%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5#Fake-.2C_mock-.D0.BE.D0.B1.D1.8A.D0.B5.D0.BA.D1.82.D1.8B_.D0.B8_.D0.B8.D0.BD.D1.82.D0.B5.D0.B3.D1.80.D0.B0.D1.86.D0.B8.D0.BE.D0.BD.D0.BD.D1.8B.D0.B5_.D1.82.D0.B5.D1.81.D1.82.D1.8B


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 13, 2014, 15:08
А как я написал выше пойдёт?
Ну как в старом мультике "а так сойдет?"  :). Ну вот зачем создавать еще один поток, что Вы хотели этим выразить? Если ничего, то зачем говнокодить?

Лишь преобразование из строки в целое. Что в этом плохого?


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Февраль 13, 2014, 15:34
Лишь преобразование из строки в целое. Что в этом плохого?
Плохо (и очень) что Вы не стремитесь к совершенству своего кода. Насколько оно достижимо - то философский вопрос. Но если нет самого стремления - никакая беготня по серверам, гитам (и где угодно) не поможет.

Все, умолкаю


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Hrundel от Февраль 13, 2014, 15:41
Почему QTestLib настолько беден по сравнению с googletest (судя по отзывам на форумах)? Почему в нём нет поддержки mock-объектов?

Потому,  что это все нафиг не нужно. Особенно если ты пишешь программы в которых меньше 20.000 строк кода.
Еще раз повторюсь - без знаний разработки архитектуры все это сотрясание воздуха. С грамматно разработанной архитектурой тебе не понадобятся никакие навороченые тесты. Все тестовые фреймворки направлены на гиганские проекты.  Поставь лучше перед собой задачу - создания оптимальной архитектуры программы, изучи UML, научись качественно работать с классами, пиши как можно проще и понятнее - тогда тебе Unit-тесты будут очень редко необходимы - только для сложных структур данных.
На мой взгляд ты двигаешься не с того конца. Не надо заниматься тем, чем занимаеться группа из 20 человек программистов.

Приведу пример:

Парень из моего потока пришел на практику. Там уже год отработал паренек простым заштатным программистом. Год пытался написать программу - безрезультатно. Этот мой однокурсник изучил задачу - за месяц разработал архитектуру, два месяца писал, сдал досрочно полностью рабочий релиз!

А вообще, я присоеденяюсь к Igors - делай что хочешь!


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Old от Февраль 13, 2014, 15:49
2 8Observer8
Задавайте меньше вопрос и больше думайте/пробуйте сами, читайте, разбирайтесь. Все приходит с опытом, которого у вас немного.
Будет больше опыта/знаний, и код будет лучше и писаться будет проще. Не спешите, все будет. ;)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: kambala от Февраль 13, 2014, 15:54
...иначе станешь Spark (http://www.prog.org.ru/topic_25332_0.html) №2


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 13, 2014, 15:58
Лишь преобразование из строки в целое. Что в этом плохого?
Плохо (и очень) что Вы не стремитесь к совершенству своего кода. Насколько оно достижимо - то философский вопрос. Но если нет самого стремления - никакая беготня по серверам, гитам (и где угодно) не поможет.

Все, умолкаю

Я не настаиваю, что это хорошо. Я понял, что это плохо, но не понял почему? Я помню о программе, я её сейчас доделаю.

2 8Observer8
Задавайте меньше вопрос и больше думайте/пробуйте сами, читайте, разбирайтесь. Все приходит с опытом, которого у вас немного.
Будет больше опыта/знаний, и код будет лучше и писаться будет проще. Не спешите, все будет. ;)

Спасибо! Если у меня не получится стать младшим разработчиком в нормальной фирме, в которую я хочу (через две недели), то я реально труп  :D


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Hrundel от Февраль 13, 2014, 16:00
Спасибо! Если у меня не получится стать младшим разработчиком в нормальной фирме, в которую я хочу (через две недели), то я реально труп  :D

Дык вот откуда берется отстойный софт!


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 13, 2014, 16:07
Спасибо! Если у меня не получится стать младшим разработчиком в нормальной фирме, в которую я хочу (через две недели), то я реально труп  :D

Дык вот откуда берется отстойный софт!

Я считаю, что ещё мне рановато в петлю лезть. Люди говорят, что ещё можно побороться.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 13, 2014, 16:32
Почему QTestLib настолько беден по сравнению с googletest (судя по отзывам на форумах)? Почему в нём нет поддержки mock-объектов?

Потому,  что это все нафиг не нужно. Особенно если ты пишешь программы в которых меньше 20.000 строк кода.
Еще раз повторюсь - без знаний разработки архитектуры все это сотрясание воздуха. С грамматно разработанной архитектурой тебе не понадобятся никакие навороченые тесты. Все тестовые фреймворки направлены на гиганские проекты.  Поставь лучше перед собой задачу - создания оптимальной архитектуры программы, изучи UML, научись качественно работать с классами, пиши как можно проще и понятнее - тогда тебе Unit-тесты будут очень редко необходимы - только для сложных структур данных.
На мой взгляд ты двигаешься не с того конца. Не надо заниматься тем, чем занимаеться группа из 20 человек программистов.

Согласен, с QTestLib, googletest я перегнул. Сейчас мне не нужно тратить на это время. С тем, что Вы мне посоветовали осваивать, я согласен. Нужно расставлять приоритеты.

То что я вначале писал про CppUnit, мне просто удобно так писать функцию, которая решает задачу. Я смотрю какие входные данные для задачи и какое будет соответствие на выходе. С помощью тестов описываю все "щекотливые" ситуации, чтобы не забыть их учесть в функции и чтобы сервер меня не обломал. Для задач это очень удобно, вот я и описал это. Думал, что кому-то пригодится. Хотя... тот ресурс с задачами для школьников и студентов, а тут уже рабочии люди сидят. Этого я не учёл. Поэтому это глупо получилось.

Я решил с того ресурса с задачами 35 штук (правда из раздела "Начинающие")

Разве решение задач не учит программированию?


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Old от Февраль 13, 2014, 16:44
Разве решение задач не учит программированию?
Скажу так, учит основам.
Мое мнение, учится нужно на реальной большой задаче. Придумайте себе задачу, в которой будет все что вы хотите освоить и решайте ее, тогда вы сразу будете учится объединять решение маленьких подзадач для решения большой, сможете представлять систему целиком, продумывать ее архитектуру.
Решая только маленькие задачи вы это пропускаете.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Hrundel от Февраль 13, 2014, 16:49
Разве решение задач не учит программированию?

Вот тут-то собака и порылась!!! Ты программированию учишься или разработке? Это разные вещи. Тестирование - это одна из стадий разработки занимающая большую ее часть. Ты хочешь стать младшим разработчиком, но понятия не имеешь о разработке! Учи UML и пытайся вникнуть в основы архитектуры.

Мое мнение, учится нужно на реальной большой задаче.

Полностью согласен с Old!!!


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Bepec от Февраль 13, 2014, 16:54
Я б посоветовал сразу идти в фирму младшим разработчиком на маленькую ЗП. Обычно берут, так как всегда есть задачка, которая не столь важна, а рук не хватает :)

Там из тебя выбьют дурь про тестирование и прочее. Дадут реальную з/п, если будет хороший начальник, ещё и подъучит тебя нормальной разработке.

PS начинай писать программу с алгоритма работы :D


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 13, 2014, 17:13
Разве решение задач не учит программированию?
Скажу так, учит основам.
Мое мнение, учится нужно на реальной большой задаче. Придумайте себе задачу, в которой будет все что вы хотите освоить и решайте ее, тогда вы сразу будете учится объединять решение маленьких подзадач для решения большой, сможете представлять систему целиком, продумывать ее архитектуру.
Решая только маленькие задачи вы это пропускаете.

Спасибо большое! Я буду тратить минимум времени в день не решение задач. Мне приходила в голову такая идея: начать писать проект, который будет включать в себя по максимуму из того, что мне нужно освоить. Я начну такую тему, как продумаю проект. Хочу чтобы меня направляли. Одному мне очень трудно.

Всем спасибо! Здесь буду писать вопросы по задачкам. Прошу всех помогать, кто как может. Igors, мне подкинул идею (и код), как организовать код в main.cpp. Выложу попозже.

Я понял, что во-порвых мне нужно учиться основам программирования по задачкам, а во-вторых, придумывать и реализовывать большой проект, архитектуру, которого описывать с помощью UML.

Вопросы по задачкам я буду задавать в этой теме, а проект писать в новой.

Я б посоветовал сразу идти в фирму младшим разработчиком на маленькую ЗП. Обычно берут, так как всегда есть задачка, которая не столь важна, а рук не хватает :)

Там из тебя выбьют дурь про тестирование и прочее. Дадут реальную з/п, если будет хороший начальник, ещё и подъучит тебя нормальной разработке.

PS начинай писать программу с алгоритма работы :D

На маленькую зарплату и хочу.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Bepec от Февраль 13, 2014, 17:31
Я б рекомендовал забыть о том, что пишут об "быстром" программировании.

Чтобы ускорять разработку - нужно уметь разрабатывать, строить архитектуру :)

PS За то время, когда вы напишите тесты для  программки в 5-7к строк я напишу программу и оттестирую её. 

PPS кто-то из светил программирования на С++ даже написал статью - как я погнался за "красивым" кодом и потерял в эффективности.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 13, 2014, 17:48
Я б рекомендовал забыть о том, что пишут об "быстром" программировании.
Чтобы ускорять разработку - нужно уметь разрабатывать, строить архитектуру :)
PS За то время, когда вы напишите тесты для  программки в 5-7к строк я напишу программу и оттестирую её. 
PPS кто-то из светил программирования на С++ даже написал статью - как я погнался за "красивым" кодом и потерял в эффективности.

Я уже писал, что лично мне удобно писать сначала тесты, а потом код, так как если я знаю, что на входе и что ожидается на выходе, то могу с помощью тестов быстренько написать это соответствие. Всего лишь для острых моментов, это занимает минимум времени (именно, для задачек). Я говорю именно о функции, у которой есть вход и выход, и которая решает задачу. На практике может это и не нужно, так как только в задачах используются простые типы данных, а на практике функции, как правило, принимают объекты "непростых" типов. Ещё раз повторюсь, что мне так удобно решать задачки. Если я открою решение и захочу его улучшить, то я не боюсь, что-то испортить, так как после исправлений, я сразу запускаю тесты.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 13, 2014, 17:50
Я сдал вот эту задачу: http://acmp.ru/?main=task&id_task=50

Она правильно решена, но я бы хотел услышать вашу критику кода, подхода к решению и т.д.

Я буду переписывать содержимое main.cpp, как посоветовал Igors в ответе #16. Меня сейчас интересует, то как можно улучшить и упростить код (который в функциях, а не в main). А может всё нормально?

Код:
#include <iostream>
#include <fstream>
#include <string>
#include <set>
using namespace std;

string shiftStringToLeft(const string &inStr) {
    string str = inStr;
    if (!str.empty()) {
        char c = str[0];
        str = str.substr(1, str.size() - 1);
        str.push_back(c);
    }
    return str;
}

void numberOfDifferentPermutations(const string &inStr, set<string> &outArray) {
    int n = inStr.size();
    string str = inStr;
    for (int i = 0; i < n; ++i) {
        outArray.insert(str);
        str = shiftStringToLeft(str);
    }
}

int amountOfSubstrings(string inStr, string substr) {
    int nfound = 0;
    size_t found = inStr.find(substr);
    while (found != string::npos) {
        nfound++;
        found = inStr.find(substr, found+1);
    }
    return nfound;
}

int nCyclicalSubstrings(string inStr, string substr) {
    set<string> outArray;
    numberOfDifferentPermutations(substr, outArray);
    set<string>::const_iterator it = outArray.begin();

    int nfound = 0;
    int size = outArray.size();
    for (int i = 0; i < size; ++i) {
        nfound += amountOfSubstrings(inStr, *it);
        it++;
    }

    return nfound;
}

int main(int argc, char** argv) {
    string inFileName = "input.txt";
    ifstream in;
    in.open(inFileName.c_str());
    if (!in.is_open()) {
        cerr << "Error: could not open the file " << inFileName.c_str() << endl;
        return 1;
    }

    string outFileName = "output.txt";
    ofstream out;
    out.open(outFileName.c_str());
    if (!out.is_open()) {
        cerr << "Error: could not open the file " << outFileName.c_str() << endl;
        in.close();
        return 1;
    }

    string str;
    string substr;
    if (in >> str >> substr) {
        int result = nCyclicalSubstrings(str, substr);
        out << result << endl;
    } else {
        cerr << "Error: incorrect data in the file " << inFileName.c_str() << endl;
        in.close();
        out.close();
        return 1;
    }

    in.close();
    out.close();
    return 0;
}


Название: Re: Тренировка навыков быстрого программирования
Отправлено: kambala от Февраль 13, 2014, 18:32
писать тесты — нормально, но не когда ты только обучаешься программированию/разработке. имхо


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Bepec от Февраль 13, 2014, 19:09
Я не спорю, выглядит ваш код очень умно и оригинально, но нихрена не понятно :D Особенно в функциях (моё мнение, конечно же)
Моя версия задачи.

PS нафига простейшую операцию из 13!!! строк разбивать на 4 функции с какими то передаточными аргументами - я этого не могу понять просто :D

PPS был у меня коллега с такой же проблемой. Пытался каждое действие разбивать на функции. Т.е. сесть на стул это
  • Проверить есть ли стул
  • Проверить поддерживается ли тип стула
  • Попытаться сесть
  • Проверить удобно ли сидеть
  • Проверить можно ли пододвинуть стул
  • Пододвинуть стул
В результате вместо взял стул, переставил, сел, пододвинул в 20 строк у него получался монстр с фабрикой для пары классов. Избыточно это.

Код:
#include <fstream>
#include <conio.h>
#include <iostream>

using namespace std;
int main(int argc, char *argv[])
{
ifstream input("input.txt");
if (!input)
{
exit(1);
}

string source ;
std::getline(input, source);
string findString;
std::getline(input, findString);
input.close();

if (findString.size() > source.size())
{
exit(1);
}

string recursiveString = findString;
int result = 0;
for (int i = 0;i != findString.size(); i++)
{
recursiveString.insert(0, 1, recursiveString[recursiveString.size()-1]);
recursiveString.erase(recursiveString.size()-1, 1);
int pos = -recursiveString.size();
while(true)
{
pos = source.find(recursiveString, pos+recursiveString.size());
if (pos!= -1)
result++;
else
break;
}
}
ofstream out("OUTPUT.txt");
if (out)
{
out << result;
}
exit(0);
}


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Hrundel от Февраль 13, 2014, 20:09
Если у тебя правда такое безумное желание стать младшим разрабом - вот тебе простейшая задача:

Напиши программу визуализирующую ненаправленые взвешанные графы до 50 узлов.

Условия к решению обычно прилагаются, поэтому даю условия:

1. Разработать структуру данных с вожмозностью быстрого перехода от узла к узлу по кантам.
2. Реализовать трассировку от любого узла.
3. Реализовать ввод данных из файла (парсинг) любого наиболее удовлетворяющего задаче формата файла.

Всё!

Люди скажите, для младшего разраба покатит?


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Bepec от Февраль 13, 2014, 20:14
Ххы... ты меня расстроил. Я не младший разраб  :'(


Название: Re: Тренировка навыков быстрого программирования
Отправлено: OKTA от Февраль 13, 2014, 20:16
Забыли добавить последнее условие - нафига это вообще надо, чтобы знать, что делаешь что-то полезное  ;D


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Hrundel от Февраль 13, 2014, 20:17
Ну, Верес, про тебя мы знаем, что ты не младший разраб  ;D Но ты, зато, продвинутый программер в Qt. Знания у тебя широкие.

Забыли добавить последнее условие - нафига это вообще надо, чтобы знать, что делаешь что-то полезное  ;D

Да, это хорошо сказано :D


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Bepec от Февраль 14, 2014, 00:24
Я вот ещё заметил что по стилю кода ТС ближе к C#, чем к С++ :)

to Hrundel Эммм... Какая ещё информация на меня у вас есть?


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 14, 2014, 09:09
Я не спорю, выглядит ваш код очень умно и оригинально, но нихрена не понятно :D Особенно в функциях (моё мнение, конечно же)
Моя версия задачи.

PS нафига простейшую операцию из 13!!! строк разбивать на 4 функции с какими то передаточными аргументами - я этого не могу понять просто :D

PPS был у меня коллега с такой же проблемой. Пытался каждое действие разбивать на функции. Т.е. сесть на стул это
  • Проверить есть ли стул
  • Проверить поддерживается ли тип стула
  • Попытаться сесть
  • Проверить удобно ли сидеть
  • Проверить можно ли пододвинуть стул
  • Пододвинуть стул
В результате вместо взял стул, переставил, сел, пододвинул в 20 строк у него получался монстр с фабрикой для пары классов. Избыточно это.

Код:
#include <fstream>
#include <conio.h>
#include <iostream>

using namespace std;
int main(int argc, char *argv[])
{
ifstream input("input.txt");
if (!input)
{
exit(1);
}

string source ;
std::getline(input, source);
string findString;
std::getline(input, findString);
input.close();

if (findString.size() > source.size())
{
exit(1);
}

string recursiveString = findString;
int result = 0;
for (int i = 0;i != findString.size(); i++)
{
recursiveString.insert(0, 1, recursiveString[recursiveString.size()-1]);
recursiveString.erase(recursiveString.size()-1, 1);
int pos = -recursiveString.size();
while(true)
{
pos = source.find(recursiveString, pos+recursiveString.size());
if (pos!= -1)
result++;
else
break;
}
}
ofstream out("OUTPUT.txt");
if (out)
{
out << result;
}
exit(0);
}

Спасибо за попытку, но Ваша программа неверно работает. Её нужно сдать внизу страницы: http://acmp.ru/?main=task&id_task=50

С замечаниями по поводу архитектуры - полностью согласен. Я нагородил кучу функций. Буду улучшать. Как говорится - рефакторить.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 14, 2014, 10:00
Я вот ещё заметил что по стилю кода ТС ближе к C#, чем к С++ :)

Не знаю, что именно Вас сподвигло на такие размышления, но действительно сейчас я параллельно изучаю C#, потому что моя подруга учится на втором курсе и они сейчас начали  в этом семестре проходить C#. Мы вместе делаем лабораторки. Точнее она делает, а я ей помогаю. Она большая молодец. Очень старается. В нашем проекте, который мы сейчас пишем, пользователь вводит лекарства (название, цену, серийный номер, тип). Он может отсортировать массив лекарств по заданому полю и выводить на экран список лекарств. Я ей лишь помог реализовать сортировку и немного улучшить код. Если кому будет интересна сортировка объектов по заданому полю (или есть предложения по улучшению архитектуры), то вот наша текущая работа (предупреждаю, что это черновая работа и там ещё много чего нужно улучшать) http://codepad.org/n6jHdTjO

У меня, кстати, появилась идея реализовывать тоже cамое на Qt (для этого будет другая тема). Тут есть и наследование и какое-то уже "полезное" приложение с сортировой по полю массива объектов. Вот бы ещё базу данных прикрутить... SQLite например, я о ней немного читал и пробовал работать с ней (сохранять и читать строки таблицы, редактировать таблицу). Хотя в списке вопросов для подготовки нет баз данных. Ну хотя бы без базы данных, а в бинарный файл сохранять лекарства. А то может только время потрачу на БД, а в работе это не пригодится.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Bepec от Февраль 14, 2014, 10:42
По секрету - именно в стиле C# работа со строками у вас.

PS не могу сказать в чем причина "неприятия" системы :) Вроде условию удовлетворяет.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 14, 2014, 11:31
PS не могу сказать в чем причина "неприятия" системы :) Вроде условию удовлетворяет.

Я доберусь на Вашей программы :) Сейчас свою улучшаю, как написал Igors.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Hrundel от Февраль 14, 2014, 13:03
Так я не понял, ты решил проигнорировать поставленную задачу? Или ты надеешься, что тебе на работе таких заданий давать не будут? Думаешь что будешь решать упражнения как у твоей подруги на втором семестре?
Это задание как раз на две недели. Я это делал на пятом семестре. За две недели реально выполняется.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 14, 2014, 15:11
Напиши программу визуализирующую ненаправленые взвешанные графы до 50 узлов.

Условия к решению обычно прилагаются, поэтому даю условия:

1. Разработать структуру данных с вожмозностью быстрого перехода от узла к узлу по кантам.
2. Реализовать трассировку от любого узла.
3. Реализовать ввод данных из файла (парсинг) любого наиболее удовлетворяющего задаче формата файла.

Можете привести пример, где на практике это будет нужно? Пример из Вашей практики, так сказать.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 14, 2014, 15:16
Код
C++ (Qt)
int main(int argc, char** argv)
{
 std::vector <int> vec;
 
// получаем имя файла из командной строки, если там пусто, то input.txt (по умолчанию)
 std::string iFileName = GetInName(argc, argv);
 
// читаем данные из файла
 int err = ReadData(iFileName, vec);
 if (err) return ShowError(err, &iFileName);
 
// выполняем содержательную часть
 int result;
 err = sumOfMaxAndMin(arr, &result);
 if (err) return ShowError(err, &iFileName);
 
// записываем выходной файл
 std::string oFileName = GetOutName(argc, argv);
 err = WriteResult(oFileName, result);
 if (err) return ShowError(err, &oFileName);
 
 return 0;
}
Теперь начинаем парить ReadData и др ф-ции, там тоже выделяем ф-ции, их будет уже меньше - и так до тех пор пока не напишем все. Когда Вы все это сделаете (аккуратно, с любовью а не абы как) - Вы с удивлением обнаружите что in.close() не понадобился ни разу  :)

Igors, при реализации Вашей идеи я испытал большую радость! Спасибо Вам огромное! Теперь мне самому стало легче и приятнее читать свой код.

close() вызываю один раз для входного файла и один раз для выходного (внутри функций чтения и записи).

Код
C++ (Qt)
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
 
int readData(const std::string& iFileName, std::vector<int>& arr);
int writeResult(const std::string& oFileName, int &result);
int showError(int err, const std::string& fileName);
int sumOfMaxAndMin(const std::vector<int>& arr, int& result);
 
int main(int argc, char** argv) {
 
   // Массив для хранения входных данных
   std::vector <int> arr;
 
   // Имя входного файла
   std::string iFileName = "input.txt";
 
   // Читаем данные из файла
   int err = readData(iFileName, arr);
   if (err) return showError(err, iFileName);
 
   // Выполняем содержательную часть
   int result;
   err = sumOfMaxAndMin(arr, result);
   if (err) return showError(err, iFileName);
 
   // Записываем выходной файл
   std::string oFileName = "output.txt";
   err = writeResult(oFileName, result);
   if (err) return showError(err, oFileName);
 
   return 0;
}
 
/**
* Читаем данные из файла
*
* @param iFileName Имя входного файла
* @param vec Массив, в который будут считаны входные данные
* @return Код ошибки: 0 - если ошибок нет
*                     1 - если файл не удалось открыть
*                     2 - если в файле некорректные данные
*/

int readData(const std::string& iFileName, std::vector<int>& arr) {
 
   // Открываем файл с входными данными
   std::ifstream in;
   in.open(iFileName.c_str());
   if (!in.is_open()) {
       return 1;
   }
 
   // Читаем данные из файла
   int value, err = 0;
   std::string input;
   while (in >> input) {
       if (std::stringstream(input) >> value) {
           arr.push_back(value);
       } else {
           err = 2;
           break;
       }
   }
 
   // Закрываем файл и возвращаем код ошибки
   in.close();
   return err;
}
 
/**
* Записываем результат выходной в файл
*
* @param iFileName Имя выходного файла
* @param vec Массив, который нужно записать в файл
* @return Код ошибки: 0 - если ошибок нет
*                     1 - если файл не удалось открыть
*                     2 - если в файле не удалось записать
*/

int writeResult(const std::string& oFileName, int& result) {
 
   // Открываем файл для записи
   std::ofstream out;
   out.open(oFileName.c_str());
   if (!out.is_open()) {
       return 1;
   }
 
   // Записываем данные в файл
   out << result << std::endl;
 
   // Закрываем файл и возвращаем код ошибки
   out.close();
   return 0;
}
 
/**
* Выводит текст с ошибкой на экран
*
* @param err Код ошибки
* @param iFileName Имя файла, в котором произошла ошибка
*/

int showError(int err, const std::string& fileName) {
   switch (err) {
       case 1:
           std::cerr << "Error: could not open the file " << fileName.c_str() << std::endl;
           break;
       case 2:
           std::cerr << "Error: incorrect data in the file " << fileName.c_str() << std::endl;
           break;
       default:
           std::cerr << "Error code: " << err << "; file name: " << fileName.c_str() << std::endl;
           break;
   }
 
   return err;
}
 
/**
* Сумма максимума из чисел с чётными номерами и
* минимума из чисел с нечётными номерами
*
* @param arr Массив целых чисел
* @param result Сумма максимума из чисел с чётными номерами и
* минимума из чисел с нечётными номерами
* @return Код ошибки
*/

int sumOfMaxAndMin(const std::vector<int>& arr, int& result) {
 
   // Массивы для чисел с чётным и нечётными номерами
   std::vector<int> odd;
   std::vector<int> even;
 
   // Размер входного массива
   std::size_t size = arr.size();
 
   // Сортируем на чётный и нечётные массивы
   for (int i = 0; i < size; ++i) {
       if ((i+1)%2 != 0) {
           odd.push_back(arr[i]);
       } else {
           even.push_back(arr[i]);
       }
   }
 
   // Находим минимальный среди нечётных
   int min = 0;
   if (odd.size() > 0) {
       min = *std::min_element(odd.begin(), odd.end());
   }
 
   // Находим максимальный среди чётных
   int max = 0;
   if (even.size() > 0) {
       max = *std::max_element(even.begin(), even.end());
   }
 
   // Вычисляем результат
   result = max + min;
 
   // Возвращаем код ошибки
   return 0;
}
 

P.S. Это решение вот этой задачи: http://acmp.ru/index.asp?main=task&id_task=272
Время: 0,208 сек
Память: 1064 Кб



Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Февраль 14, 2014, 15:25
Я сдал вот эту задачу: http://acmp.ru/?main=task&id_task=50

Она правильно решена, но я бы хотел услышать вашу критику кода, подхода к решению и т.д.

Я буду переписывать содержимое main.cpp, как посоветовал Igors в ответе #16. Меня сейчас интересует, то как можно улучшить и упростить код (который в функциях, а не в main). А может всё нормально?
Алгоритм (содержательная часть). Пока нет понятия что все чего-то стоит, весит. Использован std::set - зачем? Ведь ассоциативный контейнер - удовольствие дорогое. И зачем здесь вообще нужен контейнер? Рассмотрим циклический сдвиг

- abcd  // было
- dabc  // стало

Кто же мешает найти сначала "d" и затем проверить не заканчивается ли найденное на "аbc"? Этот алгоритм использует 0 (ноль) памяти, и по меньшей мере на порядок быстрее.

А тут вообще распустился
Цитировать
int amountOfSubstrings(string inStr, string substr) {
Какого подавать данные по значению вызывая их копирование? Здесь не Qt где имплисит шара попку подмоет.

Относитесь к задаче более вдумчиво и аккуратно (чему кстати отлично учит язык С). Бездумно ляпать контейнерами - ума много не надо.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Old от Февраль 14, 2014, 15:29
Теперь мне самому стало легче и приятнее читать свой код.
Читать может и стало приятней, только вот использовать такие функции повторно вряд ли получиться.
Одна из целей выделения кода в отдельную функцию - это повторное использование этого кода в других местах программы.
Давайте посмотрим на прототипы ваших функций:
int readData(const std::string& iFileName, std::vector<int>& arr);
int writeResult(const std::string& oFileName, int &result);

и ответим на вопрос, а смогу ли я использовать эти функции для загрузки/сохранения данных из другого источника, например, сети, середины файла или текстового буфера в крайнем случае? Нет.

Теперь давайте вспомним про потоки (stream) и для чего они вообще в C++ были придуманы. Как раз для того, что бы функции могла работать с разными источниками данных одним и тем же способом. И если изменить реализацию функций на следующий, то функции больше не придется переписывать, достаточно будет давать на вход нужный поток.
int readData( istream &is, std::vector<int>& arr );
int writeResult( ostream &os, int result );



Название: Re: Тренировка навыков быстрого программирования
Отправлено: Bepec от Февраль 14, 2014, 16:06
А меня больше интересует что в моём коде неправильно ;D


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Февраль 14, 2014, 16:10
И если изменить реализацию функций на следующий, то функции больше не придется переписывать, достаточно будет давать на вход нужный поток.
int readData( istream &is, std::vector<int>& arr );
int writeResult( ostream &os, int result );

Это имеет свои резоны, но в повторном использовании можно усомниться. Напр выглядит более вероятно что изменится не тип ввода (что-то будет вместо файла), а тип данных (что-то др вместо вектора int). С др стороны есть работа которую можно поручить readData (string) - хоть проверить открытие файла. Ну никто не мешает "декомпозировать" ее на более мелкие ф-ции и readData (stream) будет одной из них.

В любом случае главное - выделять/разделять I/O, UI и расчетную части, а не валить все в кучу которая развалится при первом же изменении.

Да, и константы/песики надо понаводить (enum), а то 1, 2. 3 потом хрен найдешь



Название: Re: Тренировка навыков быстрого программирования
Отправлено: Old от Февраль 14, 2014, 16:31
С др стороны есть работа которую можно поручить readData (string) - хоть проверить открытие файла.
Проверять открытие файла в функции readData? Вам нравится это название? А поручить ей можно еще много чего, название серьезное. :)

Ну никто не мешает "декомпозировать" ее на более мелкие ф-ции и readData (stream) будет одной из них.
Вот про это и речь, я предлагаю 8Observer8 вначале подумать, что бы не нужно было проводить потом "декомпозиции".


Название: Re: Тренировка навыков быстрого программирования
Отправлено: BuRn от Февраль 14, 2014, 18:51
[ОФТОП]
Мне кажется, или человек занимается какой-то хер...ей простите ? Из диалогов выше, я так понял, что чел на форуме решил обучиться программированию на задачках уровня 1-2 курс универа.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Nidxogg от Февраль 14, 2014, 18:56
Для понимания есть задачки получше?


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Февраль 14, 2014, 20:46
Проверять открытие файла в функции readData? Вам нравится это название? А поручить ей можно еще много чего, название серьезное. :)
Название вполне нравится, только "R" (большое) лучше, ну это дело вкуса. Я четко вижу/уверен что ввод данных надо выделить, размазывать его в main явно плохо.

Вот про это и речь, я предлагаю 8Observer8 вначале подумать, что бы не нужно было проводить потом "декомпозиции".
То палка о двух концах. Дальше возникнет идея сделать ввод универсальным, перекрыть оператор >>, пойдут в ход злополучные темплейты и.т.д. Стоит ли так увлекаться? Мое мнение - нет, пока достаточно локализовать ввод, а дальше посмотрим.

[ОФТОП]
Мне кажется, или человек занимается какой-то хер...ей простите ? Из диалогов выше, я так понял, что чел на форуме решил обучиться программированию на задачках уровня 1-2 курс универа.
Не то чтобы я приветствую этот метод - но вынужден признать что он "не хуже остальных". Многое зависит от того как подходить к задаче (пусть простой). Препод не будет вдаваться в концепции/идеологию, нет возможности (а часто и желания), ему надо чтобы дите хоть что-то освоило и не оборзело. А на форуме бьют (что вполне норм) - ну пока наш герой стойко это выдерживает  :)

А меня больше интересует что в моём коде неправильно ;D
Вы лучше расскажите как это Вы сократили себе объем работы в неск раз избавившись от всякого утомительного контроля ошибок? Правильно ли я понимаю что это "непринципиально", "никак не влияет на суть" и.т.п. ?   :)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Old от Февраль 14, 2014, 20:56
Я четко вижу/уверен что ввод данных надо выделить, размазывать его в main явно плохо.
Так не размазывайте. Никто же не заставляет. :)

Мое мнение - нет.
Ок.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Bepec от Февраль 14, 2014, 21:11
Igors какие ошибки? Зачем? У программы есть чёткие условия. Они не размазаны, как ваши задачи. Запуск, чтение из input, вывод в output. Человека нет в этой схеме.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Февраль 14, 2014, 21:22
Igors какие ошибки? Зачем?
Признаюсь - Вы меня поставили/загнали в тупик. Единственный ответ что приходит в голову типа "ну а совесть есть? Ведь так юзверь не сможет работать" - но это звучит как-то напыщенно, старомодно, неудобно и говорить  :'(


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 14, 2014, 21:26
Спасибо, ребят! Много классной инфы. Я завтра всё проработаю.

Вот функция из предыдущего сообщения. Что о ней скажете? Не скупитесь в критике

Код
/**
* Сумма максимума из чисел с чётными номерами и
* минимума из чисел с нечётными номерами
*
* @param arr Массив целых чисел
* @param result Сумма максимума из чисел с чётными номерами и
* минимума из чисел с нечётными номерами
* @return Код ошибки
*/
int sumOfMaxAndMin(const std::vector<int>& arr, int& result) {
 
   // Массивы для чисел с чётным и нечётными номерами
   std::vector<int> odd;
   std::vector<int> even;
 
   // Размер входного массива
   std::size_t size = arr.size();
 
   // Сортируем на чётный и нечётные массивы
   for (int i = 0; i < size; ++i) {
       if ((i+1)%2 != 0) {
           odd.push_back(arr[i]);
       } else {
           even.push_back(arr[i]);
       }
   }
 
   // Находим минимальный среди нечётных
   int min = 0;
   if (odd.size() > 0) {
       min = *std::min_element(odd.begin(), odd.end());
   }
 
   // Находим максимальный среди чётных
   int max = 0;
   if (even.size() > 0) {
       max = *std::max_element(even.begin(), even.end());
   }
 
   // Вычисляем результат
   result = max + min;
 
   // Возвращаем код ошибки
   return 0;
}

Вот про это и речь, я предлагаю 8Observer8 вначале подумать, что бы не нужно было проводить потом "декомпозиции".
То палка о двух концах. Дальше возникнет идея сделать ввод универсальным, перекрыть оператор >>, пойдут в ход злополучные темплейты и.т.д. Стоит ли так увлекаться? Мое мнение - нет, пока достаточно локализовать ввод, а дальше посмотрим.

Это очень интересная тема (оператор >>, темплейты). Замечания по алгоритмам к задачам устраню. А тем временем буду думать об улучшении функциий (чтение, запись), чтобы сделать их универсальными. Дайте, пожалуйста, задание, куда двигаться дальше по улучшению.

Цитировать
Да, и константы/песики надо понаводить (enum), а то 1, 2. 3 потом хрен найдешь
Что такое песики?


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Hrundel от Февраль 14, 2014, 21:40
Можете привести пример, где на практике это будет нужно? Пример из Вашей практики, так сказать.

Что, неужели не хватает фантазии? Элементарный пример - компьютерные сети и скорость соединений. Например выбор не самой короткой, а самой быстрой маршрутизации.
Да и вообще, с моей точки зрения,  если тебе приходится объяснять значимость графов в информатике - то лучше забей на это дело! Или иди переучиваться.
А почему тебя твоя профессия не устраивает? Зачем делать то, о чем ты не имешь представления?


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Hrundel от Февраль 14, 2014, 21:44
[ОФТОП]
Мне кажется, или человек занимается какой-то хер...ей простите ? Из диалогов выше, я так понял, что чел на форуме решил обучиться программированию на задачках уровня 1-2 курс универа.

[ОФТОП]
Самое правильное замечание. Но еще ужастнее, что он хочет занять чье-то место и продуцировать слив.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Old от Февраль 14, 2014, 21:46
Вот функция из предыдущего сообщения. Что о ней скажете? Не скупитесь в критике
Нет нужды перекладывать числа из исходного вектора в векторы odd и even, достаточно использовать два int для хранения min и max.
Для чего этот цирк с result, какую ошибку вы ждете от этой функции?


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Февраль 14, 2014, 22:02
Вот функция из предыдущего сообщения. Что о ней скажете? Не скупитесь в критике
Та же ошибка - использование контейнеров без всякой на то необходимости. Вы видите что в std есть для этого тулзы - и применяете их, не подумав что есть решение проще, короче, лучше. Впрочем эта ошибка очень популярна. Почему бы просто не пробежаться по массиву "в стиле начинающего" на ходу определяя чет/нечет?


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 14, 2014, 22:10
Переделал. Сейчас как? Нормально?

Код
C++ (Qt)
/**
* Сумма максимума из чисел с чётными номерами и
* минимума из чисел с нечётными номерами
*
* @param arr Массив целых чисел
* @return Сумма максимума из чисел с чётными номерами и
* минимума из чисел с нечётными номерами
*/

int sumOfMaxAndMin(const std::vector<int>& arr) {
 
   // Размер входного массива
   std::size_t size = arr.size();
 
   int min, max;
 
   if (size == 0) {
       return 0;
   } else if (size == 1) {
       return arr[0];
   } else {
       min = arr[0];
       max = arr[1];
       for (int i = 0; i < size; ++i) {
           if ((i+1)%2 != 0) {
               if (arr[i] < min) {
                   min = arr[i];
               }
           } else {
               if (arr[i] > max) {
                   max = arr[i];
               }
           }
       }
   }
 
   return max + min;
}
 



Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Февраль 14, 2014, 22:20
Переделал. Сейчас как? Нормально?
Классика советского кино
Цитировать
эээ - нэт, Торопытся не надо - Вы должны вернуть обществу полноценного чэловэка
Тщательнее с постами - здесь Ваши ошибки недостойны даже обсуждения


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Hrundel от Февраль 14, 2014, 22:24
8Observer8, еще раз тебе говорю, что не надо тебе за это браться. Тебя любой информатик на пустяке высмеит.
Это математическая задача, которая тупо решается формулой Гауса без всякого задр...тного пребора массивов. Единственное что нужно ввести в функцию чтобы получить ответ - это последнее число ряда.

Код:
n = n * (n+1) : 2

Все! это все  что нужно + немного фантазии, которой у тебя по ходу нет.

Ты хотя бы условие своей задачи понимаешь?

Код:
Сумма максимума из чисел с чётными номерами и минимума из чисел с нечётными номерами

Мининмун нечетных чисел равен еденице! Его вообще считать не надо! Это ненужная операция!


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Февраль 14, 2014, 22:36
Все! это все  что нужно + немного фантазии, которой у тебя по ходу нет.
Зачем так жестко? Я тоже "не во всем" согласен с ТС, считаю что многие вещи нужно осознать, пережить, причем глубоко (нахрапом ничего не сделаешь), а для этого нужно время, опыт, желание - да многое. Но в целом он показывает деловой, конструктивный и корректный подход. Давайте и мы будем корректны


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 14, 2014, 23:05
Ты хотя бы условие своей задачи понимаешь?

Код:
Сумма максимума из чисел с чётными номерами и минимума из чисел с нечётными номерами

Мининмун нечетных чисел равен еденице! Его вообще считать не надо! Это ненужная операция!

Здесь речь идёт о не нечётных числах, а о числах с нечётными номерами в массиве.

На входе может быть такой массив: 2, 4, -5, 8. Нечётным тут является номер и в задаче номера начинаются с единицы. В данном примере, минимум из нечётных - это -5, а максимум из чётных - это 8. Сумма равна: 3.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Hrundel от Февраль 14, 2014, 23:18
Значит, отсортируй и снова решай Гаусом. Гаус одной формулой не заканчивается.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: BuRn от Февраль 14, 2014, 23:20
Цитировать
чтобы сделать их универсальными.
М.б. меня щас закидают поносом, но судя из практики, всегда универсальные вещи ведут к оч. плохим последствиям в дальнейшем. ИМХО решение задачи не должно быть универсальным. Лично я всегда стараюсь сделать определенный функционал для определенных вещей, ибо кучу раз натыкался на то, что если и делать что - то универсальное, в итоге получается фейл, ибо:"в одном месте правишь, в другом отваливается". Хотя мб это я такой не удачник... Не сторонник универсальных вещей, каждая задача должна выполнять только тот функционал, который на нее возложен, не более...


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 15, 2014, 07:58
Можете привести пример, где на практике это будет нужно? Пример из Вашей практики, так сказать.

Что, неужели не хватает фантазии? Элементарный пример - компьютерные сети и скорость соединений. Например выбор не самой короткой, а самой быстрой маршрутизации.
Да и вообще, с моей точки зрения,  если тебе приходится объяснять значимость графов в информатике - то лучше забей на это дело! Или иди переучиваться.
А почему тебя твоя профессия не устраивает? Зачем делать то, о чем ты не имешь представления?

Зря Вы обобщаете всех программистов. Есть математики-программисты (которых готовит мех-мат и книт (факультет компьютерных наук и информационных технологий)), а есть инженеры-программисты (которых выпускает политех). Есть тысячи областей программирования, где нужны совершенно разные знания, навыки и умения (к примеру, возьмите разработку сайтов на PHP, jQuery, JavaScript). Как я понимаю, в разработку игровых движков вообще не стоит соваться, если не знаешь мат. анализа, аналитическую геометрию, векторную алгебру, физику, OpenGL (или DirectX) и т.д. Хорошо, конечно же, когда математик-программист сочетается с инженером-программистом и работает в соответствующей области. Но далеко не во всех областях программирования нужен Дональд Кнут. Такие знания нужны в узких кругах. Откройте любой фрилансерный сайт и посмотрите какие там предложения. Вы практически не найдёте тех задач о которых говорите. Там в 99% случаев - заказы для инженеров-программистов. Судя из Ваших обобщений - у Вас очень узкий кругозор. Большинство разработчиков не использует в своей повседневной практики графы. К примеру, возьмите этот крупный международный фрилансерный сайт http://www.freelancer.com/ и убедитесь сколько заказов для инженеров-программистов (я имею ввиду разделы: C++, Java, C#, PHP)

Я закончил физический факультет универа (по специальности: радиофизик). У нас было программирование, но мало. Но все курсовые у меня были связаны с программированием. Плюс 3.5 года в КБ (http://kbep.ru/) инженером-конструктором (там очень большой круг должностных обязанностей, в основном разработка документации (ТУ), написание методик проведения испытаний на стендах и т.д.). Я участвовал в модульном тестировании ПО на ассемблере для микроконтроллера c167. Этот МК в составе СУДГ-20 (система управления и диагностики генератора) управлял генератором на военном самолёте. Потом участвовал в модульном тестировании того же МК, который был в составе КРД-142 (комплексный регулятор двигателя). Этот МК управлял авиационным газотурбинным двигателем на другом военном самолёте. Я знаю, как работают разработчики ПО в том КБ, что они делают и что никакие графы им не были нужны на практике. Это были выпускники политеха, книта, физ. фака. Дома вдоль и поперёк освоил простой МК 8052 и его программирование на ассемблере и Си. Писал ПО для пк на WinAPI и Си, которое принимает (по RS-232), обрабатывает и отображает данные от мк. Посути, инженерное программирование сводится к сборке, обработке, хранении и выдачи информации пользователю. Вот в этой области я и хочу работать. В области инженерной разработки ПО.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Февраль 15, 2014, 10:32
Я закончил физический факультет универа
Конечно Вы не рассказали ничего плохого, но чем меньше таких "лирических опусов" - тем лучше. Здесь надо говорить о программировании, большие отступления неуместны.

Тщательнее с постами - здесь Ваши ошибки недостойны даже обсуждения
Тут я был неправ - не понял условия, думал что чет/нечет определяется по числу (а надо по индексу). Тогда да, нормально, но все-таки немного неряшливо.
Код
C++ (Qt)
int sumOfMaxAndMin(const std::vector<int>& arr) {
 
   // Размер входного массива
   std::size_t size = arr.size();
 
   int min, max;
 
   if (size == 0) {
       return 0;
   } else if (size == 1) {
       return arr[0];
   } else {
       min = arr[0];
       max = arr[1];
       for (int i = 0; i < size; ++i) {
           if ((i+1)%2 != 0) {
               if (arr[i] < min) {
                   min = arr[i];
               }
           } else {
               if (arr[i] > max) {
                   max = arr[i];
               }
           }
       }
   }
 
   return max + min;
}
 
Замечания

- лишние скобки
- else после return - ну и так пишут, дело вкуса, но необходимости нет
- цикл начинается с 2 (а не с 0)
- min, max лучше описать позже, перед их использованием
- как я понял по условию индекс "1-based". Тогда это надо оформить и чуть откомментить, напр
Код
C++ (Qt)
bool even = (i & 1);  // inverted odd/even (index is one-based)
if (even) {
...
 

Что-то задачки - ну прямо "ниже травы", замахнитесь на покрупнее, а то интереса ноль  :)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Hrundel от Февраль 15, 2014, 11:06
Из всего сказанного, я так и не понял - а чем радиофизика не устраивает? Почему надо вдруг разработчиком становиться?


Название: Re: Тренировка навыков быстрого программирования
Отправлено: BuRn от Февраль 15, 2014, 11:11
Из всего сказанного, я так и не понял - а чем радиофизика не устраивает? Почему надо вдруг разработчиком становиться?
Могу предположить, это все тот устой, который сложился лед эдак 10 назад, что :"О программист круто же"


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 15, 2014, 13:00
Конечно Вы не рассказали ничего плохого, но чем меньше таких "лирических опусов" - тем лучше. Здесь надо говорить о программировании, большие отступления неуместны.

Довели :D

Замечания
- лишние скобки
- else после return - ну и так пишут, дело вкуса, но необходимости нет
- цикл начинается с 2 (а не с 0)
- min, max лучше описать позже, перед их использованием
- как я понял по условию индекс "1-based". Тогда это надо оформить и чуть откомментить, напр
Код
C++ (Qt)
bool even = (i & 1);  // inverted odd/even (index is one-based)
if (even) {
...
 

> - лишние скобки
Вы хотите сказать, что количество фигурных скобок в операторах лучше уменьшить? Я в книжке подглядел, что лучше везде ставить, даже если один оператор в цикле (или в условии). Книжка называется "Совершенный код"

> - else после return - ну и так пишут, дело вкуса, но необходимости нет
Мне же результат будет известен только за пределами else? Или я что-то не понял?

> - цикл начинается с 2 (а не с 0)
Понял. Элементы 0 и 1 уже сыграли свою роль. Мысль была такая. Я её не додумал.

> - min, max лучше описать позже, перед их использованием
min и max мне в return же нужны? Позже не получится же?

> как я понял по условию индекс "1-based". Тогда это надо оформить и чуть откомментить, напр
Да согласен. Добавил. Хороший комментарий, спасибо!

Что-то задачки - ну прямо "ниже травы", замахнитесь на покрупнее, а то интереса ноль  :)

Да, пора бы покрупнее :) Там они по сложности разделяются в процентах.Больше 50% я пока не осиляю. Мда... Этот сайт для школьников... Куда катится мир :) Сложно, но постепенно (может за год) я решу все 600 :D. Если в среднем по 2 задачи в день.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: kambala от Февраль 15, 2014, 17:08
Цитировать
- лишние скобки
лишних не бывает, в основном все зависит от стиля
Из всего сказанного, я так и не понял - а чем радиофизика не устраивает? Почему надо вдруг разработчиком становиться?
Могу предположить, это все тот устой, который сложился лед эдак 10 назад, что :"О программист круто же"
на самом деле все проще на мой взгляд: зар. плата


Название: Re: Тренировка навыков быстрого программир
Отправлено: Nidxogg от Февраль 15, 2014, 17:50
Цитировать
Из всего сказанного, я так и не понял - а чем радиофизика не устраивает? Почему надо вдруг разработчиком становиться?
Оффтопну:
В России по данной специальности врятли получиться нормально работать.
А для забургорья нужен опыт


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Февраль 15, 2014, 19:02
Мне же результат будет известен только за пределами else? Или я что-то не понял?
Лично я бы писал так
Код
C++ (Qt)
 
   if (size == 0) return 0;
   if (size == 1) return arr[0];
 
   int  min = arr[0];
   int  max = arr[1];
   for (int i = 2; i < size; ++i) {
    ...
 
Некоторые любят без return'ов, чтобы ф-ция обязательно всегда доходила до последней строки. Тогда напр так
Код
C++ (Qt)
int min = 0, max = 0;
 
if (size > 0) {
min = arr[0];
if (size > 1) {
 max = arr[1];
 for (int i = 2; i < size; ++i) {
  ....
 }
}
}
return min + max;
А в общем здесь нечего обсуждать т.к. все уж слишком просто  :)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: gil9red от Февраль 16, 2014, 00:01
Спасибо, ребят! Много классной инфы. Я завтра всё проработаю.

Вот функция из предыдущего сообщения. Что о ней скажете? Не скупитесь в критике

Код
/**
* Сумма максимума из чисел с чётными номерами и
* минимума из чисел с нечётными номерами
*
* @param arr Массив целых чисел
* @param result Сумма максимума из чисел с чётными номерами и
* минимума из чисел с нечётными номерами
* @return Код ошибки
*/
int sumOfMaxAndMin(const std::vector<int>& arr, int& result) {
 
   // Массивы для чисел с чётным и нечётными номерами
   std::vector<int> odd;
   std::vector<int> even;
 
   // Размер входного массива
   std::size_t size = arr.size();
 
   // Сортируем на чётный и нечётные массивы
   for (int i = 0; i < size; ++i) {
       if ((i+1)%2 != 0) {
           odd.push_back(arr[i]);
       } else {
           even.push_back(arr[i]);
       }
   }
 
   // Находим минимальный среди нечётных
   int min = 0;
   if (odd.size() > 0) {
       min = *std::min_element(odd.begin(), odd.end());
   }
 
   // Находим максимальный среди чётных
   int max = 0;
   if (even.size() > 0) {
       max = *std::max_element(even.begin(), even.end());
   }
 
   // Вычисляем результат
   result = max + min;
 
   // Возвращаем код ошибки
   return 0;
}

Вот про это и речь, я предлагаю 8Observer8 вначале подумать, что бы не нужно было проводить потом "декомпозиции".
То палка о двух концах. Дальше возникнет идея сделать ввод универсальным, перекрыть оператор >>, пойдут в ход злополучные темплейты и.т.д. Стоит ли так увлекаться? Мое мнение - нет, пока достаточно локализовать ввод, а дальше посмотрим.

Это очень интересная тема (оператор >>, темплейты). Замечания по алгоритмам к задачам устраню. А тем временем буду думать об улучшении функциий (чтение, запись), чтобы сделать их универсальными. Дайте, пожалуйста, задание, куда двигаться дальше по улучшению.

Цитировать
Да, и константы/песики надо понаводить (enum), а то 1, 2. 3 потом хрен найдешь
Что такое песики?


Зачем так код усложнять? :)
Код
C++ (Qt)
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <limits.h>
 
using namespace std;
 
int main()
{
   freopen("input.txt","r",stdin);
   freopen("output.txt","w",stdout);
 
   int n, max = INT_MIN, min = INT_MAX, count = 1;
 
   while( cin >> n )
   {        
       if ( count % 2 )
       {
           if ( min > n )
               min = n;
       } else
       {
           if ( max < n )
               max = n;
       }
 
       count++;
   }
 
   cout << min + max;
 
   return 0;
}
 

Подсадили меня на сайт http://acmp.ru/, вот уже второй день решаю задачки ;D


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 16, 2014, 07:06
Подсадили меня на сайт http://acmp.ru/, вот уже второй день решаю задачки ;D

Давайте с Вами соревноваться, кто больше решит? То есть решать не на скорость, а на количество. Я планирую за год или полтора их все решить (их 600 всего)

Правда я пока решаю задачи из раздела для начинающих:

(http://i7.pixs.ru/storage/0/7/2/129png_3415736_10893072.png)

Вот моя статистика:

(http://i7.pixs.ru/storage/8/7/5/130png_8343816_10892875.png)

Решил одну задачу со сложностью 46% http://acmp.ru/index.asp?main=task&id_task=50 Эта та задача, в которой я применил Set и которую нужно переделать.
Алгоритм (содержательная часть). Пока нет понятия что все чего-то стоит, весит. Использован std::set - зачем? Ведь ассоциативный контейнер - удовольствие дорогое. И зачем здесь вообще нужен контейнер? Рассмотрим циклический сдвиг
- abcd  // было
- dabc  // стало
Кто же мешает найти сначала "d" и затем проверить не заканчивается ли найденное на "аbc"? Этот алгоритм использует 0 (ноль) памяти, и по меньшей мере на порядок быстрее.

Правда, по памяти и скорости она немного занимает:

(http://i.pixs.ru/storage/9/0/7/131png_5555622_10892907.png)

Зачем так код усложнять? :)

Что касается самого алгоритма, то он у Вас действительно проще и лучше. Если бы Вы участвовали в Олимпиаде по программированию, то Ваша программа вообще идеальна, так как у Вас нет ни одной "лишней" строки кода. Вы сэкономили драгоценные человеко-часы. Но с точки зрения разработчика она ужасна, так как не проверяет ошибки и повторно её не используешь (например, не перекопипастишь для решения другой задачи; где нужно будет заменить только "содержательную часть"). Вот я решил для себя, что не буду решать на скорость, а буду решать на качество, чтобы людям было удобно, легко и приятно читать программу и использовать функции повторно (во всяком случае теперь я к этому стремлюсь)

Советую взять такой подход на вооружение, как в решении этой задачи: http://acmp.ru/index.asp?main=task&id_task=272

Код
C++ (Qt)
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
 
int readData(const std::string& iFileName, std::vector<int>& arr);
int writeResult(const std::string& oFileName, int &result);
int showError(int err, const std::string& fileName);
int sumOfMaxAndMin(const std::vector<int>& arr);
 
int main(int argc, char** argv) {
 
   // Массив для хранения входных данных
   std::vector <int> arr;
 
   // Имя входного файла
   std::string iFileName = "input.txt";
 
   // Читаем данные из файла
   int err = readData(iFileName, arr);
   if (err) return showError(err, iFileName);
 
   // Выполняем содержательную часть
   int result = sumOfMaxAndMin(arr);
 
   //    int result;
   //    err = sumOfMaxAndMin(arr, result);
   //    if (err) return showError(err, iFileName);
 
   // Записываем выходной файл
   std::string oFileName = "output.txt";
   err = writeResult(oFileName, result);
   if (err) return showError(err, oFileName);
 
   return 0;
}
 
/**
* Читаем данные из файла
*
* @param iFileName Имя входного файла
* @param vec Массив, в который будут считаны входные данные
* @return Код ошибки: 0 - если ошибок нет
*                     1 - если файл не удалось открыть
*                     2 - если в файле некорректные данные
*/

int readData(const std::string& iFileName, std::vector<int>& arr) {
 
   // Открываем файл с входными данными
   std::ifstream in;
   in.open(iFileName.c_str());
   if (!in.is_open()) {
       return 1;
   }
 
   // Читаем данные из файла
   int value, err = 0;
   std::string input;
   while (in >> input) {
       if (std::stringstream(input) >> value) {
           arr.push_back(value);
       } else {
           err = 2;
           break;
       }
   }
 
   // Закрываем файл и возвращаем код ошибки
   in.close();
   return err;
}
 
/**
* Записываем результат выходной в файл
*
* @param iFileName Имя выходного файла
* @param vec Массив, который нужно записать в файл
* @return Код ошибки: 0 - если ошибок нет
*                     1 - если файл не удалось открыть
*                     2 - если в файле не удалось записать
*/

int writeResult(const std::string& oFileName, int& result) {
 
   // Открываем файл для записи
   std::ofstream out;
   out.open(oFileName.c_str());
   if (!out.is_open()) {
       return 1;
   }
 
   // Записываем данные в файл
   out << result << std::endl;
 
   // Закрываем файл и возвращаем код ошибки
   out.close();
   return 0;
}
 
/**
* Выводит текст с ошибкой на экран
*
* @param err Код ошибки
* @param iFileName Имя файла, в котором произошла ошибка
*/

int showError(int err, const std::string& fileName) {
   switch (err) {
       case 1:
           std::cerr << "Error: could not open the file " << fileName.c_str() << std::endl;
           break;
       case 2:
           std::cerr << "Error: incorrect data in the file " << fileName.c_str() << std::endl;
           break;
       default:
           std::cerr << "Error code: " << err << "; file name: " << fileName.c_str() << std::endl;
           break;
   }
 
   return err;
}
 
/**
* Сумма максимума из чисел с чётными номерами и
* минимума из чисел с нечётными номерами
*
* @param arr Массив целых чисел
* @return Сумма максимума из чисел с чётными номерами и
* минимума из чисел с нечётными номерами
*/

int sumOfMaxAndMin(const std::vector<int>& arr) {
 
   // Размер входного массива
   std::size_t size = arr.size();
 
   int min = 0, max = 0;
 
   if (size == 0) return 0;
   if (size == 1) return arr[0];
 
   min = arr[0];
   max = arr[1];
   for (int i = 2; i < size; ++i) {
       if ((i + 1) % 2 != 0) { // inverted odd/even (index is one-based)
           if (arr[i] < min) {
               min = arr[i];
           }
       } else {
           if (arr[i] > max) {
               max = arr[i];
           }
       }
   }
 
   return max + min;
}
 

P.S. Я теперь понимаю насколько всё же важны тесты (для изменения (улучшения) решений задач), так как могу без страха изменять код, а потом сразу запускать написанные однажды тесты.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: gil9red от Февраль 16, 2014, 09:03
Давайте с Вами соревноваться, кто больше решит? То есть решать не на скорость, а на количество. Я планирую за год или полтора их все решить (их 600 всего)
Нет смысла :) т.к. скоро, через несколько дней мне надоест решать задачки, и вернусь к написанию своего проекта, который по совместительству является дипломом :)

Цитировать
Что касается самого алгоритма, то он у Вас действительно проще и лучше. Если бы Вы участвовали в Олимпиаде по программированию, то Ваша программа вообще идеальна, так как у Вас нет ни одной "лишней" строки кода. Вы сэкономили драгоценные человеко-часы. Но с точки зрения разработчика она ужасна, так как не проверяет ошибки и повторно её не используешь (например, не перекопипастишь для решения другой задачи; где нужно будет заменить только "содержательную часть"). Вот я решил для себя, что не буду решать на скорость, а буду решать на качество, чтобы людям было удобно, легко и приятно читать программу и использовать функции повторно (во всяком случае теперь я к этому стремлюсь)
Тык, ранговая система на том сайте обязывает сокращать код, если хочешь попасть в топ (правда, я только один раз попал в топ, и то на 18 место, и для этого мне пришлось сокращать код используя #define :) и после такого, было ощущение, что код прошел через обфускацию :D) А система проверки гарантируется, что подаваться программе будет именно файл input.txt и данные в нем будут именно в том виде, который описан в задаче, поэтому я не использовал проверки, и комментарии тоже, и имена переменных тоже сокращены :)

Цитировать
Советую взять такой подход на вооружение, как в решении этой задачи: http://acmp.ru/index.asp?main=task&id_task=272
Про такой подход я знаю не по наслышке :)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Февраль 16, 2014, 10:21
Тык, ранговая система на том сайте обязывает сокращать код, если хочешь попасть в топ

Я думал, что для топа нужно наименьшее количество ошибок "Wrong answer", "Memory limit exceeded" и т.д. Откуда у Вас такая информация о рейтинге? То есть она достоверная?


Название: Re: Тренировка навыков быстрого программирования
Отправлено: gil9red от Февраль 16, 2014, 10:59
Тык, ранговая система на том сайте обязывает сокращать код, если хочешь попасть в топ

Я думал, что для топа нужно наименьшее количество ошибок "Wrong answer", "Memory limit exceeded" и т.д. Откуда у Вас такая информация о рейтинге? То есть она достоверная?

У любой задачи есть ссылка на лучшие попытки и внизу написано таблицы с "лучшими" попытками:
Цитировать
В качестве критерия ранжирования лучших попыток служит размер кода закачиваемой программы. При подсчете размера кода не учитываются пробелы, а так же символы переноса и табуляции.

Похоже я не точно выразился, когда говорил, про топлист ^_^


Название: Re: Тренировка навыков быстрого программирования
Отправлено: lit-uriy от Февраль 16, 2014, 11:00
Определённо тему из раздела Qt нужно переносить.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Февраль 16, 2014, 11:16
Зачем так код усложнять? :)
Конечно Ваш вариант намного короче, но это достигнуто за счет отсутствия всякого контроля ошибок. Так программировать легко и приятно  :)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: gil9red от Февраль 16, 2014, 15:05
Определённо тему из раздела Qt нужно переносить.
Давно пора в говорилку ее :)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 04, 2014, 11:36
У любой задачи есть ссылка на лучшие попытки и внизу написано таблицы с "лучшими" попытками:
Цитировать
В качестве критерия ранжирования лучших попыток служит размер кода закачиваемой программы. При подсчете размера кода не учитываются пробелы, а так же символы переноса и табуляции.

Похоже я не точно выразился, когда говорил, про топлист ^_^

Я думаю, что этот ресурс можно использовать, чтобы навыки разработки развивать. Разработчики же не стремятся сокращать переменные до одной буквы. Можно оттачивать хороший стиль на задачах. А рейтинг не нужен. Он даже вреден, так как приучает к плохому стилю. Программы пишутся для людей, а не для компьютеров. Компьютеры сейчас ёмкие и на байтах много не сэкономишь.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 04, 2014, 11:37
Помогите, пожалуйста. Сейчас пытаюсь решить вот эту задачу: http://acmp.ru/?main=task&id_task=13

Вот с такими тестами нормально запускается (такие же тесты, как под описанием задачи на сайте):

Код
C++ (Qt)
   QTest::addColumn<int>("first");
   QTest::addColumn<int>("second");
   QTest::addColumn<int>("nbulls_expected");
   QTest::addColumn<int>("ncows_expected");
 
   QTest::newRow("bulls_and_cows_01") << 5671 << 7251 << 1 << 2;
   QTest::newRow("bulls_and_cows_02") << 1234 << 1234 << 4 << 0;
   QTest::newRow("bulls_and_cows_03") << 2034 << 6234 << 2 << 1;
 

Вот моя функция, которая решает задачу:

Код
C++ (Qt)
/**
* Возвращает (через ссылки) количество совпадений цифр двух
* чисел на тех же позициях (быки) и на разных (коровы)
*
* @param first Первое число
* @param second Второе число
* @param nbulls Возвращаемое значение. Количество совпадений вместе с
* позицией (быки)
* @param ncows Возвращаемое значение. Количество совпадений, не
* учитывая позицию (коровы)
*/

void bulls_and_cows(int first, int second, int &nbulls, int &ncows) {
 
   div_t divresult_first;
   div_t divresult_second;
 
   int first_temp = first;
   int second_temp = second;
 
   std::vector<int> vec_first;
   std::vector<int> vec_second;
 
   const std::size_t nsize = 4;
 
   // Подсчёт быков
   for (std::size_t i = 0; i < nsize; ++i) {
       // Деление с сохранением частного и остатка
       divresult_first = div(first_temp, 10);
       divresult_second = div(second_temp, 10);
 
       // Сохраняем цифры для поиска коров
       vec_first.push_back(divresult_first.rem);
       vec_second.push_back(divresult_second.rem);
 
       // Поиск быков
       if (divresult_first.rem == divresult_second.rem) {
           ++nbulls;
       }
       first_temp = divresult_first.quot;
       second_temp = divresult_second.quot;
   }
 
   // Проверяем, что числа четырёхзначные
   if ( (vec_first.size() != nsize) && (vec_second.size() != nsize) ) {
       return;
   }
 
   // Подсчёт коров
   for (std::size_t i = 0; i < nsize; ++i) {
       std::vector<int>::const_iterator it = std::find(vec_second.begin(), vec_second.end(), vec_first[i]);
       if (it != vec_second.end()) {
           if (*it != vec_second[i]) {
               ++ncows;
           }
       }
   }
}

А это всё содержимое main.cpp:
Код
C++ (Qt)
#include <string>
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <vector>
#include <algorithm>
 
//#define TESTING
 
#ifndef TESTING
int readData(const std::string &iFileName, int &first, int &second);
int writeResult(const std::string& oFileName, int nbulls, int ncows);
int showError(int err, const std::string& fileName);
void bulls_and_cows(int first, int second, int &nbulls, int &ncows);
 
int main(int argc, char** argv) {
 
   // Входные данные
   int first;
   int second;
 
   // Имя входного файла
   std::string iFileName = "input.txt";
 
   // Читаем данные из файла
   int err = readData(iFileName, first, second);
   if (err) return showError(err, iFileName);
 
   // Выполняем содержательную часть
   int nbulls, ncows;
   nbulls = ncows = 0;
   bulls_and_cows(first, second, nbulls, ncows);
 
   // Записываем выходной файл
   std::string oFileName = "output.txt";
   err = writeResult(oFileName, nbulls, ncows);
   if (err) return showError(err, oFileName);
 
   return 0;
}
 
/**
* Читаем данные из файла
*
* @param iFileName Имя входного файла
* @param vec Массив, в который будут считаны входные данные
* @return Код ошибки: 0 - если ошибок нет
*                     1 - если файл не удалось открыть
*                     2 - если в файле некорректные данные
*/

int readData(const std::string& iFileName, int &first, int &second) {
 
   // Код ошибки
   int err = 0;
 
   // Открываем файл с входными данными
   std::ifstream in;
   in.open(iFileName.c_str());
   if (!in.is_open()) {
       err = 1;
       return err;
   }
 
   // Считываем данные из файла
   if (in >> first >> second) {
       err = 0;
       return err;
   } else {
       err = 2;
       return err;
   }
 
   // Закрываем файл и возвращаем нулевой код ошибки
   in.close();
   return err;
}
 
/**
* Записываем результат выходной в файл
*
* @param iFileName Имя выходного файла
* @param vec Массив, который нужно записать в файл
* @return Код ошибки: 0 - если ошибок нет
*                     1 - если файл не удалось открыть
*                     2 - если в файле не удалось записать
*/

int writeResult(const std::string& oFileName, int nbulls, int ncows) {
 
   // Открываем файл для записи
   std::ofstream out;
   out.open(oFileName.c_str());
   if (!out.is_open()) {
       return 1;
   }
 
   // Записываем данные в файл
   out << nbulls << " " << ncows << std::endl;
 
   // Закрываем файл и возвращаем код ошибки
   out.close();
   return 0;
}
 
/**
* Выводит текст с ошибкой на экран
*
* @param err Код ошибки
* @param iFileName Имя файла, в котором произошла ошибка
*/

int showError(int err, const std::string& fileName) {
   switch (err) {
   case 1:
       std::cerr << "Error: could not open the file " << fileName.c_str() << std::endl;
       break;
   case 2:
       std::cerr << "Error: incorrect data in the file " << fileName.c_str() << std::endl;
       break;
   default:
       std::cerr << "Error code: " << err << "; file name: " << fileName.c_str() << std::endl;
       break;
   }
 
   return err;
}
#endif
 
/**
* Возвращает (через ссылки) количество совпадений цифр двух
* чисел на тех же позициях (быки) и на разных (коровы)
*
* @param first Первое число
* @param second Второе число
* @param nbulls Возвращаемое значение. Количество совпадений вместе с
* позицией (быки)
* @param ncows Возвращаемое значение. Количество совпадений, не
* учитывая позицию (коровы)
*/

void bulls_and_cows(int first, int second, int &nbulls, int &ncows) {
 
   div_t divresult_first;
   div_t divresult_second;
 
   int first_temp = first;
   int second_temp = second;
 
   std::vector<int> vec_first;
   std::vector<int> vec_second;
 
   const std::size_t nsize = 4;
 
   // Подсчёт быков
   for (std::size_t i = 0; i < nsize; ++i) {
       // Деление с сохранением частного и остатка
       divresult_first = div(first_temp, 10);
       divresult_second = div(second_temp, 10);
 
       // Сохраняем цифры для поиска коров
       vec_first.push_back(divresult_first.rem);
       vec_second.push_back(divresult_second.rem);
 
       // Поиск быков
       if (divresult_first.rem == divresult_second.rem) {
           ++nbulls;
       }
       first_temp = divresult_first.quot;
       second_temp = divresult_second.quot;
   }
 
   // Проверяем, что числа четырёхзначные
   if ( (vec_first.size() != nsize) && (vec_second.size() != nsize) ) {
       return;
   }
 
   // Подсчёт коров
   for (std::size_t i = 0; i < nsize; ++i) {
       std::vector<int>::const_iterator it = std::find(vec_second.begin(), vec_second.end(), vec_first[i]);
       if (it != vec_second.end()) {
           if (*it != vec_second[i]) {
               ++ncows;
           }
       }
   }
}
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 04, 2014, 11:40
Проблемы забыл описать. Когда отправляю на сервер, то мне сообщают, что "Wrong answer"


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Bepec от Март 04, 2014, 12:28
:) Это и есть недостаток этого сервиса :D Моя программа не проходила пятый тест, причём все входные данные указанные в задаче и всевозможные их вариации проходят успешно :P


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 04, 2014, 12:29
:) Это и есть недостаток этого сервиса :D Моя программа не проходила пятый тест, причём все входные данные указанные в задаче и всевозможные их вариации проходят успешно :P

Спасибо за ответ! У меня задача не проходит первый тест :)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Bepec от Март 04, 2014, 14:02
Возможно ты неправильно понял - входные данные в этом сервисе неизвестны. Потому определить где ошибка невозможно :P


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 04, 2014, 15:11
Возможно ты неправильно понял - входные данные в этом сервисе неизвестны. Потому определить где ошибка невозможно :P

Какие входные данные для моей программы могут могут приводить к неверному результату? Есть варианты?


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Bepec от Март 04, 2014, 15:15
Неа :) В том вся и прелесть :P


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 04, 2014, 15:17
Я имел ввиду, что может я задачу неверно понял? Наверняка, в моём алгоритме ошибка. Скорее всего есть такие входные данные, которые моя программа неверно обрабатывает. Буду думать.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Март 05, 2014, 09:10
1)
Код
C++ (Qt)
void bulls_and_cows(int first, int second, int &nbulls, int &ncows)
 
Часто пишут так
Код
C++ (Qt)
void bulls_and_cows(int first, int second, int * nbulls, int * ncows)
 
Смысл: вызывающий видит вход/выход, Если же ссылки, то можно так
Код
C++ (Qt)
void bulls_and_cows(int iFirst, int iSecond, int & oBulls, int & oCows)
 

2)
Код
C++ (Qt)
   // Проверяем, что числа четырёхзначные
   if ( (vec_first.size() != nsize) && (vec_second.size() != nsize) ) {
       return;
   }
 
Правильно || (вместо &&), и возврат кода ошибки никто не отменял. И если у Вас цикл до nsize, то откуда возьмется др число эл-тов?

3) Не выделена ф-ция создания массива/контейнера из числа, все свалено в  bulls_and_cows, в результате она смотрится тяжеловато.

4) Неуемное использование std:: Чем не устраивал простенький char[4] (вместо векторов)? Да, это не общее решение - но нужна ли здесь какая-то общность? С др стороны по скорости "просто массив" заметно выигрывает. Вообще зачем подсчеты в 2 циклах? Почему бы не написать непредвзято и незатейливо, напр
Код
C++ (Qt)
void CalcBullsCows( const char * s1, const char * s2, int count, int & num_Bull, int & num_Cows )
{
 num_Bull = num_Cows = 0;
 for (int i = 0; i < count; ++i) {
   if (s1[i] == s2[i]) {
    ++num_Bulls;
    continue;
   }
 
  for (int j = 0; j < count; ++j) {
   if (s1[j] == s2[i])
    if (s1[j] != s2[j])  { // на всякий случай учтем что цифры могут повторяться
      ++num_Cows;
       break;  
    }
   }
 }
}


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 05, 2014, 09:39
Спасибо огромное! Обязательно всё разберу, даже может за сегодня :)

У меня вопрос. Какую букву лучше поставить перед именем "fileName" (см. функцию ниже) . С одной стороны это имя выходного файла, а с другой - входной параметр для функции:

Код
C++ (Qt)
/**
* Записываем результат выходной в файл
*
* @param oFileName Имя выходного файла
* @param vec Массив, который нужно записать в файл
* @return Код ошибки: 0 - если ошибок нет
*                     1 - если файл не удалось открыть
*                     2 - если в файле не удалось записать
*/

int writeResult(const std::string& oFileName, int iBulls, int iCows) {
 
   // Открываем файл для записи
   std::ofstream out;
   out.open(oFileName.c_str());
   if (!out.is_open()) {
       return 1;
   }
 
   // Записываем данные в файл
   out << nbulls << " " << ncows << std::endl;
 
   // Закрываем файл и возвращаем код ошибки
   out.close();
   return 0;
}
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Old от Март 05, 2014, 09:48
У меня вопрос. Какую букву лучше поставить перед именем "fileName" (см. функцию ниже) . С одной стороны это имя выходного файла, а с другой - входной параметр для функции:
Не надо никаких букв, просто давайте нормальные имена параметрам и переменным.
Это имя результирующего файла.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: OKTA от Март 05, 2014, 09:54
Лично по мне удобна вот такая нотация - один раз определил _In_ и _Out_ и пользуйся на здоровье)
Код:
void func(
  _Out_  int a,
  _In_   int b,
 );


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 05, 2014, 10:14
Лично по мне удобна вот такая нотация - один раз определил _In_ и _Out_ и пользуйся на здоровье)
Код:
void func(
  _Out_  int a,
  _In_   int b,
 );

Первый раз такое вижу. И это будет компилироваться? Пожалуйста, напишите маленький примерчик по вызову такой функции :)

Не надо никаких букв, просто давайте нормальные имена параметрам и переменным.
Это имя результирующего файла.

Old, мне очень хочется узнать Ваше мнение, куда прижимать значок '&'? И ещё вопрос: в следующей функции уместны ли буквы 'i' и 'o' перед именами:  Bulls и Cows
Код
C++ (Qt)
void bulls_and_cows(int iFirst, int iSecond, int & oBulls, int & oCows);

Лично мне хочеться написать вот так:
Код
C++ (Qt)
void bulls_and_cows(int firstNumber, int secondNumber, int & nBulls, int & nCows);


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Март 05, 2014, 10:20
У меня вопрос. Какую букву лучше поставить перед именем "fileName" (см. функцию ниже) . С одной стороны это имя выходного файла, а с другой - входной параметр для функции:
Все меряется "относительно ф-ции" поэтому "i". Если используется и как вход и как выход то "io". Если файл для записи, то неплохо напр "iOutFileName". Эти соглашения необязательны, но многие их используют, и в этом есть смысл.

А вот возвращать 1 (0) - явный признак что "не профи" :) Обязательно должны быть enum или константы или даже #define (что кому нравится) - но никак не числа вбитые в код.
Код
C++ (Qt)
 
if (!out.is_open()) {
return errFileOpen;


Название: Re: Тренировка навыков быстрого программирования
Отправлено: carrygun от Март 05, 2014, 10:24
...куда прижимать значок '&'?

По этому поводу можно почитать вот это (http://qt-project.org/wiki/Qt_Coding_Style).


Название: Re: Тренировка навыков быстрого программирования
Отправлено: OKTA от Март 05, 2014, 10:25
Да все просто! Делаете define и затем используете в объявлении и определении функций) препроцессор потом уберет все эти _In_ & _Out_!

Код:
#define _In_
#define _Out_

void func(
  _Out_  int a,
  _In_   int b,
 );

Удобно опять же на мой взгляд при этом группировать параметры по одному в строке, чтобы удобнее читать было. Вот пример из Windows :
Код:
BOOL WINAPI CryptImportPublicKeyInfoEx2(
  _In_   DWORD dwCertEncodingType,
  _In_   PCERT_PUBLIC_KEY_INFO pInfo,
  _In_   DWORD dwFlags,
  _In_   void *pvAuxInfo,
  _Out_  BCRYPT_KEY_HANDLE *phKey
);


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Март 05, 2014, 10:47
Лично мне хочеться написать вот так:
Так и пишите, не надо следовать каким-то догмам и.т.п. Знать "как делают другие" полезно - но не более того
Цитировать
When strictly following a rule makes your code look bad, feel free to break it


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Old от Март 05, 2014, 10:48
Old, мне очень хочется узнать Ваше мнение, куда прижимать значок '&'?
Я прижимаю к имени, и ссылку и указатель.

И ещё вопрос: в следующей функции уместны ли буквы 'i' и 'o' перед именами:  Bulls и Cows
Для меня не уместны.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: gil9red от Март 05, 2014, 11:58
Помогите, пожалуйста. Сейчас пытаюсь решить вот эту задачу: http://acmp.ru/?main=task&id_task=13

Вот с такими тестами нормально запускается (такие же тесты, как под описанием задачи на сайте):

Код
C++ (Qt)
   QTest::addColumn<int>("first");
   QTest::addColumn<int>("second");
   QTest::addColumn<int>("nbulls_expected");
   QTest::addColumn<int>("ncows_expected");
 
   QTest::newRow("bulls_and_cows_01") << 5671 << 7251 << 1 << 2;
   QTest::newRow("bulls_and_cows_02") << 1234 << 1234 << 4 << 0;
   QTest::newRow("bulls_and_cows_03") << 2034 << 6234 << 2 << 1;
 

Вот моя функция, которая решает задачу:

Код
C++ (Qt)
/**
* Возвращает (через ссылки) количество совпадений цифр двух
* чисел на тех же позициях (быки) и на разных (коровы)
*
* @param first Первое число
* @param second Второе число
* @param nbulls Возвращаемое значение. Количество совпадений вместе с
* позицией (быки)
* @param ncows Возвращаемое значение. Количество совпадений, не
* учитывая позицию (коровы)
*/

void bulls_and_cows(int first, int second, int &nbulls, int &ncows) {
 
   div_t divresult_first;
   div_t divresult_second;
 
   int first_temp = first;
   int second_temp = second;
 
   std::vector<int> vec_first;
   std::vector<int> vec_second;
 
   const std::size_t nsize = 4;
 
   // Подсчёт быков
   for (std::size_t i = 0; i < nsize; ++i) {
       // Деление с сохранением частного и остатка
       divresult_first = div(first_temp, 10);
       divresult_second = div(second_temp, 10);
 
       // Сохраняем цифры для поиска коров
       vec_first.push_back(divresult_first.rem);
       vec_second.push_back(divresult_second.rem);
 
       // Поиск быков
       if (divresult_first.rem == divresult_second.rem) {
           ++nbulls;
       }
       first_temp = divresult_first.quot;
       second_temp = divresult_second.quot;
   }
 
   // Проверяем, что числа четырёхзначные
   if ( (vec_first.size() != nsize) && (vec_second.size() != nsize) ) {
       return;
   }
 
   // Подсчёт коров
   for (std::size_t i = 0; i < nsize; ++i) {
       std::vector<int>::const_iterator it = std::find(vec_second.begin(), vec_second.end(), vec_first[i]);
       if (it != vec_second.end()) {
           if (*it != vec_second[i]) {
               ++ncows;
           }
       }
   }
}

А это всё содержимое main.cpp:
Код
C++ (Qt)
#include <string>
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <vector>
#include <algorithm>
 
//#define TESTING
 
#ifndef TESTING
int readData(const std::string &iFileName, int &first, int &second);
int writeResult(const std::string& oFileName, int nbulls, int ncows);
int showError(int err, const std::string& fileName);
void bulls_and_cows(int first, int second, int &nbulls, int &ncows);
 
int main(int argc, char** argv) {
 
   // Входные данные
   int first;
   int second;
 
   // Имя входного файла
   std::string iFileName = "input.txt";
 
   // Читаем данные из файла
   int err = readData(iFileName, first, second);
   if (err) return showError(err, iFileName);
 
   // Выполняем содержательную часть
   int nbulls, ncows;
   nbulls = ncows = 0;
   bulls_and_cows(first, second, nbulls, ncows);
 
   // Записываем выходной файл
   std::string oFileName = "output.txt";
   err = writeResult(oFileName, nbulls, ncows);
   if (err) return showError(err, oFileName);
 
   return 0;
}
 
/**
* Читаем данные из файла
*
* @param iFileName Имя входного файла
* @param vec Массив, в который будут считаны входные данные
* @return Код ошибки: 0 - если ошибок нет
*                     1 - если файл не удалось открыть
*                     2 - если в файле некорректные данные
*/

int readData(const std::string& iFileName, int &first, int &second) {
 
   // Код ошибки
   int err = 0;
 
   // Открываем файл с входными данными
   std::ifstream in;
   in.open(iFileName.c_str());
   if (!in.is_open()) {
       err = 1;
       return err;
   }
 
   // Считываем данные из файла
   if (in >> first >> second) {
       err = 0;
       return err;
   } else {
       err = 2;
       return err;
   }
 
   // Закрываем файл и возвращаем нулевой код ошибки
   in.close();
   return err;
}
 
/**
* Записываем результат выходной в файл
*
* @param iFileName Имя выходного файла
* @param vec Массив, который нужно записать в файл
* @return Код ошибки: 0 - если ошибок нет
*                     1 - если файл не удалось открыть
*                     2 - если в файле не удалось записать
*/

int writeResult(const std::string& oFileName, int nbulls, int ncows) {
 
   // Открываем файл для записи
   std::ofstream out;
   out.open(oFileName.c_str());
   if (!out.is_open()) {
       return 1;
   }
 
   // Записываем данные в файл
   out << nbulls << " " << ncows << std::endl;
 
   // Закрываем файл и возвращаем код ошибки
   out.close();
   return 0;
}
 
/**
* Выводит текст с ошибкой на экран
*
* @param err Код ошибки
* @param iFileName Имя файла, в котором произошла ошибка
*/

int showError(int err, const std::string& fileName) {
   switch (err) {
   case 1:
       std::cerr << "Error: could not open the file " << fileName.c_str() << std::endl;
       break;
   case 2:
       std::cerr << "Error: incorrect data in the file " << fileName.c_str() << std::endl;
       break;
   default:
       std::cerr << "Error code: " << err << "; file name: " << fileName.c_str() << std::endl;
       break;
   }
 
   return err;
}
#endif
 
/**
* Возвращает (через ссылки) количество совпадений цифр двух
* чисел на тех же позициях (быки) и на разных (коровы)
*
* @param first Первое число
* @param second Второе число
* @param nbulls Возвращаемое значение. Количество совпадений вместе с
* позицией (быки)
* @param ncows Возвращаемое значение. Количество совпадений, не
* учитывая позицию (коровы)
*/

void bulls_and_cows(int first, int second, int &nbulls, int &ncows) {
 
   div_t divresult_first;
   div_t divresult_second;
 
   int first_temp = first;
   int second_temp = second;
 
   std::vector<int> vec_first;
   std::vector<int> vec_second;
 
   const std::size_t nsize = 4;
 
   // Подсчёт быков
   for (std::size_t i = 0; i < nsize; ++i) {
       // Деление с сохранением частного и остатка
       divresult_first = div(first_temp, 10);
       divresult_second = div(second_temp, 10);
 
       // Сохраняем цифры для поиска коров
       vec_first.push_back(divresult_first.rem);
       vec_second.push_back(divresult_second.rem);
 
       // Поиск быков
       if (divresult_first.rem == divresult_second.rem) {
           ++nbulls;
       }
       first_temp = divresult_first.quot;
       second_temp = divresult_second.quot;
   }
 
   // Проверяем, что числа четырёхзначные
   if ( (vec_first.size() != nsize) && (vec_second.size() != nsize) ) {
       return;
   }
 
   // Подсчёт коров
   for (std::size_t i = 0; i < nsize; ++i) {
       std::vector<int>::const_iterator it = std::find(vec_second.begin(), vec_second.end(), vec_first[i]);
       if (it != vec_second.end()) {
           if (*it != vec_second[i]) {
               ++ncows;
           }
       }
   }
}
 

Не знаю, у все проходило :)
инклудов много - один проект использовал для всех задач, и было влом убирать их после решения :)
Код:
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <vector>
#include <math.h>
#include <list>
#include <map>
#include <set>
#include <iomanip>
#include <iterator>
#include <sstream>
#include <algorithm>
 
using namespace std;
 
int main()
{
    freopen( "input.txt", "r", stdin );
    freopen( "output.txt", "w", stdout );
 
    string s1, s2;
    cin >> s1 >> s2;
    int bulls=0, cows=0;
 
//    cout << s1 << " " << s2 << "\n";
 
    for ( int i = 0; i < 4; i++ )
        if ( s1[i] == s2[i] )
            bulls++;
 
    for ( int i = 0; i < 4; i++ )
    {
        for ( int j = 0; j < 4; j++ )
            if ( s1[i] == s2[j] && i != j )
                cows++;
    }
 
    cout << bulls << " " << cows /*<< "\n"*/;
 
    return 0;
}

Но я бы на вашем месте решал бы нормальные (попробуйте сделать браузер или текстовый редактор, можно и xml с html, или плеер видео или ауди) - такие будут интереснее и познавательнее )
Олимпиадные мало чему научат, там просто нужно знать мат алгоритмы или хорошо их гуглить в википедии. Да и олимпиадные больше части уникальные, их алгоритм пригодится только для данной задачи и все.
Сам решил около сотни задач, не все своими силами - алгоритмы некоторых находились в википедии :)
Удачи с задачками ))


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 05, 2014, 14:00
Смысл: вызывающий видит вход/выход, Если же ссылки, то можно так
Код
C++ (Qt)
void bulls_and_cows(int iFirst, int iSecond, int & oBulls, int & oCows)
 

Решил первые переменные немного дополнить:
Код
C++ (Qt)
void bulls_and_cows(int firstNumber, int secondNumber, ...)
 

Если переменные используются для выхода, то лучше отметить это, указав букву 'o':
Код
C++ (Qt)
int readData(const std::string & fileName, int & oFirstNumber, int & oSecondNumber);
 

Если название функции "прочитатьДанные" readData(const std::string & fileName, ...), то понятно, что имя входного файла нужно передать, поэтому пишу просто: fileName

Считаю, что в следующей функции уточнения излишни (так как мы записываем в файл, то что передаём) и можно просто написать число быков и число коров: int nBulls, int nCows
Код
C++ (Qt)
int writeResult(const std::string & fileName, int nBulls, int nCows);
 

Как и здесь:
Код
C++ (Qt)
int showError(int err, const std::string & fileName);
 

А вот в следующей функции, как-то не очень смотрятся переменные: nBulls и nCows если пометить, что они используются для выхода: int & onBulls, int & onCows

Код
C++ (Qt)
void bulls_and_cows(int firstNumber, int secondNumber, int & onBulls, int & onCows);
 

Можно конечно и так написать: o_nBulls, o_nCows, но это не очень хорошо смотрится. Или же так: oBulls, oCows. Но а что если я перед переменной хочу букву поставить, которая в данном случае обозначает "количество": nBulls


Название: Re: Тренировка навыков быстрого программирования
Отправлено: OKTA от Март 05, 2014, 14:03
Чем мой вариант не устраивает?  ;D


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 05, 2014, 14:06
Чем мой вариант не устраивает?  ;D

Я до него ещё не добрался :) Не могу всё сразу :)

Куча разных дел, приходится переключаться с одного на другое.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: OKTA от Март 05, 2014, 14:07
Так он как раз избавит от проблемы с добавлением буковок  ;D


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 05, 2014, 14:08
А этот способ только для Windows?


Название: Re: Тренировка навыков быстрого программирования
Отправлено: OKTA от Март 05, 2014, 14:11
для всего конечно  ;)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 05, 2014, 14:16
для всего конечно  ;)

Сначала со следующими вариантами хочу разобраться :)

Решил, что лучше отказаться от буквы 'n' для обозначения количества. И для возвращаемых переменных из фукнций писать: oBulls

Правда, тогда получается, что если эти переменные - это входные данные для функции, то их нужно передавать так: bulls, cows, то есть писать с маленькой буквы.

Для входа: oBulls, oCows
Для выхода: bulls, cows

Ну либо так:
Для входа: oBulls, oCows
Для выхода: nBulls, nCows

Правда в последнем случае получается небольшая путанница. Как будто буквы 'o' и 'n' противоположенны друг другу. Поэтому лучше так:
Для входа: oBulls, oCows
Для выхода: bulls, cows


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Bepec от Март 05, 2014, 14:18
А есть ещё методика (непомню кого), где пишут явно inBulls, outBulls.
PS выбирать надо как тебе нравится.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Март 05, 2014, 14:20
Можно конечно и так написать: o_nBulls, o_nCows, но это не очень хорошо смотрится. Или же так: oBulls, oCows. Но а что если я перед переменной хочу букву поставить, которая в данном случае обозначает "количество": nBulls
oNumBulls (Cows), префикс "n" проблематичен. Если аргумент подается по НЕконстантой ссылке - и так ясно что ожидается его заполнение/изменение. Другое дело что это не поможет вызывающему, напр
Код
C++ (Qt)
bulls_and_cows(first, second, nBulls, nCows);
Где вход и выход? Пока неясно, нужно лезть в прототип ф-ции (а это время)
Код
C++ (Qt)
bulls_and_cows(first, second, &nBulls, &nCows);
A так? Да, внутри указатель может чуть менее удобен, но зато куда яснее на вызове. Библия рекомендует этот вариант

Но в конце-концов все это - дело вкуса. Опять Вы песиками увлеклись :) А ведь "содержательная часть" провалена капитально.

Чем мой вариант не устраивает?  ;D
Да тем что он невыносимо длинный  :) Для API/экспорта - согласен, есть смысл, но в каждой рабочей ф-ции так делать вряд ли кто будет


Название: Re: Тренировка навыков быстрого программирования
Отправлено: OKTA от Март 05, 2014, 14:27
А если вход и выход в одном аргументе?  ;D


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Old от Март 05, 2014, 14:31
Библия рекомендует этот вариант
Про какую библию вы все время говорите?


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 05, 2014, 15:56
Я определился с именами переменных.

1) Если в программе есть имена входного и выходного файла, то лучше это отметить:
Код
C++ (Qt)
int main(int argc, char** argv) {
   // ...
   std::string iFileName = "input.txt";
   // ...
   std::string oFileName = "output.txt";
   // ...
}

2) В принимающей функции решил отказаться от каких-либо букв, а писать названия полностью, например: numberOfBulls

3) Решил отказаться от букв 'i' и 'o', так как, если ссылка НЕ константная, то и так понятно, что переменная используется для выходных значений:
Код
C++ (Qt)
void bulls_and_cows(int firstNumber, int secondNumber, int &numberOfBulls, int &numberOfCows);
 

4) Прижимаю значок '&' к имени переменной, как написано в руководстве: http://qt-project.org/wiki/Qt_Coding_Style_Russian

Цитировать
Всегда ставьте один пробел после ‘*’ или ‘&’, если они стоят перед описанием типов. Но никогда не ставьте пробелы после ‘*’ или ‘&’ и именем переменной.
Код
C++ (Qt)
    char *x;
    const QString &myString;
    const char * const y = "hello";
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 05, 2014, 16:01
...куда прижимать значок '&'?

По этому поводу можно почитать вот это (http://qt-project.org/wiki/Qt_Coding_Style).

Вот за это отдельное спасибо! :)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 05, 2014, 16:06
Очень странно здесь написано: http://qt-project.org/wiki/Qt_Coding_Style_Russian (http://qt-project.org/wiki/Qt_Coding_Style_Russian)

Пишут, что:
Цитировать
Функции и переменные должны именоваться с прописной буквы, а если имя переменной или функции состоит из нескольких слов, то первое слово должно начинаться с прописной буквы, остальные – со строчных.

Прописная - это значит с большой буквы, то есть имена переменных они рекомендуют писать с большой буквы. А сами пишут с маленькой:
Код
C++ (Qt)
       // А так - правильно
       int height;
       int width;
       char *nameOfThis;
       char *nameOfThat;
 



Название: Re: Тренировка навыков быстрого программирования
Отправлено: OKTA от Март 05, 2014, 16:13
неправильный перевод)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 05, 2014, 16:15
Да, скорее всего, перевод неверный :)

По ссылке выше, ещё такое написано:
Цитировать
Public-классы начинаются с буквы ‘Q’ (QRgb)
Что такое "public-классы"? А бывают ещё "private-классы"?


Название: Re: Тренировка навыков быстрого программирования
Отправлено: LisandreL от Март 05, 2014, 16:18
Собственно:
Variables and functions start with a lower-case letter. Each consecutive word in a variable’s name starts with an upper-case letter


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 05, 2014, 16:21
LisandreL, спасибо! Теперь вижу. Нужно было просто переключить на английский и сравнить :)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Март 05, 2014, 17:55
Ну если уж разговор о "каллиграфии" то упомянем еще одну популярную вещь
Код
C++ (Qt)
void MyList::scrollToNode( int index, bool selectIt );
Что здесь может быть плохого  ???


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 06, 2014, 06:05
4) Неуемное использование std:: Чем не устраивал простенький char[4] (вместо векторов)? Да, это не общее решение - но нужна ли здесь какая-то общность? С др стороны по скорости "просто массив" заметно выигрывает.

А на сколько быстрее? Может быть прирост будет настолько мизерный, что им можно принебречь, учитывая современные процессоры?

STL уже сам по себе быстрый по сравнению с другими языками. Вот здесь написано: http://acm.timus.ru/help.aspx?topic=java
Цитировать
Решения на Java почти всегда работают достаточно большое время и требуют много памяти по сравнению с другими языками независимо от сложности задачи. Такова особенность этого языка. Но, тем не менее, гарантируется, что почти все задачи на Timus Online Judge могут быть сданы на Java без особых проблем по сравнению с другими языками. Вот список всех задач, для которых это не гарантируется: 1220, 1275, 1306.

И вот здесь о скорости и памяти программа на C#: http://acm.timus.ru/help.aspx?topic=csharp
Цитировать
Решения на C# по времени работы и по объему используемой памяти сравнимы с решениями на Java. Поэтому, почти все задачи на Timus Online Judge могут быть сданы на C# без особых проблем по сравнению с C/C++ и Pascal. Для решения следующих задач лучше не использовать Java и C#: 1220, 1275, 1306.

Вот здесь я прочитал про STL: http://acm.timus.ru/help.aspx?topic=cpp
Цитировать
STL — стандартная библиотека шаблонов (Standard Template Library), неотъемлемая часть C++, предоставляющая в распоряжение программиста набор контейнеров, итераторов и алгоритмов. Умелое использование этой библиотеки помогает сократить объем кода и уменьшить время на написание программы.

Таким образом, я хочу научиться писать программы с наименьшим количеством строк кода, используя алгоритмы и контейнеры STL, как можно эффективнее.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: OKTA от Март 06, 2014, 08:11
Так быстро писать программы или писать быстрые программы?  ;D
Программа на Си для этих быков и коров будет работать точно быстрее и если при единичном запуске это заметно не будет, то представьте запуск программы 1000 раз, 1000000 раз подряд - здесь уже малейшее ускорение алгоритма будет играть огромную роль. Конечно зависит от целей и задач программы, но в случаях, когда можно обойтись без доп.средств (типа STL) - не стоит к ним обращаться. Ты же не будешь каждый раз браться за шуруповерт, когда надо будет закрутить винтик - удобнее, быстрее и ювелирнее будет взяться за отверточку  ;D Да, несомненно, шуроповерт ускоряет закручивание длинных шурупов, но если шурупы маленькие - больше времени за этим шуруповертом идти ;D Для большего интереса - возьми программу API MOnitor и посмотри, сколько вызовов системных функций делает винда при открытии какого-нибудь файла к примеру - офигеешь  ;D


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Old от Март 06, 2014, 08:22
Таким образом, я хочу научиться писать программы с наименьшим количеством строк кода, используя алгоритмы и контейнеры STL, как можно эффективнее.
Если вы заранее знаете длину вектора, то рекомендую сразу создавать вектор указанной длины или резервировать необходимое количество памяти. Это исключит ненужные перераспределения памяти и копирования.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 06, 2014, 08:24
Программа на Си для этих быков и коров будет работать точно быстрее

У меня есть знакомый, который всю жизнь (ему уже больше 50) пишет на ассемблере для микроконтроллеров. Когда однажды ему предложили писать на Си он приводил много аргументов, почему на Си программы медленнее, чем на ассемблере, и сколько мусора создаёт компилятор Си. Для написания программ для ПК он использует исключительно Си и WinAPI. Так компилятор C++ (и любой фреймворк) генерирует много лишнего кода.

Вот что Линус Торвальдс написал о языке C++:

Цитировать
C++ - ужасный язык. Еще более ужасным его делает тот факт, что его использует множество неквалифицированных программистов, причем там, где с его помощью проще всего создать полнейшее фуфло. Честно говоря, даже если язык C использовался бы только для того, чтобы держать в отдалении программистов на C++, это само по себе послужило бы достаточным оправданием использования этого языка.Другими словами, выбор языка C является единственным разумным выбором. Я пришел к выводу, что программист, который предпочел бы при написании какой-либо программы использовать язык C++, а не C, скорее всего, принадлежит к такому типу программистов, которых я бы предпочел выгнать вон, так, чтобы они не смогли прийти и испортить проект, которым я занимаюсь. C++ является причиной плохих проектных решений. Вы неизбежно начинаете использовать «изящные» возможности таких библиотек языка, как STL, Boost и другую подобную ерунду, которая может «помочь» вам программировать, однако добиваетесь этим только:
- бесконечного геморроя, когда они не работают (и каждый, кто скажет мне, что STL и, в особенности, Boost, стабильны и переносимы, просто несет полный бред, и это даже не смешно).
- создания неэффективных, оторванных от жизни программных моделей; в результате через пару лет вы замечаете, что некоторые абстракции не слишком эффективны, однако весь ваш код уже находится в зависимости от всех этих изящных объектных моделей, и вы не можете исправить его, не переписав при этом всё приложение.
Другими словами, единственный способ использовать хороший, эффективный, системный и переносимый C++ заключается в том, чтобы ограничить себя теми возможностями, которые в принципе доступны в языке C. Кроме того, использование языка C означает, что никто не испортит ваш проект, и вы сможете найти кучу программистов, которые действительно разбираются в низкоуровневых проблемах и не испортят все дело какой-нибудь идиотской объектно-моделируемой чепухой.

P.S. Вот оригинал его письма: http://harmful.cat-v.org/software/c++/linus
P.S.S. Критика письма: http://dshevchenko.biz/ru/content/%D0%BB%D0%B8%D0%BD%D1%83%D1%81-%D1%82%D0%BE%D1%80%D0%B2%D0%B0%D0%BB%D1%8C%D1%81-%D0%BF%D1%80%D0%BE%D1%82%D0%B8%D0%B2-c-%D0%BC%D0%BE%D0%B9-%D0%BE%D1%82%D0%B2%D0%B5%D1%82

Так быстро писать программы или писать быстрые программы?  ;D

Я хочу писать именно быстро, и пусть они работают настолько быстро насколько позволит STL :)

Таким образом, я хочу научиться писать программы с наименьшим количеством строк кода, используя алгоритмы и контейнеры STL, как можно эффективнее.
Если вы заранее знаете длину вектора, то рекомендую сразу создавать вектор указанной длины или резервировать необходимое количество памяти. Это исключит ненужные перераспределения памяти и копирования.


Отличное замечание! Спасибо большое! Исправил:

Код
C++ (Qt)
void bulls_and_cows(int firstNumber, int secondNumber, int & numberOfBulls, int & numberOfCows) {
   // ...
   const std::size_t nsize = 4;
 
   std::vector<int> vec_first(nsize);
   std::vector<int> vec_second(nsize);
   // ...
}
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Март 06, 2014, 11:02
А на сколько быстрее? Может быть прирост будет настолько мизерный, что им можно принебречь, учитывая современные процессоры?
Сожалею что Вы уже начинаете прибегать к 100% типовым аргументам говнокодера  :'(
Считать надо не "НАсколько" а "ВО сколько". У Вас  использование вектора снижает скорость минимум в 2 раза, т.к. расчетная часть очень быстрая - бОльшая часть времени будет потрачена на вызываемый вектором malloc.

Таким образом, я хочу научиться писать программы с наименьшим количеством строк кода, используя алгоритмы и контейнеры STL, как можно эффективнее.
"std не дураки придумали. Поэтому использовать std = хорошо, и надо выучить его получше". Этот подход очень популярен :) Беда в том что решения "с обильным использованием std" очень часто оказываются неадекватны задаче, потому что человек нацелен на то "как найти это в std" вместо того чтобы думать своей головой.

Хорошо, вот Вы хотите сделать "обязательно с std". Тогда можно было напр так
Код
C++ (Qt)
void CalcBullsCows( const TVector & v1, const TVector & v2, int & numBulls, int & numCows )
{
for (size_t i = 0; i < v2.size(); ++i) {
 TVector:::const_iterator it = std::find(v1.begin(), v1.end(), v2[i]);
 if (it == v1.end()) continue;
 if (std::distance(v1.begin(), it) == i)
  ++numBulls;
 else
  ++numCows;
}
}
Этот код примерно равноценен сишному, и все равно предполагается использование линейного контейнера (иначе std::distance печален). Ну так никто не мешал Вам подойти принципиально и написать для любого контейнера, напр так
Код
C++ (Qt)
template <class Cont1, class Cont2>
void CalcBullsCows( const Cont1 & v1, const Cont2 & v2, int & numBulls, int & numCows )
{
..
}
 
Общий алгоритм - значит общий, в этом есть смысл. А у Вас что? Развели сопли, тут же контейнеры создаете, тут же и считаете. Типа "чем больше std насую - тем круче". Впрочем не Вы первый/последний  :)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 17, 2014, 18:08
Подскажите, пожалуйста, почему не работает enum

Я заменил вот этот код:

Код
C++ (Qt)
int showError(int errorCode, const std::string& fileName) {
   switch (errorCode) {
   case 1:
       std::cerr << "Error: cannot open the file " << fileName.c_str() << std::endl;
       break;
   case 2:
       std::cerr << "Error: cannot write to the file " << fileName.c_str() << std::endl;
       break;
   case 3:
       std::cerr << "Error: incorrect data in the file " << fileName.c_str() << std::endl;
       break;
   default:
       std::cerr << "Error code: " << errorCode << "; file name: " << fileName.c_str() << std::endl;
       break;
   }
 
   return errorCode;
}
 

Вот на этот:

Код
C++ (Qt)
enum ErrorType {
   errCannotOpenFile,
   errCannotWriteToFile,
   errIncorrectData
};
 
//...
 
int showError(int errorCode, const std::string& fileName) {
   switch (errorCode) {
   case ErrorType::errCannotOpenFile:
       std::cerr << "Error: cannot open the file " << fileName.c_str() << std::endl;
       break;
   case ErrorType::errCannotWriteToFile:
       std::cerr << "Error: cannot write to the file " << fileName.c_str() << std::endl;
       break;
   case ErrorType::errIncorrectData:
       std::cerr << "Error: incorrect data in the file " << fileName.c_str() << std::endl;
       break;
   default:
       std::cerr << "Error code: " << errorCode << "; file name: " << fileName.c_str() << std::endl;
       break;
   }
 
   return errorCode;
}
 

Выдаёт такие ошибки:
Цитировать
main.cpp:118: error: 'ErrorType' is not a class or namespace
     case ErrorType::errCannotOpenFile:
            ^


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 17, 2014, 18:15
Нашёл ошибку :)

Нужно вместо: ErrorType::errIncorrectData

Написать: errIncorrectData


Название: Re: Тренировка навыков быстрого программирования
Отправлено: kambala от Март 17, 2014, 19:13
в C++11 уже можно и ErrorType::errIncorrectData насколько я помню


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 17, 2014, 19:33
в C++11 уже можно и ErrorType::errIncorrectData насколько я помню

Ага, спасибо! Действительно - можно :)

В .pro надо написать:
Код
C++ (Qt)
QMAKE_CXXFLAGS += -std=c++11
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Март 18, 2014, 05:07
Код
C++ (Qt)
int showError(int errorCode, const std::string& fileName) {
   switch (errorCode) {
   case ErrorType::errCannotOpenFile:
       std::cerr << "Error: cannot open the file " << fileName.c_str() << std::endl;
       break;
 
c_str излишне, cerr умеет выводить std::string. Также откуда Вы возьмете fileName если ошибка не связана с файлом? Гибче так
Код
C++ (Qt)
int showError(int errorCode, const std::string& fileName = std::string());
 
Или так
Код
C++ (Qt)
int showError(int errorCode, const char * fileName = 0);
int showError(int errorCode, const char * msg1 = 0, const char * msg2 = 0);
 
Здесь придется чуть повозиться (просто так fileName не напечатать), но возможностей больше. И, строго говоря, "Error: cannot open the file " не есть хорошо, строки-константы должны грузиться из ресурсов


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 18, 2014, 06:05
Igors, огромное спасибо! Возьму на вооружение :)

Я так и не понял, зачем функция showError() возвращает код ошибки, который она и принимает? Это может иметь смысл?


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Март 18, 2014, 06:11
Я так и не понял, зачем функция showError() возвращает код ошибки, который она и принимает? Это может иметь смысл?
Пример
Код
C++ (Qt)
if (!veс.size()) {
ShowError(errNoData, "not enough data");
return;
}
 
if (!veс.size())
return ShowError(errNoData, "not enough data");
 
Второй вариант симпатичнее


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 18, 2014, 09:18
Посмотрите, пожалуйста, на следующий код. Если у нас файл не открылся, а мы его закрываем в этом нет ничего страшного?

Код
C++ (Qt)
enum ErrorType {
   errCannotOpenFile,
   errCannotWriteToFile,
   errIncorrectData,
   errNo
};
 
// ...
 
int readData(const QString & fileName, QString & data) {
   QFile iFile(fileName);
 
   ErrorType errorType;
 
   if (!iFile.open(QIODevice::ReadOnly)) {
       errorType = ErrorType::errCannotOpenFile;
   } else {
       data = iFile.readAll();
       errorType ErrorType::errNo;
   }
 
   iFile.close();
   return errorType;
}
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: OKTA от Март 18, 2014, 09:23
Почему бы сразу не сделать return в том месте, где возникать должна ошибка открытия?


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Johnik от Март 18, 2014, 09:27
а почему бы не сделать тогда так:
Код
C++ (Qt)
int readData(const QString & fileName, QString & data) {
   QFile iFile(fileName);
 
   ErrorType errorType;
 
   if (!iFile.open(QIODevice::ReadOnly)) {
       errorType = ErrorType::errCannotOpenFile;
   } else {
       data = iFile.readAll();
       errorType ErrorType::errNo;
       iFile.close();
   }
 
   return errorType;
}
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 18, 2014, 09:30
Да, вот этот вариант мне подходит. Люблю, когда один выход из функции :)

Можно, конечно, как OKTA предложил:

Код
C++ (Qt)
int readData(const QString & fileName, QString & data) {
   QFile iFile(fileName);
 
   if (!iFile.open(QIODevice::ReadOnly)) {
       return ErrorType::errCannotOpenFile;
   } else {
       data = iFile.readAll();
       iFile.close();
       return ErrorType::errNo;
   }
}
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: OKTA от Март 18, 2014, 09:37
Возвращать значение сразу удобно, когда после ошибки еще куча кода, которому не имеет смысла работать в случае ошибки.
Разработчики винды, к примеру, знаю не гнушаются ставить перед последним return метку типа "cleanup:" и после нее проводить нужные операции завершения, если они нужны. А в местах, где может возникать ошибка, ставят макрос типа #define CHECK_STATUS(Status) if(!NT_SUCCESS(Status)) {goto cleanup;}


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Old от Март 18, 2014, 09:52
Разработчики винды
Ох далеко не лучший пример. :)

Выход по goto может заметно сократить функцию в С, потому что очистка всех ресурсов будет происходить в одном месте.
В С++ это не нужно, потому что можно и нужно использовать RAII.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Март 18, 2014, 09:58
1) Уберите close(), оно вообще не нужно, деструктор сам закроет

2)
Код
C++ (Qt)
       errorType = ErrorType::errCannotOpenFile;
 
А здесь переборщили. Вместо errorType лучше error или даже err, здесь "Type" только сбивает. Квалифицировать имя - ну можно, но необязательно, на мой вкус лучше так
Код
C++ (Qt)
enum {
   errNone     = 0,
   errFileOpen = -1000,
   errFileWrite = -1001,
 
   errDataBad = -5000,
   errDataNoFormat = -5001,
};
 
Префикс err достаточно выразителен сам по себе, не вижу с чем он заклинит. Может "err_" еще лучше. Код errNone обязательно ноль. А коды ошибок лучше распихать по группам.

3)
Люблю, когда один выход из функции :)
Тогда не забывайте присваивать переменой ошибки начальное значение  :)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 18, 2014, 10:31
А что означает: errDataNoFormat?

Я вот так хочу писать:

Код
C++ (Qt)
/**
* Коды ошибок
*/

enum ErrorType {
   errNone = 0,            /**< Нет ошибок */
   errFileOpen = -1000,    /**< Ошибка отрытия файла */
   errFileWrite = -1001,   /**< Ошибка записи в файл */
 
   errDataBad = -5000      /**< Некорректные данные в файле */
};
 

А с помощью Doxywizard можно сгерерировать такую документацию для своего проекта, как в этом примере: http://qwt.sourceforge.net/class_qwt_plot.html

В документации для Goxygen вот так написано:
Код
C++ (Qt)
/**
*  A test class. A more elaborate class description.
*/

class Test{
public:    
   /**      
    * An enum.    
    * More detailed enum description.    
    */
   
   enum TEnum {          
       TVal1, /**< enum value TVal1. */            
       TVal2, /**< enum value TVal2. */            
       TVal3  /**< enum value TVal3. */          
   }        *enumPtr, /**< enum pointer. Details. */      
   enumVar;  /**< enum variable. Details. */            
   /**      
    * A constructor.      
    * A more elaborate description of the constructor.      
    */
     
   Test();      
   /**      
    * A destructor.      
    * A more elaborate description of the destructor.      
    */
   
   ~Test();          
   /**      
    * a normal member taking two arguments and returning an integer value.      
    * @param a an integer argument.      
    * @param s a constant character pointer.      
    * @see Test()      
    * @see ~Test()      
    * @see testMeToo()      
    * @see publicVar()      
    * @return The test results      
    */
     
   int testMe(int a,const char *s);            
   /**      
    * A pure virtual member.      
    * @see testMe()      
    * @param c1 the first argument.      
    * @param c2 the second argument.      
    */
     
   virtual void testMeToo(char c1,char c2) = 0;        
   /**        
    * a public variable.      
    * Details.      
    */
     
   int publicVar;            
   /**      
    * a function variable.      
    * Details.      
    */
     
   int (*handler)(int a,int b);
};
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 18, 2014, 11:05
Я сейчас открыл исходники Qwt (qwt_plot.h). Там enum вот так оформляется:
Код
C++ (Qt)
public:
   //! \brief Axis index
   enum Axis
   {
       //! Y axis left of the canvas
       yLeft,
 
       //! Y axis right of the canvas
       yRight,
 
       //! X axis below the canvas
       xBottom,
 
       //! X axis above the canvas
       xTop,
 
       //! Number of axes
       axisCnt
   };
 

В документации это потом выглядит вот так:
(http://i6.pixs.ru/storage/3/3/9/156png_8448659_11285339.png)

Ну и пример из документации Doxygen нужно другой взять (предыдущий был Java style, а этот Qt style):

Цитировать
Here is an example of a documented piece of C++ code using the Qt style:

Код
C++ (Qt)
/*!  A more elaborate class description.*/
class Test {
public:
   //! An enum.    
 
   /*! More detailed enum description. */
   enum TEnum {
       TVal1, /*!< Enum value TVal1. */
       TVal2, /*!< Enum value TVal2. */
       TVal3 /*!< Enum value TVal3. */
   }
   //! Enum pointer.        
   /*! Details. */
   *enumPtr,
   //! Enum variable.        
   /*! Details. */
   enumVar;
 
   //! A constructor.    
   /*!      
     A more elaborate description of the constructor.    
    */

   Test();
   //! A destructor.    
   /*!      
     A more elaborate description of the destructor.    */

   ~Test();
 
   //! A normal member taking two arguments and returning an integer value.    
   /*!      
     \param a an integer argument.      
     \param s a constant character pointer.      
     \return The test results      
     \sa Test(), ~Test(), testMeToo() and publicVar()    
    */

   int testMe(int a, const char *s);
   //! A pure virtual member.    
   /*!      
     \sa testMe()      
     \param c1 the first argument.      
     \param c2 the second argument.    
    */

   virtual void testMeToo(char c1, char c2) = 0;
   //! A public variable.    
   /*!      
     Details.    
    */

   int publicVar;
 
   //! A function variable.    
   /*!      
     Details.    
    */

   int (*handler)(int a, int b);
};
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Март 18, 2014, 11:28
В цитируемых Вами примерах enum'ы внутри классов. С каким классом можно связать напр errDataBad? Не видно с каким, ну и не нужно навязывать класс (или пр-во имен), слава богу это не жаба. В глобальных enum нет ничего плохого если они хорошо продуманы. Вообще не стремитесь "навернуть", часто (если не всегда) можно сделать проще, напр
Код
C++ (Qt)
typedef int TErrCode;
 
int DoSomething1( void );  // что оно вернет - хз
TErrCode DoSomething2( void );  // ага!
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Old от Март 18, 2014, 11:39
В глобальных enum нет ничего плохого если они хорошо продуманы.
Плохого в них ничего и нет, но только неименованные не позволяют контролировать на этапе компиляции, то что позволяют именованные, а именно:
Код
C++ (Qt)
void showError( int err )
{
}
 
void showError( ErrorType err )
{
}
 
Вот в первом случае мне компилятор разрешит передать в качестве параметра любую фигню, в отличие от второго варианта.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Март 18, 2014, 12:33
Вот в первом случае мне компилятор разрешит передать в качестве параметра любую фигню, в отличие от второго варианта.
Часто это ничем особенным не грозит, напр в данном случае распечатается код неизвестной ошибки. А вот иметь всюду ErrorType:: все-таки отягощает текст. Впрочем, все это уже вкусовщина  :)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Old от Март 18, 2014, 12:39
Часто это ничем особенным не грозит
Как правило любые ошибки в программах ничем особенным не грозят. :)

А вот скажем, если в enum находятся режимы работы, то его использование в качестве параметра, может избавить от проверки входных параметров.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 18, 2014, 12:54
Я имел ввиду, как понять без комментариев, что означает: errDataNoFormat. На самом деле, что это означает?

Лучше комментарии писать. А doxygen позволит сгенерировать документацию:
Код
C++ (Qt)
//! Коды ошибок
enum ErrorType {
   //! Нет ошибок
   errNone = 0,
 
   //! Ошибка открытия файла
   errFileOpen = -1000,
 
   //! Ошибка записи в файл
   errFileWrite = -1001,
 
   //! Некорректные данные в файле
   errDataBad = -5000
};
 

Всё же я соглашусь с OKTA, что нужно сразу возвращать, чтобы видно было, что программа дальше не будет выполняться:
Код
C++ (Qt)
int readData(const QString &fileName, QString &data ) {
   QFile iFile(fileName);
   if ( !iFile.open( QIODevice::ReadOnly ) ) {
       return ErrorType::errFileOpen;
   } else {
       data = iFile.readAll();
       iFile.close();
       return ErrorType::errNone;
   }
}
 

Код
C++ (Qt)
int showError(int errorCode, const char * fileName = 0);
int showError(int errorCode, const char * msg1 = 0, const char * msg2 = 0);
 
Здесь придется чуть повозиться (просто так fileName не напечатать), но возможностей больше. И, строго говоря, "Error: cannot open the file " не есть хорошо, строки-константы должны грузиться из ресурсов

Что значит просто так не напечатать? А как строку в ресурсах создать?

Код
C++ (Qt)
int showError(const QString & fileName, ErrorType errorCode) {
   switch (errorCode) {
   case ErrorType::errFileOpen:
       std::cerr << "Error: cannot open the file " << fileName.toStdString() << std::endl;
       break;
   case ErrorType::errFileWrite:
       std::cerr << "Error: cannot write to the file " << fileName.toStdString() << std::endl;
       break;
   case ErrorType::errDataBad:
       std::cerr << "Error: incorrect data in the file " << fileName.toStdString() << std::endl;
       break;
   default:
       std::cerr << "Error code: " << errorCode << "; file name: " << fileName.toStdString() << std::endl;
       break;
   }
 
   return errorCode;
}
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Old от Март 18, 2014, 12:56
Всё же я соглашусь с OKTA, что нужно сразу возвращать, чтобы видно было, что праграмма дальше не будет выполняться:
Лучше после возврата не использовать else, это избыточно:

Код
C++ (Qt)
int readData(const QString &fileName, QString &data ) {
   QFile iFile(fileName);
   if ( !iFile.open( QIODevice::ReadOnly ) )
       return ErrorType::errFileOpen;
 
   data = iFile.readAll();
   return ErrorType::errNone;
}
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 18, 2014, 12:59
Да, Вы правы! Спасибо! :)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Old от Март 18, 2014, 13:04
Да, Вы правы! Спасибо! :)
И как правило, в компаниях используется свой стиль обязательный к использованию, поэтому все рекомендации в этой тебе вам могут не пригодиться. ;)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 18, 2014, 13:10
Сейчас вот так переписал:

Код
C++ (Qt)
//! Коды ошибок
enum ErrorType {
   //! Нет ошибок
   errNone = 0,
 
   //! Ошибка открытия файла
   errFileOpen = -1000,
 
   //! Ошибка записи в файл
   errFileWrite = -1001,
 
   //! Некорректные данные в файле
   errDataBad = -5000
};
 
ErrorType readData( const QString &fileName, QString &data );
ErrorType writeResult( const QString &fileName, QString &data );
void showData( const QString &data );
ErrorType showError( const QString &fileName, ErrorType errorCode );
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 18, 2014, 14:03
Я думаю, что тут уже нечего усложнять :) Единственное, что... есть мысль сделать через исключения, но пока без них. Запись в файл:

Код
C++ (Qt)
/*!
* Записываем данные в файл
* \param fileName Имя файла, в который будем записывать
* \param data Данные, которые будут записаны в файл
* \return Код ошибки
*/

ErrorType writeResult( const QString &fileName, QString &data ) {
   QFile file(fileName);
 
   if ( !file.open( QIODevice::WriteOnly ) )
       return ErrorType::errFileOpen;
 
   QTextStream stream(&file);
   stream << data;
   file.close();
 
   if (stream.status() != QTextStream::Ok)
       return ErrorType::errFileWrite;
 
   return ErrorType::errNone;
}
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Март 18, 2014, 14:10
Я имел ввиду, как понять без комментариев, что означает: errDataNoFormat. На самом деле, что это означает?
"Ошибка данные не форматированы"  :) Это я просто привел для примера. Как и предыдущая, начинается с errData, так что какое-то представление читающий сразу получает: ошибка в данных. Дальше (что за NoFormat) уже по задаче. А комментарии... полагаю скоро Вам надоест их рисовать
Код
C++ (Qt)
errDataBad,  // wrong (invalid) data
"Масло масляное", такой комментарий ничего не проясняет, он просто не нужен т.к. имя говорит само за себя.

И не надо строить наполеновских планов с Doxygen и.т.п. До этого еще дистанция такого огромного размера  :)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Old от Март 18, 2014, 14:21
И не надо строить наполеновских планов с Doxygen и.т.п. До этого еще дистанция такого огромного размера  :)
До чего "этого" эта дистанция?
Doxygen простой и удобный инструмент, который можно использовать всегда и везде, а не ждать программу своей жизни. :)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 18, 2014, 16:10
Следующий оператор if не выполняется в случае: (errorCode != 0). Почему?

Код
C++ (Qt)
//! Error codes
enum ErrorType {
   //! None errors
   errNone = 0,
 
   //! Error of the opening of a file
   errFileOpen = -1000,
 
   //! Error of the writing of a file
   errFileWrite = -1001,
 
   //! Wrong data
   errDataBad = -5000
};
 
int main( int argc, char *argv[] ) {
   // ...
   ErrorType errorCode = ErrorType::errNone;
 
   // Read data from a file
   QString iFileName = QString( "input.txt" );
   errorCode = readData( iFileName, data );
   if ( !errorCode ) {
       showError( iFileName, errorCode );
   }
 
   // ...
}
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Old от Март 18, 2014, 16:17
Сейчас в примере написано: если нет ошибки (errorCode == 0), напечатать сообщение о ошибке.

Что значит не работает errorCode != 0?


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 18, 2014, 16:22
Тело оператора if не выполняется в случае отсутствия файла:
Код
C++ (Qt)
if ( !errorCode ) {
   showError( iFileName, errorCode );
}
 

И ещё вопрос. У меня функция main() возвращает: return a.exec( );

Могу ли я так написать (то есть вернуть ErrorType::errFileOpen):
Код
C++ (Qt)
int main( int argc, char *argv[] ) {
   QCoreApplication a( argc, argv );
   // ...
 
   if ( errorCode != ErrorType::errNone ) {
       return showError( iFileName, errorCode );
   }
 
   // ...
 
   return a.exec( );
}
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Old от Март 18, 2014, 16:25
Тело оператора if не выполняется в случае отсутствия файла:
Конечно, потому что оно будет выполняться при отсутствии ошибок (если errorCode == 0).

Могу ли я так написать (то есть вернуть ErrorType::errFileOpen):
Можете.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 18, 2014, 16:32
Закружился с этим выражением: !errorCode :) Понял. Спасибо!

Чтобы было понятнее, вот так написал:
Код
C++ (Qt)
if ( errorCode != ErrorType::errNone ) {
   return showError( iFileName, errorCode );
}
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: OKTA от Март 18, 2014, 16:38
Напиши просто if(errorCode) - читаться будет "если ошибка" грубо говоря, а if(!errorCode) - если не ошибка  :)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Igors от Март 18, 2014, 16:40
Могу ли я так написать (то есть вернуть ErrorType::errFileOpen):
Код
C++ (Qt)
 
   if ( errorCode != ErrorType::errNone ) {
       return showError( iFileName, errorCode );
   }
}
 
Вот без errorCode ф-ция showError точно не живет, а iFileName - хз, может и пустой быть. Так зачем ставить первостепенный аргумент вторым? Вообще незатейливый вариант
Код
C++ (Qt)
   if (error)
       return showError(error, iFileName);
 
мне нравится куда больше. Связавшись с ErrorType:: Вы конечно поступили "академически" правильно. Но выгода с той академичности когда еще будет, а таскать везде квалифицированное имя уже приходится  :)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Март 18, 2014, 17:13
С очерёдностью согласен. Имя бы ещё аргументом по умолчанию сделать. Ну, а ErrorType:: я всё же потаскаю. Выглядит солидно :) Да и хочеться к хорошему привыкать. Когда привыкаешь, то уже легче становится :)


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Апрель 03, 2014, 18:37
Спасибо вам огромное, форумчане! C вашей помощью я нашёл подход к оформлению задач. Этот подход использую во всех задачах здесь: www.acmp.ru Просто копирую код из задачи в задачу и немного меняю исходник (это, конечно, не касается содержательной части :) )

Поясню подход на примере самой первой задачи: http://acmp.ru/?main=task&id_task=1

Благодаря классам исключений, в main простой и аккуратный код:
Код
C++ (Qt)
int main() {
   std::string fileNameIn = "input.txt";
   int firstNumber = 0;
   int secondNumber = 0;
 
   try {
       readData( fileNameIn, firstNumber, secondNumber );
   } catch ( const FileError &e ) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   }
 
   int result = sum(firstNumber, secondNumber);
 
   std::string fileNameOut = "output.txt";
   try {
       writeResult( fileNameOut, result );
   } catch ( const FileError &e ) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   }
 
   return 0;
}

Я теперь сначала пишу заглушку, которая решает задачу, к примеру:
Код
C++ (Qt)
int sum(int firstNumber, int secondNumber) {
   return 0;
}

А потом тесты c помощью "Qt Unit Test". Всё согласно методологии TDD (сначала тесты, которые учитывают (описывают) всю функциональность, а после написания тестов - пишу саму функциональность):
Код
C++ (Qt)
   QTest::addColumn<int>("firstNumber");
   QTest::addColumn<int>("secondNumber");
   QTest::addColumn<int>("expected");
 
   QTest::newRow("sum_01") << 1 << 2 << 3;
   QTest::newRow("sum_02") << -1 << -2 << -3;
   QTest::newRow("sum_03") << -3 << 5 << 2;
   QTest::newRow("sum_04") << 5 << -3 << 2;
   QTest::newRow("sum_05") << -5 << 3 << -2;
 

В файле .pro проекта  "Qt Unit Test" надо писать путь к main.cpp SOURCES += ../acmp_0001_sum/main.cpp

А в main.cpp определить директиву #define TESTING чтобы можно было тестировать, а перед отправкой на сервер www.acmp.ru надо закомментировать эту строку #define TESTING. Вот как это выглядит:
Код
C++ (Qt)
//#define TESTING
#ifndef TESTING
// ...
int main() {
   // ...
}
#endif // TESTING
 
int sum(int firstNumber, int secondNumber) {
   int result = firstNumber + secondNumber;
   return result;
}
 

Вот весь код двух проектов (в одном решается задача, а в другом тесты для задачи)
acmp_0001_sum.pro
Код
C++ (Qt)
SOURCES += \
   main.cpp
 

main.cpp
Код
C++ (Qt)
//#define TESTING
#ifndef TESTING
 
#include <iostream>
#include <stdexcept>
#include <string>
#include <sstream>
#include <fstream>
 
class FileError : public std::runtime_error {
public:
 
   FileError( const std::string &fileIn ) : std::runtime_error( "" ), m_file( fileIn ) {
   }
 
   virtual const char* what( ) const throw() {
       return m_msg.c_str( );
   }
 
   std::string getFileName( ) const {
       return m_file;
   }
 
   virtual ~FileError() throw() {
 
   }
 
protected:
   std::string m_file;
   std::string m_msg;
};
 
class FileOpenError : public FileError {
public:
 
   FileOpenError( const std::string &fileNameIn ) : FileError( fileNameIn ) {
       m_msg = "Unable to open " + fileNameIn;
   }
};
 
class FileReadError : public FileError {
public:
 
   FileReadError( const std::string &fileNameIn, int lineNumIn ) :
   FileError( fileNameIn ), m_lineNum( lineNumIn ) {
       std::ostringstream ostr;
       ostr << "Error reading " << fileNameIn << " at line " << lineNumIn;
       m_msg = ostr.str( );
   }
 
   int getLineNum( ) const {
       return m_lineNum;
   }
 
protected:
   int m_lineNum;
};
 
class FileWriteError : public FileError {
public:
 
   FileWriteError( const std::string &fileNameIn ) : FileError( fileNameIn ) {
       m_msg = "Unable to write " + fileNameIn;
   }
};
 
void readData( const std::string &fileName, int &firstNumber, int &secondNumber )
throw (FileOpenError, FileReadError);
 
void writeResult( const std::string &fileName, int number )
throw (FileOpenError, FileWriteError);
 
int sum(int firstNumber, int secondNumber);
 
int main() {
   std::string fileNameIn = "input.txt";
   int firstNumber = 0;
   int secondNumber = 0;
 
   try {
       readData( fileNameIn, firstNumber, secondNumber );
   } catch ( const FileError &e ) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   }
 
   int result = sum(firstNumber, secondNumber);
 
   std::string fileNameOut = "output.txt";
   try {
       writeResult( fileNameOut, result );
   } catch ( const FileError &e ) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   }
 
   return 0;
}
 
void readData( const std::string &fileName, int &firstNumber, int &secondNumber )
throw ( FileOpenError, FileReadError ) {
   std::ifstream file;
   file.open( fileName.c_str( ) );
   if ( file.fail( ) ) {
       throw FileOpenError( fileName );
   }
 
   int lineNumIn = 0;
   if ( !( file >> firstNumber >> secondNumber ) ) {
       lineNumIn++;
       throw FileReadError( fileName, lineNumIn );
   }
}
 
void writeResult( const std::string &fileName, int number )
throw (FileOpenError, FileWriteError) {
   std::ofstream file;
   file.open( fileName.c_str( ) );
 
   if ( file.fail( ) ) {
       throw FileOpenError( fileName );
   }
 
   if ( !( file << number ) ) {
       throw FileWriteError( fileName );
   }
 
   file << std::endl;
}
#endif // TESTING
 
int sum(int firstNumber, int secondNumber) {
   int result = firstNumber + secondNumber;
   return result;
}
 
 

acmp_0001_sum_tests.pro
Код
C++ (Qt)
#-------------------------------------------------
#
# Project created by QtCreator 2014-04-03T19:03:48
#
#-------------------------------------------------
 
QT       += testlib
 
QT       -= gui
 
TARGET = tst_SumTests
CONFIG   += console
CONFIG   -= app_bundle
 
TEMPLATE = app
 
 
SOURCES += tst_SumTests.cpp
SOURCES += ../acmp_0001_sum/main.cpp
DEFINES += SRCDIR=\\\"$$PWD/\\\"

tst_SumTests.cpp
Код
C++ (Qt)
#include <QString>
#include <QtTest>
 
int sum(int firstNumber, int secondNumber);
 
class SumTests : public QObject
{
   Q_OBJECT
 
public:
   SumTests();
 
private Q_SLOTS:
   void testCase1_data();
   void testCase1();
};
 
SumTests::SumTests()
{
}
 
void SumTests::testCase1_data()
{
   QTest::addColumn<int>("firstNumber");
   QTest::addColumn<int>("secondNumber");
   QTest::addColumn<int>("expected");
 
   QTest::newRow("sum_01") << 1 << 2 << 3;
   QTest::newRow("sum_02") << -1 << -2 << -3;
   QTest::newRow("sum_03") << -3 << 5 << 2;
   QTest::newRow("sum_04") << 5 << -3 << 2;
   QTest::newRow("sum_05") << -5 << 3 << -2;
}
 
void SumTests::testCase1()
{
   QFETCH(int, firstNumber);
   QFETCH(int, secondNumber);
   QFETCH(int, expected);
 
   int actual = sum(firstNumber, secondNumber);
   QCOMPARE(actual, expected);
}
 
QTEST_APPLESS_MAIN(SumTests)
 
#include "tst_SumTests.moc"
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Апрель 05, 2014, 20:28
Я ещё усовершенствовал программу. Теперь функция может проверять свой аргумент.

Допустим мы хотим разработать функцию для решения задачи: http://acmp.ru/?main=task&id_task=3

Я назвал эту функцию: int five_and_five(int number). Она возвращает квадрат аргумента. В задаче сказано, что функция принимает аргумент, который заканчивается на цифру 5. А ещё есть ограничения диапазона значений аргумента: [5; 4*10^5]

Я решил смоделировать ситуацию, когда функция может контролировать свой входной аргумент и сообщать, если нарушено соглашение вызова.

Для этой функции хорошо бы подошли классы из стандартной библиотеки, унаследованные от std::logic_error: это std::invalid_argument и std::out_of_range: http://www.cplusplus.com/reference/stdexcept/logic_error/

Но тогда придёться писать текст сообщений об ошибках в функции five_and_five(), что совсем неудобно, так как в каждой тестируемой функции (если их будет много) придёться дублировать сообщения об ошибках). Поэтому я написал два класса исключений: InvalidArgument, OutOfRange унаследованные от третьего: LogicError, который в свою очередь унаследован от std::logic_error:
Код
C++ (Qt)
class LogicError : public std::logic_error {
public:
 
   LogicError( int argument ) : std::logic_error( "" ), m_argument( argument ) {
 
   }
 
   virtual const char *what( ) const throw () {
       return m_message.c_str( );
   }
 
   virtual ~LogicError( ) throw () {
 
   }
 
protected:
   int m_argument;
   std::string m_message;
};
 
class InvalidArgument : public LogicError {
public:
 
   InvalidArgument( int argument ) : LogicError( argument ) {
       std::stringstream stream;
       stream << argument;
       m_message = "Argument " + stream.str( ) + " mush be multiple of 5";
   }
};
 
class OutOfRange : public LogicError {
public:
 
   OutOfRange( int argument, int beginOfRange, int endOfRange ) : LogicError( argument ) {
       std::stringstream stream;
       std::string str_argument, str_beginOfRange, str_endOfRange;
 
       stream << argument;
       str_argument = stream.str();
       stream.str("");
 
       stream << beginOfRange;
       str_beginOfRange = stream.str();
       stream.str("");
 
       stream << endOfRange;
       str_endOfRange = stream.str();
       stream.str("");
 
       m_message = "Argument " + str_argument + " don't hit on the range [" +
               str_beginOfRange + ", " + str_endOfRange + "]";
   }
};
 

Пользователь функции five_and_five() может легко понять, какие исключения она выбрасывает. Для этого ему достаточно посмотреть на её объявление:
Код
C++ (Qt)
double fiveAndFive( int number ) throw (InvalidArgument, OutOfRange);
 

Так пользователь будет вызывать функцию в main():
Код
C++ (Qt)
   int result = 0;
   try {
       result = fiveAndFive(number);
   } catch ( const LogicError &e ) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   } catch ( ... ) {
       std::cerr << "Uncaught exception." << std::endl;
       return 1;
   }
 

Так выглядит сама функция:
Код
C++ (Qt)
double fiveAndFive( int number ) throw (InvalidArgument, OutOfRange) {
   if ( (number % 5) != 0 ) {
       throw InvalidArgument( number );
   }
 
   const int beginOfRange = 5;
   const int endOfRange = 400000;
   if ( (number < beginOfRange) || (endOfRange < number) ) {
       throw OutOfRange( number, beginOfRange, endOfRange );
   }
 
   double result = (double) number * (double) number;
   return result;
}
 

Вот решение задачи (здесь макрос "#define TESTING" нужен для переключения в режим тестирования с помощью QTest):
Код
C++ (Qt)
#include <stdexcept>
#include <string>
#include <sstream>
 
//#define TESTING
#ifndef TESTING
 
#include <iostream>
#include <fstream>
 
class FileError : public std::runtime_error {
public:
 
   FileError( const std::string &fileIn ) : std::runtime_error( "" ), m_file( fileIn ) {
   }
 
   virtual const char* what( ) const throw() {
       return m_msg.c_str( );
   }
 
   std::string getFileName( ) const {
       return m_file;
   }
 
   virtual ~FileError() throw() {
 
   }
 
protected:
   std::string m_file;
   std::string m_msg;
};
 
class FileOpenError : public FileError {
public:
 
   FileOpenError( const std::string &fileNameIn ) : FileError( fileNameIn ) {
       m_msg = "Unable to open " + fileNameIn;
   }
};
 
class FileReadError : public FileError {
public:
 
   FileReadError( const std::string &fileNameIn, int lineNumIn ) :
       FileError( fileNameIn ), m_lineNum( lineNumIn ) {
       std::ostringstream ostr;
       ostr << "Error reading " << fileNameIn << " at line " << lineNumIn;
       m_msg = ostr.str( );
   }
 
   int getLineNum( ) const {
       return m_lineNum;
   }
 
protected:
   int m_lineNum;
};
 
class FileWriteError : public FileError {
public:
 
   FileWriteError( const std::string &fileNameIn ) : FileError( fileNameIn ) {
       m_msg = "Unable to write " + fileNameIn;
   }
};
#endif // TESTING
 
class LogicError : public std::logic_error {
public:
 
   LogicError( int argument ) : std::logic_error( "" ), m_argument( argument ) {
 
   }
 
   virtual const char *what( ) const throw () {
       return m_message.c_str( );
   }
 
   virtual ~LogicError( ) throw () {
 
   }
 
protected:
   int m_argument;
   std::string m_message;
};
 
class InvalidArgument : public LogicError {
public:
 
   InvalidArgument( int argument ) : LogicError( argument ) {
       std::stringstream stream;
       stream << argument;
       m_message = "Argument " + stream.str( ) + " mush be multiple of 5";
   }
};
 
class OutOfRange : public LogicError {
public:
 
   OutOfRange( int argument, int beginOfRange, int endOfRange ) : LogicError( argument ) {
       std::stringstream stream;
       stream << argument << beginOfRange << endOfRange;
       std::string str_argument, str_beginOfRange, str_endOfRange;
       stream >> str_argument >> str_beginOfRange >> str_endOfRange;
 
       m_message = "Argument " + str_argument + " don't hit on the range [" +
               str_beginOfRange + ", " + str_endOfRange + "]";
   }
};
 
#ifndef TESTING
void readData( const std::string &fileName, int &number )
throw (FileOpenError, FileReadError);
 
void writeResult( const std::string &fileName, int result )
throw (FileOpenError, FileWriteError);
 
double fiveAndFive( int number ) throw (InvalidArgument, OutOfRange);
 
int main() {
   std::string fileNameIn = "input.txt";
   int number = 0;
 
   try {
       readData( fileNameIn, number );
   } catch ( const FileError &e ) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   } catch ( ... ) {
       std::cerr << "Uncaught exception." << std::endl;
       return 1;
   }
 
   int result = 0;
   try {
       result = fiveAndFive(number);
   } catch ( const LogicError &e ) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   } catch ( ... ) {
       std::cerr << "Uncaught exception." << std::endl;
       return 1;
   }
 
   std::string fileNameOut = "output.txt";
   try {
       writeResult( fileNameOut, result );
   } catch ( const FileError &e ) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   }
 
   return 0;
}
 
void readData( const std::string &fileName, int &number )
throw ( FileOpenError, FileReadError ) {
   std::ifstream file;
   file.open( fileName.c_str( ) );
   if ( file.fail( ) ) {
       throw FileOpenError( fileName );
   }
 
   int lineNumIn = 0;
   if ( !( file >> number ) ) {
       lineNumIn++;
       throw FileReadError( fileName, lineNumIn );
   }
}
 
void writeResult( const std::string &fileName, int result )
throw (FileOpenError, FileWriteError) {
   std::ofstream file;
   file.open( fileName.c_str( ) );
 
   if ( file.fail( ) ) {
       throw FileOpenError( fileName );
   }
 
   if ( !( file << result ) ) {
       throw FileWriteError( fileName );
   }
 
   file << std::endl;
}
#endif // TESTING
 
double fiveAndFive( int number ) throw (InvalidArgument, OutOfRange) {
   if ( (number % 5) != 0 ) {
       throw InvalidArgument( number );
   }
 
   const int beginOfRange = 5;
   const int endOfRange = 400000;
   if ( (number < beginOfRange) || (endOfRange < number) ) {
       throw OutOfRange( number, beginOfRange, endOfRange );
   }
 
   double result = (double) number * (double) number;
   return result;
}
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Апрель 06, 2014, 08:59
Следующий код неверный:
Код
C++ (Qt)
class OutOfRange : public LogicError {
public:
 
   OutOfRange( int argument, int beginOfRange, int endOfRange ) : LogicError( argument ) {
       std::stringstream stream;
       stream << argument << beginOfRange << endOfRange;
       std::string str_argument, str_beginOfRange, str_endOfRange;
       stream >> str_argument >> str_beginOfRange >> str_endOfRange;
 
       m_message = "Argument " + str_argument + " don't hit on the range [" +
               str_beginOfRange + ", " + str_endOfRange + "]";
   }
};
 

Я его заменил на:
Код
C++ (Qt)
class OutOfRange : public LogicError {
public:
 
   OutOfRange( int argument, int beginOfRange, int endOfRange ) : LogicError( argument ) {
       std::stringstream stream;
       std::string str_argument, str_beginOfRange, str_endOfRange;
 
       stream << argument;
       str_argument = stream.str();
       stream.str("");
 
       stream << beginOfRange;
       str_beginOfRange = stream.str();
       stream.str("");
 
       stream << endOfRange;
       str_endOfRange = stream.str();
       stream.str("");
 
       m_message = "Argument " + str_argument + " don't hit on the range [" +
               str_beginOfRange + ", " + str_endOfRange + "]";
   }
};
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: Old от Апрель 06, 2014, 09:09
Сделай те уже функции для перевода числа в строку и наоборот. :)
С шаблонами можно сделать две универсальные функции для любых чисел.


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Апрель 06, 2014, 11:07
Спасибо за идею :)

Ну, как дело дойдёт до double - сделаю. А пока для int:
Код
C++ (Qt)
std::string intToString( int number ) {
   std::stringstream stream;
   stream << number;
   return stream.str( );
}
 
class OutOfRange : public LogicError {
public:
 
   OutOfRange( int argument, int beginOfRange, int endOfRange ) : LogicError( argument ) {
       std::string str_argument, str_beginOfRange, str_endOfRange;
 
       str_argument = intToString( argument );
       str_beginOfRange = intToString( beginOfRange );
       str_endOfRange = intToString( endOfRange );
 
       m_message = "Argument " + str_argument + " don't hit on the range [" +
               str_beginOfRange + ", " + str_endOfRange + "]";
   }
};
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Апрель 07, 2014, 11:49
Оставляю здесь довольно полный пример. Возможно, кому-нибудь пригодится :)

Пример разработки ПО через тестирование

Задание на разработку.. Написать класс с именем FiveAndFive. В этом классе должен быть метод fiveAndFive(), который возвращает квадрат своего аргумента.

Соглашения вызова метода:
1) Метод работает с аргументом из диапазона: [5, 4*10^5]. Если нарушено это соглашение, то метод выбрасывает исключение.
2) Метод работает с аргументом кратным пяти. Если нарушено это соглашение, то метод выбрасывает исключение.

- создаём консольное приложение "Qt Console Application"
Имя папки: FiveAndFiveProject
Имя проекта: FiveAndFive

- создаём проект "Qt Unit Test" в той же папке: FiveAndFiveProject
Имя проекта: FiveAndFiveTests
Имя класса с тестами: FiveAndFiveTests
Имя исходного файла с тестами: tst_FiveAndFiveTests.cpp

- в проекте FiveAndFive создаём класс с тем же именем: FiveAndFive, а так же создаём заглушку для метода fiveAndFive(). Так же добавляем классы исключений (код проекта см. ниже)

Весь код проекта FiveAndFive: https://github.com/8Observer8/FiveAndFive

FiveAndFive.pro
Код
C++ (Qt)
QT       += core
 
QT       -= gui
 
TARGET = FiveAndFive
CONFIG   += console
CONFIG   -= app_bundle
 
TEMPLATE = app
 
 
SOURCES += main.cpp \
   FiveAndFive.cpp
 
HEADERS += \
   FiveAndFive.h \
   FileError.h \
   FileOpenError.h \
   FileReadError.h \
   FileWriteError.h \
   LogicError.h \
   InvalidArgument.h \
   OutOfRange.h
 

FiveAndFive.h
Код
C++ (Qt)
#ifndef FIVEANDFIVE_H
#define FIVEANDFIVE_H
 
#include "InvalidArgument.h"
#include "OutOfRange.h"
 
class FiveAndFive {
public:
   double fiveAndFive( int number ) throw (InvalidArgument, OutOfRange);
};
 
#endif // FIVEANDFIVE_H
 

FiveAndFive.cpp
Код
C++ (Qt)
#include "FiveAndFive.h"
 
double FiveAndFive::fiveAndFive( int number ) throw (InvalidArgument, OutOfRange) {
   if ( (number % 5) != 0 ) {
       throw InvalidArgument( number );
   }
 
   const int beginOfRange = 5;
   const int endOfRange = 400000;
   if ( (number < beginOfRange) || (endOfRange < number) ) {
       throw OutOfRange( number, beginOfRange, endOfRange );
   }
 
   double result = (double) number * (double) number;
   return result;
}
 

main.cpp
Код
C++ (Qt)
#include <QCoreApplication>
#include <iostream>
#include <fstream>
#include "FiveAndFive.h"
#include "FileError.h"
#include "FileOpenError.h"
#include "FileReadError.h"
#include "FileWriteError.h"
#include "LogicError.h"
 
void readData( const std::string &fileName, int &number )
throw (FileOpenError, FileReadError);
 
void writeResult( const std::string &fileName, int result )
throw (FileOpenError, FileWriteError);
 
int main( int argc, char *argv[] ) {
   QCoreApplication a( argc, argv );
 
   std::string fileNameIn = "input.txt";
   int number = 0;
 
   try {
       readData( fileNameIn, number );
   } catch ( const FileError &e ) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   } catch ( ... ) {
       std::cerr << "Uncaught exception." << std::endl;
       return 1;
   }
 
   int result = 0;
   FiveAndFive faf;
   try {
       result = faf.fiveAndFive( number );
   } catch ( const LogicError &e ) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   } catch ( ... ) {
       std::cerr << "Uncaught exception." << std::endl;
       return 1;
   }
 
   std::string fileNameOut = "output.txt";
   try {
       writeResult( fileNameOut, result );
   } catch ( const FileError &e ) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   }
 
   std::cout << "See file " << fileNameOut << std::endl;
 
   return a.exec( );
}
 
void readData( const std::string &fileName, int &number )
throw ( FileOpenError, FileReadError) {
   std::ifstream file;
   file.open( fileName.c_str( ) );
   if ( file.fail( ) ) {
       throw FileOpenError( fileName );
   }
 
   int lineNumIn = 0;
   if ( !(file >> number) ) {
       lineNumIn++;
       throw FileReadError( fileName, lineNumIn );
   }
}
 
void writeResult( const std::string &fileName, int result )
throw (FileOpenError, FileWriteError) {
   std::ofstream file;
   file.open( fileName.c_str( ) );
 
   if ( file.fail( ) ) {
       throw FileOpenError( fileName );
   }
 
   if ( !(file << result) ) {
       throw FileWriteError( fileName );
   }
 
   file << std::endl;
}
 

LogicError.h
Код
C++ (Qt)
#ifndef LOGICERROR_H
#define LOGICERROR_H
 
#include <string>
#include <stdexcept>
 
class LogicError : public std::logic_error {
public:
 
   LogicError( int argument ) : std::logic_error( "" ), m_argument( argument ) {
 
   }
 
   virtual const char *what( ) const throw () {
       return m_message.c_str( );
   }
 
   virtual ~LogicError( ) throw () {
 
   }
 
protected:
   int m_argument;
   std::string m_message;
};
 
#endif // LOGICERROR_H
 

InvalidArgument.h
Код
C++ (Qt)
#ifndef INVALIDARGUMENT_H
#define INVALIDARGUMENT_H
 
#include <string>
#include <sstream>
#include "LogicError.h"
 
class InvalidArgument : public LogicError {
public:
 
   InvalidArgument( int argument ) : LogicError( argument ) {
       std::stringstream stream;
       stream << argument;
       m_message = "Argument " + stream.str( ) + " mush be multiple of 5";
   }
};
 
#endif // INVALIDARGUMENT_H
 

OutOfRange.h
Код
C++ (Qt)
#ifndef OUTOFRANGE_H
#define OUTOFRANGE_H
 
#include <string>
#include <sstream>
#include "LogicError.h"
 
class OutOfRange : public LogicError {
public:
 
   OutOfRange( int argument, int beginOfRange, int endOfRange ) : LogicError( argument ) {
       std::string str_argument, str_beginOfRange, str_endOfRange;
 
       str_argument = intToString( argument );
       str_beginOfRange = intToString( beginOfRange );
       str_endOfRange = intToString( endOfRange );
 
       m_message = "Argument " + str_argument + " don't hit on the range [" +
               str_beginOfRange + ", " + str_endOfRange + "]";
   }
 
private:
   std::string intToString( int number ) {
       std::stringstream stream;
       stream << number;
       return stream.str( );
   }
};
 
#endif // OUTOFRANGE_H
 

FileError.h
Код
C++ (Qt)
#ifndef FILEERROR_H
#define FILEERROR_H
 
#include <string>
#include <stdexcept>
 
class FileError : public std::runtime_error {
public:
 
   FileError( const std::string &fileIn ) : std::runtime_error( "" ), m_file( fileIn ) {
   }
 
   virtual const char* what( ) const throw() {
       return m_msg.c_str( );
   }
 
   virtual ~FileError() throw() {
 
   }
 
protected:
   std::string m_file;
   std::string m_msg;
};
 
#endif // FILEERROR_H
 

FileOpenError.h
Код
C++ (Qt)
#ifndef FILEOPENERROR_H
#define FILEOPENERROR_H
 
#include <string>
#include "FileError.h"
 
class FileOpenError : public FileError {
public:
 
   FileOpenError( const std::string &fileNameIn ) : FileError( fileNameIn ) {
       m_msg = "Unable to open " + fileNameIn;
   }
};
 
#endif // FILEOPENERROR_H
 

FileReadError.h
Код
C++ (Qt)
#ifndef FILEREADERROR_H
#define FILEREADERROR_H
 
#include <string>
#include <sstream>
#include "FileError.h"
 
class FileReadError : public FileError {
public:
 
   FileReadError( const std::string &fileNameIn, int lineNumIn ) :
       FileError( fileNameIn ), m_lineNum( lineNumIn ) {
       std::ostringstream ostr;
       ostr << "Error reading " << fileNameIn << " at line " << lineNumIn;
       m_msg = ostr.str( );
   }
 
protected:
   int m_lineNum;
};
 
#endif // FILEREADERROR_H
 

FileWriteError.h
Код
C++ (Qt)
#ifndef FILEWRITEERROR_H
#define FILEWRITEERROR_H
 
#include <string>
#include "FileError.h"
 
class FileWriteError : public FileError {
public:
 
   FileWriteError( const std::string &fileNameIn ) : FileError( fileNameIn ) {
       m_msg = "Unable to write " + fileNameIn;
   }
};
 
#endif // FILEWRITEERROR_H
 

- открываем файл tst_FiveAndFiveTests.cpp проекта FiveAndFiveTests и добавляем тесты (код проекта см. ниже)

Примечание. Не забудьте добавить в файл .pro строки:
Код
C++ (Qt)
INCLUDEPATH += "../FiveAndFive"
SOURCES += ../FiveAndFive/FiveAndFive.cpp
 

Весь код проекта FiveAndFiveTests: https://github.com/8Observer8/FiveAndFiveTests

FiveAndFiveTests.pro
Код
C++ (Qt)
QT       += testlib
 
QT       -= gui
 
TARGET = tst_FiveAndFiveTests
CONFIG   += console
CONFIG   -= app_bundle
 
TEMPLATE = app
 
 
SOURCES += tst_FiveAndFiveTests.cpp
INCLUDEPATH += "../FiveAndFive"
SOURCES += ../FiveAndFive/FiveAndFive.cpp
DEFINES += SRCDIR=\\\"$$PWD/\\\"

tst_FiveAndFiveTests.cpp
Код
C++ (Qt)
#include <QString>
#include <QtTest>
 
#include "FiveAndFive.h"
 
class FiveAndFiveTests : public QObject {
   Q_OBJECT
 
public:
   FiveAndFiveTests( );
 
   static inline bool qFuzzyCompare( double p1, double p2, double delta ) {
       return ( qAbs( p1 - p2 ) <= delta * qMin( qAbs( p1 ), qAbs( p2 ) ));
   }
 
   private
Q_SLOTS:
   void testCase1_data( );
   void testCase1( );
};
 
FiveAndFiveTests::FiveAndFiveTests( ) {
}
 
void FiveAndFiveTests::testCase1_data( ) {
   QTest::addColumn<int>("number");
   QTest::addColumn<double>("expected");
   QTest::addColumn<bool>("isExpectedException");
 
   bool exception = true;
   bool no_exception = false;
 
   QTest::newRow( "fiveAndFive_02" ) << 0 << 0.0 << exception;
   QTest::newRow( "fiveAndFive_01" ) << 1 << 0.0 << exception;
   QTest::newRow( "fiveAndFive_03" ) << 4 << 0.0 << exception;
   QTest::newRow( "fiveAndFive_04" ) << 5 << 25.0 << no_exception;
   QTest::newRow( "fiveAndFive_05" ) << 6 << 0.0 << exception;
   QTest::newRow( "fiveAndFive_06" ) << 399995 << 159996000025.0 << no_exception;
   QTest::newRow( "fiveAndFive_07" ) << 400000 << 160000000000.0 << no_exception;
   QTest::newRow( "fiveAndFive_08" ) << 400001 << 0.0 << exception;
   QTest::newRow( "fiveAndFive_09" ) << 400005 << 0.0 << exception;
}
 
void FiveAndFiveTests::testCase1( ) {
   QFETCH( int, number );
   QFETCH( double, expected );
   QFETCH( bool, isExpectedException );
 
   double delta = 0.0001;
 
   FiveAndFive faf;
 
   try {
       double actual = faf.fiveAndFive( number );
       bool result = qFuzzyCompare( actual, expected, delta );
       if ( isExpectedException ) {
           QVERIFY2( false, "There is no exception." );
       } else {
           QString msg = QString( "\nActual: %1"
                   "\nExpected: %2"
                   "\nDelta: %3" ).arg( actual ).arg( expected ).arg( delta );
           QVERIFY2( result, msg.toStdString( ).c_str( ) );
       }
 
   } catch ( const LogicError& e ) {
       if ( !isExpectedException ) {
           QVERIFY2( false, "Exception was occur." );
       } else {
           QVERIFY2( true, "" );
       }
   } catch ( ... ) {
       QVERIFY2( false, "Uncaught exception." );
   }
}
 
QTEST_APPLESS_MAIN( FiveAndFiveTests )
 
#include "tst_FiveAndFiveTests.moc"
 


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Апрель 12, 2014, 00:03
Сделай те уже функции для перевода числа в строку и наоборот. :)
С шаблонами можно сделать две универсальные функции для любых чисел.

Нашёл такой способ перевода из числа в строку:
Код
C++ (Qt)
#include <QCoreApplication>
#include <string>
#include <iostream>
#include "boost/lexical_cast.hpp"
 
int main( int argc, char *argv[] ) {
   QCoreApplication a( argc, argv );
 
   int i = 5;
   std::string s = boost::lexical_cast<std::string>(i);
   std::cout << s << std::endl;
 
   double d = 5.5;
   s = boost::lexical_cast<std::string>(d);
   std::cout << s << std::endl;
 
   return a.exec( );
}
 

Исходники: https://github.com/8Observer8/NumberToString


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Июнь 26, 2014, 07:29
Код
C++ (Qt)
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
 
int sumOfMaxAndMin(const vector<int>& arr) {
   int sum = 0;
 
   return sum;
}
 
int main(int argc, char** argv) {
   string inFileName = "input.txt";
   ifstream in;
   in.open(inFileName.c_str());
   if (!in.is_open()) {
       cerr << "Error: could not open the file " << inFileName.c_str() << endl;
       return 1;
   }
 
   string outFileName = "output.txt";
   ofstream out;
   out.open(outFileName.c_str());
   if (!out.is_open()) {
       cerr << "Error: could not open the file " << outFileName.c_str() << endl;
       in.close();
       return 1;
   }
 
   vector<int> arr;
   int value;
   string input;
   stringstream stream;
   while (in >> input) {
       stream << input;
       if (stream >> value) {
           cout << value << endl;
       } else {
           cerr << "Error: incorrect data in the file " << inFileName.c_str() << endl;
           in.close();
           out.close();
           return 1;
       }
   }
 
   int sum = sumOfMaxAndMin(arr);
   out << sum << endl;
 
   in.close();
   out.close();
   return 0;
}
 

В базовых вещах "плаваете" капитально, опыта/кладки почти нет. Ну не пишет программист 3 раза in.close(), не валит все в main и.т.д.

Код
C++ (Qt)
int main(int argc, char** argv)
{
 std::vector <int> vec;
 
// получаем имя файла из командной строки, если там пусто, то input.txt (по умолчанию)
 std::string iFileName = GetInName(argc, argv);
 
// читаем данные из файла
 int err = ReadData(iFileName, vec);
 if (err) return ShowError(err, &iFileName);
 
// выполняем содержательную часть
 int result;
 err = sumOfMaxAndMin(arr, &result);
 if (err) return ShowError(err, &iFileName);
 
// записываем выходной файл
 std::string oFileName = GetOutName(argc, argv);
 err = WriteResult(oFileName, result);
 if (err) return ShowError(err, &oFileName);
 
 return 0;
}
Теперь начинаем парить ReadData и др ф-ции, там тоже выделяем ф-ции, их будет уже меньше - и так до тех пор пока не напишем все. Когда Вы все это сделаете (аккуратно, с любовью а не абы как) - Вы с удивлением обнаружите что in.close() не понадобился ни разу  :)

Благодаря этой теме, я нашёл способ оформления и разработки программ. Теперь функция main() не содержит ничего лишнего. Все файловые ошибки я наследую от класса "FileError", поэтому могу написать:

Код:
...
} catch ( const FileError &e) {
        std::cerr << e.what( ) << std::endl;
        return 1;
...

Проект "TextFile"

Исходники примера "TextFile": https://github.com/8Observer8/Qt_TextFile

Описание:
В этом примере целые числа читаются из файла "input.txt" и выводятся файл "output.txt". Числа не должны выходить из диапазона [-100, 100]. В противном случае, пользователю будет выведено сообщение:
Цитировать
Error: the argument "101" doesn't hit into the range [-100, 100]

Пример демонстрирует, как тестировать свободные функции с помощью макроса "ASSERT_EQ( expected, actual )", и исключения с помощью макросов: ASSERT_THROW и ASSERT_NO_THROW.

Пример выполнен по методологии TDD. То есть, к примеру:
- сначала создавалась заглушка разрабатываемой функции
- потом, описывалась функциональность будущей функции с помощью тестов на GTest
- далее, реализовывалась функциональность и перезапускались тесты, до полного их выполнения

Краткое пояснение к этому проекту:

main.cpp
Код
C++ (Qt)
#include <iostream>
#include <string>
#include <vector>
#include <QString>
#include "freeFunctions.h"
#include "LogicError.h"
#include "FileError.h"
 
int main( )
{
   // Read data from the input file
   QString fileNameIn = "input.txt";
   QString content;
 
   try {
       readData( fileNameIn, content );
   } catch ( const LogicError &e ) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   } catch ( const FileError &e) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   } catch ( ... ) {
       std::cerr << "Error: unknown exception" << std::endl;
       return 1;
   }
 
   // Parse the content to the integer array
   std::vector<int> arr;
   try {
       parseToIntArray( content, arr );
   } catch ( const LogicError &e ) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   } catch ( ... ) {
       std::cerr << "Error: unknown exception" << std::endl;
       return 1;
   }
 
   // Write data to the output file
   QString fileNameOut = "output.txt";
   try {
       writeData( fileNameOut, arr );
   } catch ( const LogicError &e ) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   } catch ( const FileError &e ) {
       std::cerr << e.what( ) << std::endl;
       return 1;
   } catch ( ... ) {
       std::cerr << "Error: unknown exception" << std::endl;
       return 1;
   }
 
   return 0;
}
 

Функция "void readData( const QString &fileName, QString &content )" читает данные из файла с именем "fileName" и помещает их в строковый объект "content".

Функция "void parseToIntArray( const QString &source, std::vector<int> &destination )" парсит данные из строкового объекта "content" в массив целых чисел.

Массив выводится в файл "output.txt" с помощью функции: void writeData( const QString &fileName, const std::vector<int> &arr )

Эти функции выбрасывают исключения. Вот некоторые из них:
- FileOpenError - "Ошибка открытия файла". К примеру, это исключение может выдать такой текст пользователю: Error: unable to open the file "input.txt" in the function "readData()"
- FileReadError - "Ошибка чтения из файла"
- EmptyArgument - "Входной аргумент представляет из себя пустой аргумент"

В корневой папке этого проекта находится папка "GTests", в которой хранятся тестовые проекты на Qt для всех классов и свободных функций, которые можно было протестировать в этом проекте. Вот список этих тестовых проектов:
- TextFile_EmptyArgument_gtests
- TextFile_FileOpenError_gtests
- TextFile_FileReadError_gtests
- TextFile_FileWriteError_gtest
- TextFile_isAllDigits_gtests
- TextFile_NotNumber_gtests
- TextFile_OutOfRange_gtests
- TextFile_parseToIntArray_gtests

Все детали вы увидите, когда просмотрите сам проект "TextFile" и проекты с тестами его модулей из папки GTests: https://github.com/8Observer8/Qt_TextFile


Название: Re: Тренировка навыков быстрого программирования
Отправлено: 8Observer8 от Июнь 26, 2014, 09:02
В шапку темы добавил текст:

Внимание! Эта тема перетекла, в следующую тему, в шапку которой я буду добавлять изменения/добавления. Вам достаточно будет подписаться на неё. О всех измененияx/добавленияx я буду извещать: http://www.prog.org.ru/topic_26944_0.html