Перераспределение 1D массива целых чисел, сохранение исходных значений, обнуление остальных - PullRequest
0 голосов
/ 31 октября 2018

Я хотел бы изменить размер одномерного массива целых чисел, сохранить значения из исходного массива и инициализировать новые значения с нулями. До сих пор я придумал две альтернативы (а) с использованием calloc и memcpy:

// Resizes composition
int compo_resize(int len, int *a) {

    // initialise new composition
    int *c = calloc(2*len, sizeof a[0]);

    if (c == NULL) {
        fprintf(stderr, "calloc() failed");
        return LieanderErrorOutOfMemory;
    }

    // copy numbers from old to new composition
    memcpy(c, a, sizeof a[0] * len);

    // modify composition in-place
    *a = *c;

    // release memory
    free(c);

    return LieanderSuccess;
}

и (b) с использованием realloc и memset:

// Resizes composition
int compo_resize(int len, int *a) {

    printf("Note: resizing composition...\n");

    // reallocate memory
    void *c = realloc(a, 2*len);

    if (c == NULL) {
        fprintf(stderr, "realloc() failed");
        return LieanderErrorOutOfMemory;
    }
    else {
        // reassign pointer
        a = c;

        // zero out new elements
        memset(&a[len], 0, len * sizeof a[len]);
    }

    return LieanderSuccess;
}

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

Вызов combo_resize() является int retval = compo_resize(f->len, f->a), где f - это пользовательская структура, называемая pair:

typedef struct {
    int  fac;  // multiplication factor
    int  idx;  // index of Lieander
    int  len;  // length of compositions
    int  kth;  // no. of elements in compositions
    int *a;    // composition 1
    int *b;    // composition 2
    int  num;  // natural no.
} pair;

Ответы [ 3 ]

0 голосов
/ 31 октября 2018

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

Во-вторых, убедитесь, что вы строго относитесь к размеру массива по сравнению с размером в байтах.

// Resizes composition
int compo_resize(int len, int **a) {

    printf("Note: resizing composition...\n");

    // reallocate memory
    void *c = realloc(*a, sizeof(int) * 2 * len);

    if (c == NULL) {
        fprintf(stderr, "realloc() failed");
        return LieanderErrorOutOfMemory;
    }
    else {
        // reassign pointer
        *a = c;

        // zero out new elements
        memset(&c[len], 0, sizeof(int) * len);
    }

    return LieanderSuccess;
}
0 голосов
/ 31 октября 2018

Параметр int *a необходимо заменить на int **a, поскольку вы хотите изменить указатель от имени вызывающего абонента.

// Resizes composition
int compo_resize(int len, int **a) {

    printf("Note: resizing composition...\n");

    // reallocate memory
    int *c = realloc(*a, sizeof(c[0])*2*len);

    if (c == NULL) {
        fprintf(stderr, "realloc() failed");
        return LieanderErrorOutOfMemory;
    }
    else {
        // reassign pointer
        *a = c;

        // zero out new elements
        memset(&c[len], 0, len * sizeof c[len]);
    }

    return LieanderSuccess;
}
0 голосов
/ 31 октября 2018

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

2 - Рассмотрим бесплатную старую * a после копирования в * c.

3- Изменить объявление функции с:

int compo_resize(int len, int *a);

до

int compo_resize(int len, int **a);

потому что вы хотите обновить значение самого указателя, чтобы он указывал на вновь созданный массив.

...