C - Я не хочу выделять память, которую я не буду использовать! (новый вопрос) - PullRequest
0 голосов
/ 20 мая 2011

Я сделал свою первую программу на Си.Он удаляет комментарии C ('//').Я передаю строку в функцию strip_comments, создаю новую строку с тем же размером, что и строка аргумента, а затем копирую, char by char, игнорируя комментарии.

Это код:

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

#define IN 1
#define OUT 0

int file_size(FILE *file);
char * strip_comments(char *content);

int main(int argc, char *argv[])
{
    FILE *file;
    char *buffer, *content;
    int size;

    if (argc == 1)
    {
        printf("USAGE: stripccomments filename\n");
        return 1;
    }

    if ((file = fopen(argv[1], "rw")) == NULL)
    {
        printf("Could not open file '%s'.\n", argv[1]);
        return 1;
    }

    size = file_size(file);
    buffer = malloc(sizeof(char) * size);

    if (buffer == NULL)
    {
        printf("Could not allocate memory\n");
        return 1;
    }

    fread(buffer, sizeof(char), size, file);

    content = strip_comments(buffer);
    printf("%s", content);

    free(buffer);
    fclose(file);

    return 0;
}

int file_size(FILE *file)
{
    int size;

    fseek(file, 0, SEEK_END);
    size = ftell(file);
    rewind(file);

    return size;
}

char * strip_comments(char *content)
{
    int state, length, i, j;
    char *new_content;

    state = OUT;
    length = strlen(content);
    new_content = malloc(sizeof(char) * length);
    j = 0;

    for (i = 0; i < length; i++)
    {
        if (content[i] == '/' && content[i + 1] == '/')
        {
            state = IN;
            i++;
            continue;
        }

        if (state && content[i] == '\n')
        {
            state = OUT;
        }

        if (!state)
        {
            new_content[j] = content[i];
            j++;
        }
    }
    new_content[j + 1] = '\0';

    return new_content;
}

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

ОБНОВЛЕНИЕ: Что происходит с этим неиспользуемым пространством?Остается ли он в «подвешенном состоянии»?И что происходит с этим пробелом, когда выполнение заканчивается?

Спасибо.

Ответы [ 3 ]

2 голосов
/ 20 мая 2011

Это не решит вашу проблему, как указано, но мой подход заключается в том, чтобы написать это как функцию, которая работает с дескриптором входного файла и дескриптором выходного файла, то есть void strip_comments(FILE *infile, FILE *outfile);.В любом случае, вы в действительности выполняете только разбор символов, так что теряется при переключении с content[i++] на getc()?Если вы делаете это с помощью файловых дескрипторов вместо строк, вам а) не нужно хранить потенциально большие целые файлы в памяти, и б) не нужно беспокоиться о выделении памяти для буфера.

При этом, если вы хотите сделать это с char * s вместо этого, вы всегда можете проанализировать строку дважды: один раз, чтобы вычислить, сколько байтов выделить, затем один раз скопировать указанные байты.Или вы можете просто позвонить realloc в конце, чтобы сократить ваш буфер до нужного размера.

1 голос
/ 20 мая 2011

Поскольку ваша программа не будет знать, сколько памяти требуется для хранения источника, вы можете начать с начального размера буфера и при необходимости увеличить его. Другой способ - сначала отсканировать файл и рассчитать разницу в размерах. Оба этих подхода влияют на производительность в зависимости от количества переданных комментариев. Несколько malloc s / realloc замедляют производительность, а также дважды читают весь файл, а с другой стороны, вы беспокоитесь о том, чтобы тратить их впустую. память, это ваш выбор, или вы можете использовать все 3, установив значение по умолчанию, а затем внедрив флаги командной строки, чтобы позволить пользователю решить, какой вариант, если они того пожелают.

Также не забудьте добавить +1 к вашему strlen, чтобы учесть нулевой символ. Ваша текущая реализация перейдет на не malloc ed территорию, если файл не содержит комментариев.

Для вашего обновления:

Да, потраченное впустую пространство будет в конце вашей строки, ничего не делая, но будет правильно восстановлено после вызова free. Например, строка со строчкой 10 в блоке памяти, выделенной для 15, может выглядеть так:

size of 10\0#%^@&
          ^^^garbage
          ^^null char
0 голосов
/ 20 мая 2011

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...