2D Array Malloc - PullRequest
       1

2D Array Malloc

0 голосов
/ 19 августа 2011

Ниже приведена часть более длинного кода, где выполняется malloc'ing для 2D-массива.Кто-нибудь может сказать, если это правильно?Если я введу статические значения, код работает нормально.Иначе, ошибки сегмента ...

enum { LEN = 1024*8 };

char **tab = NULL;
int cur_LEN = LEN;
int count_lineMax = 0;


tab = malloc(count_lineMax * sizeof(*tab));
      memset(tab, 0, count_lineMax * sizeof(*tab));

if(tab == NULL && count_lineMax) {
    printf("Mem_check\n");
    exit(1);
}

for(k=0;k<count_lineMax;k++) {
    tab[k] = malloc(cur_LEN*sizeof(*tab[k]));
    memset(tab[k], 0, cur_LEN*sizeof(*tab[k]));

    if(tab[k] == NULL) {
        printf("Mem_check*\n");
        exit(1);
    }
}
for(l=0;l<count_lineMax;l++) {
    free(tab[l]);
}
free(tab);

Ответы [ 2 ]

3 голосов
/ 19 августа 2011
int count_lineMax = 0;

tab = malloc(count_lineMax * sizeof(*tab));

Что это? Ты собираешься собрать 0 байтов?

0 голосов
/ 19 августа 2011

Существует как минимум два способа построения таблицы при чтении строк.Каждый использует свойство realloc(), что если его первый аргумент является нулевым указателем, он будет вести себя как malloc() и выделит запрошенное пространство (поэтому код может запускаться самостоятельно, используя только realloc()).Этот код может выглядеть следующим образом:

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

enum { LEN = 1024*8 };

static void error(const char *fmt, ...);
static char *xstrdup(const char *str);

int main(void)
{
    char line[LEN];
    char **tab = NULL;
    int tabsize = 0;
    int lineno = 0;

    while (fgets(line, sizeof(line), stdin) != 0)
    {
        if (lineno >= tabsize)
        {
            size_t newsize = (tabsize + 2) * 2;
            char **newtab = realloc(tab, newsize * sizeof(*newtab));
            if (newtab == 0)
                error("Failed to allocate %zu bytes of memory\n", newsize * sizeof(*newtab));
            tab = newtab;
            tabsize = newsize;
        }
        tab[lineno++] = xstrdup(line);
    }

    /* Process the lines */
    for (int i = 0; i < lineno; i++)
        printf("%d: %s", i+1, tab[i]);

    /* Release the lines */
    for (int i = 0; i < lineno; i++)
        free(tab[i]);
    free(tab);

    return(0);
}

static void error(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    exit(1);
}

static char *xstrdup(const char *str)
{
    size_t len = strlen(str) + 1;
    char *copy = malloc(len);
    if (copy == 0)
        error("Failed to allocate %zu bytes of memory\n", len);
    memmove(copy, str, len);
    return(copy);
}

Альтернатива явно использует malloc(), когда таблица пуста, и наиболее просто кодируется как:

int main(void)
{
    char line[LEN];
    int tabsize = 4;
    int lineno = 0;
    char **tab = malloc(tabsize * sizeof(*tab));

    if (tab == 0)
        error("Failed to allocate %zu bytes of memory\n", tabsize * sizeof(*tab));

    ...

Все остальное может оставаться нетронутым.

Обратите внимание, что может быть удобно иметь функции xmalloc() и xrealloc(), которые гарантированно никогда не вернут нулевой указатель, поскольку вместо этого они сообщают об ошибке:

static void *xmalloc(size_t nbytes)
{
    void *space = malloc(nbytes);
    if (space == 0)
        error("Failed to allocate %zu bytes of memory\n", nbytes);
    return(space);
}

static void *xrealloc(void *buffer, size_t nbytes)
{
    void *space = realloc(buffer, nbytes);
    if (space == 0)
        error("Failed to reallocate %zu bytes of memory\n", nbytes);
    return(space);
}

В длинномterm (большие программы), это сокращает общее количество раз, когда вы пишете сообщения об ошибке «недостаточно памяти».С другой стороны, если вам необходимо восстановиться после сбоев выделения памяти (сохранить работу пользователя и т. Д.), Это неуместная стратегия.

Приведенный выше код создает рваный массив;разные записи в tab имеют разную длину.Если вам нужны однородные длины (как в исходном коде), вам нужно заменить или изменить функцию xstrdup(), чтобы выделить максимальную длину.

Возможно, вы заметили, что код в xstrdup() используется memmove() вместо strcpy().Это связано с тем, что strlen() уже измерил длину строки, поэтому нет необходимости в коде копирования для проверки каждого байта на предмет необходимости копирования.Я использовал memmove(), потому что он никогда не может пойти не так, даже если строки перекрываются, хотя в этом контексте ясно, что строки никогда не могут перекрываться, и поэтому memcpy() - что не гарантируется, что корректно будет работать, если строки перекрываются -мог использоваться, поскольку строки не могут перекрываться.

Стратегия распределения (oldsize + 2) * 2 новых записей означает, что код перераспределения памяти выполняется достаточно часто во время тестирования, без чрезмерного влияния на производительность в производственной среде.См. Практику программирования Кернигана и Пайка, чтобы обсудить, почему это хорошая идея.

Я почти всегда использую набор функций, аналогичных функции error(), потому что она значительноупрощает сообщение об ошибках.Функции, которые я обычно использую, являются частью пакета, который также записывает и сообщает имя программы (с argv[0]), и имеет довольно широкий диапазон альтернативных вариантов поведения.

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