Простой онлайн-редактор


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

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <malloc.h>


char *_ctrlLine = "#################################################";
int _cursor = 0, _maxLines = 0;


void clearBuffer(void) {
    while (getchar() != '\n');
}

void addLine(char ***lines) {
    system("CLS");

    char strBuffer[30], *tempLine = (char*)malloc(sizeof(char)*(strlen(strBuffer) + 1));
    printf("enter your row:\n>%3d ", _cursor+1);
    gets_s(strBuffer, 30);
    strcpy_s(tempLine, strlen(strBuffer) + 1, strBuffer);

    _maxLines++;
    char **temp = *lines;
    *lines = (char**)malloc(sizeof(char*) * (_maxLines+2));

    for (int i = 0; i < _cursor+1; i++)
        (*lines)[i] = temp[i];
    (*lines)[_cursor] = tempLine;
    for (int i = _cursor; i <= _maxLines; i++)
        (*lines)[i+1] = temp[i];
    free(temp);

}

void deleteLine(char ***lines) {
    system("CLS");

    if (_maxLines == 0 || _cursor == _maxLines) {
        printf((_maxLines == 0) ?
            "no lines to delete.. YET!\n" :
            "you cant delete the control line.\n");
        getchar();
        clearBuffer();
        return;
    }

    _maxLines--;
    char **temp = *lines;
    *lines = (char**)malloc(sizeof(char*) * (_maxLines+1));
    for (int i = 0; i < _cursor; i++)
        (*lines)[i] = temp[i];
    for (int i = _cursor; i <= _maxLines; i++)
        (*lines)[i] = temp[i+1];
    free(temp[_cursor]);
    free(temp);
}

void changeLine(char ***lines) {
    system("CLS");

    if (_maxLines == 0 || _cursor == _maxLines) {
        printf((_maxLines == 0) ?
            "no lines to change.. YET!\n" :
            "you cant change the control line.\n");
        getchar();
        clearBuffer();
        return;
    }

    char *temp = (*lines)[_cursor];
    puts(temp);
    printf("change the row above:\n>%3d ", _cursor+1);
    char strBuffer[30], *tempLine = (char*)malloc(sizeof(char)*(strlen(strBuffer) + 1));
    gets_s(strBuffer, 30);
    strcpy_s(tempLine, strlen(strBuffer) + 1, strBuffer);
    (*lines)[_cursor] = tempLine;
    free(temp);
}

void printLines(char **lines) {
    system("CLS");

    if (_maxLines == 0) {
        printf_s("no lines... YET!\n");
        return;
    }
    for (int i = 0; i <= _maxLines; i++) {
        putchar((_cursor == i) ? '>' : ' ');
        printf_s(" %3d %s\n", i+1, lines[i]);
    }
}

void moveCursor(bool up) {
    if (up) {
        if (_cursor > 0)
            _cursor--;
    }
    else if (_cursor < _maxLines)
        _cursor++;
}

void showOptions() {
    system("CLS");
    printf_s("a. add line\nd. delete line\nc. change line\n1. move cursor up\nq. move cursor down\nz. quit\npress any key to continue ");
    getchar();
    clearBuffer();
}

int main() {
    char key = NULL;
    char **lines = (char**)malloc(sizeof(char*));
    lines[0] = _ctrlLine;

    while (key != 'z') {
        printLines(lines);
        printf_s("what key do you want?(o for options) ");
        scanf_s("%c", &key);
        clearBuffer();
        switch (key) {
        case 'o': showOptions();
            break;
        case '1': moveCursor(1);
            break;
        case 'q': moveCursor(0);
            break;
        case 'd': deleteLine(&lines);
            break;
        case 'c': changeLine(&lines);
            break;
        case 'a': addLine(&lines);
            break;
        case 'z': printf_s("bye bye!\n");
        }
    }
    return 0;
}


Комментарии
3 ответа


  • malloc не нуждается в гипсе. На самом деле, кастинг результат функции malloc может привести к трудно найти проблемы.

  • sizeof(char) гарантированно будет 1.

  • Предпочитают принимать sizeof expression а не sizeof(type). Причина в том, что такой код остается действительным, даже если тип изменения. В вашем случае,

        *lines = malloc(sizeof(**lines) * (_maxLines+2));

  • Тройные звезды, как правило, с неодобрением. Обратите внимание, что вы даже не нуждаетесь в них. Ваш код никогда не относится к lines как таковой, а только *lines. Это то, что вас волнует, и это то, что вы будете проходить.

  • lines, cursor и maxLines являются хорошими кандидатами, чтобы быть объединены в структуру.

  • В strBuffer не служит никакой цели. Вы можете прочитать прямо на tempLine. Аналогично, changeLine можете прочитать прямо на (*lines)[_cursor]избегая выделения памяти.

  • deleteLine не нужно temp. Вы можете изменять lines на месте.

  • А printf(); getchar(); clearBuffer() последовательности должны быть включены в функцию.

4
ответ дан 13 марта 2018 в 06:03 Источник Поделиться

Большинство предпочитают что-то вроде [i+1] быть [i + 1]. Как правило, убедитесь, что ваши операторы имеют пространства с каждой стороны. Но поскольку вы немного непоследовательны с расстояния может быть, это просто опечатка.

Не включая { и } С for петли играет с огнем и что-то мне помешает.

1
ответ дан 13 марта 2018 в 06:03 Источник Поделиться

для простоты понимания и читабельности:


  1. отдельные блоки кода ( for if else while do...while switch case default ) через одну пустую строку.

  2. отдельные функции по 2 или 3 пустые строки (будьте последовательны)

  3. следовать аксиоме: только один оператор на строке и (в большинстве) один
    объявление переменной в заявлении.

============================
в общем, лучше к расположению кода в последовательности:


  1. прототипы для функций

  2. функции основной ()'

  3. органы суб функции

============================
в общем, имена переменных не должны начинаться с _<capital letter> ни с __ как такие названия являются "зарезервировано" для системы
Среди других причин, компилятор добавляет Все имена с '_'

============================
заголовочный файл: stdlib.h выставляет прототип malloc() так что не нужно включать malloc.h заголовочный файл

============================
в отношении:

while (getchar() != '\n'); 

этого недостаточно, так как состояние ВФ могут быть возвращены, поэтому также должна быть проверка на ВФ

============================
в отношении:

system("CLS");

командой "ЦБС" не портативный. Предлагаем использовать преобразование формата символа (или лучше) использовать последовательность в кодировке ANSI побег для очистки экрана и перемещая курсор в 0,0 (верхний левый) положения Чара

============================
в отношении:

void addLine(char ***lines)

пожалуйста, Google 'три звезды программиста потом переосмыслили логику этой части программы.

============================
функции: gets_s() это не портативный, предлагаю использовать: fgets()

============================
при вызове любой из кучи функций распределения: ( malloc calloc realloc )


  1. возвращаемый тип void* которые могут быть отнесены к любому указателю. Литье просто загромождает код, делая его более сложным для понимания, отладки и т. д. и 'ошибок' при выполнении отладки и/или технического обслуживания.

  2. выражение: sizeof(char) определяется в C стандарт как 1. все умножения на 1 не имеет никакого эффекта и только загромождает код.

  3. всегда проверяйте (!=Значение null), возвращаемое значение, чтобы гарантировать, что операция прошла успешно.

============================
функции: strcpy_s() это не портативный, предлагаю использовать: strncpy()

============================
при написании тело for() или while()и т. д. петля, даже если есть только (сегодня) один оператор, всегда заключайте тело в фигурные скобки '{' '}' поэтому некоторые будущие (или себя) не будет, скорее всего, поврежден логика

============================
в отношении:

char strBuffer[30]
char *tempLine = malloc(strlen(strBuffer) + 1));

поскольку массив strBuffer содержит мусор, и так как функция: strlen() не остановится, пока не встретится нулевой байт (0х00), результат вызова strlen() может вернуть все что угодно (в зависимости от того, где он столкнулся с нул байт) это приводит к неопределенному поведению и может привести к Сег вине событий.

Примечание: некоторые из мест, где размещен код вызова strlen()от окружающего кода, его следует использовать: sizeof()

============================
есть несколько проблем с обработкой переменных: cursor temp *lines и maxLines среди прочего, это заявление:

*lines = malloc(maxLines+2);

только выделения 'банальный' количество байт. Но *lines как ожидается, будет массив указателей на char. Но это не то, что выделяется.

============================
в отношении:

free(temp);

намекает, что все указатели на строки в файле копируются каждый раз, когда строка вставляется в файл.

============================
Примечание: имена переменных должны указать content или usage (или лучше обоих) некоторые имена переменных являются очень вводит в заблуждение.

============================
в функции: addline()существует большое копирование как линия вставляется в текст. ИМО: было бы гораздо лучше просто увеличить размер *lines выделение памяти через вызов realloc()

1
ответ дан 14 марта 2018 в 10:03 Источник Поделиться