Как инициализировать несколько массивов с неизвестными размерами через функцию в C - PullRequest
2 голосов
/ 12 марта 2020

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

int * pickup_Ind;
double *pickup_Val;
pickup_Ind = (int *) malloc(sizeof(int) * (size1));
pickup_Val = (double *) malloc(sizeof(double) * (size1));

int * lInd;
double *lVal;
lInd = (int *) malloc(sizeof(int) * size2);
lVal = (double *) malloc(sizeof(double) * size2);

int * simul_Ind;
double *simul_Val;
simul_Ind = (int *) malloc(sizeof(int) * (size3));
simul_Val = (double *) malloc(sizeof(double) * (size3));

Я знаю, что могу уменьшить количество строк, например, записав:

int * pickup_Ind = (int *) malloc(sizeof(int) * (size1));

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

void initialize_bounds(int *arr1,int size1)
{
arr1= (int *) malloc(sizeof(int) * (size1));
for(int i=0;i<size1;i++)
    arr1[i]=i;  
}

Но если я вызову эту функцию с помощью следующего в основном, я получу ошибку "Переменный тест используется без инициализации"

int* test;
initialize_bounds(test);

Итак, чтобы подвести итог, если бы я мог написать как то так, моя проблема решена:

int *pickup_Ind,*pickup_Val,*lind,*lval;
int size1,size2;
initalize_bounds(pickup_Ind,pickup_Val,size1,size2);

Ответы [ 4 ]

2 голосов
/ 12 марта 2020

Вы можете написать функцию

void initialize_bounds(int **ind, double **val, int size) {
    *ind = malloc(sizeof (**ind)*size);
    for (int i = 0; i < size; i++) {
        (*ind)[i] = i;
    }
    *val = malloc(sizeof (**val)*size);
}

и вызвать ее как

int * pickup_Ind;
double *pickup_Val;
initialize_bounds(&pickup_Ind, &pickup_Val, size1);

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

2 голосов
/ 12 марта 2020

На языке C аргументы передаются в функции по значению - таким образом, фактически создается копия и исходная переменная (в вызывающем коде) не может быть изменилось. Итак, если вы хотите, чтобы функция модифицировала (скажем) аргумент int, вы передаете ему указатель на это int.

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

Итак, в случае функции initialize_bounds, которую вы показали, вам понадобится:

void initialize_bounds(int** arr1,int size1) // 1st arg is a pointer to the pointer!
{
    *arr1 = (int *) malloc(sizeof(int) * (size1)); // De-reference our `arr1` pointer
    for(int i=0;i<size1;i++)
        (*arr1)[i]=i;  
}

Затем вы можете использовать это для инициализации указателя в вашей функции main с помощью вызова, подобного этому:

int* test;
initialize_bounds(&test); // We need to pass the ADDRESS of the pointer we want to modify!
0 голосов
/ 12 марта 2020

Я бы использовал что-то более высокого уровня, например, эластичные буферы. Смотрите это видео о сеансе кодирования в реальном времени, который реализует эти - реквизиты Per Vognsen для создания этого кода и для помещения в домен publi c (т. Е. Совершенно бесплатно для использования в любых целях, но я не юрист, поэтому принимайте все, что я говорю, с осторожностью:).

Вы хотите включить побитовый / ион / общий. c в исходный файл, а затем массив распределение становится простым. Эластичные буферы, возможно, наиболее близки к удобству C ++ std::vector в C. Они предлагают API, который не похож на API C ++, транскрибированный в C - он находится на правильном уровне и позволяет очень просто использовать простые указатели (например, buf_len указателя NULL равен нулю, не cra sh, buf_push(mybuf, element) добавляет элемент в массив и расширяет его при необходимости и т. д. c.

#include <assert.h>
#include <string.h>
#include <stdlib.h>
// note that common.c includes nothing, so you have to set it up
#include "common.c" 

#define buf_resize(b, n) ((n) <= buf_len(b) ? (b) : (((b) = buf__grow((b), (n), sizeof(*(b)), 0)), ((b) ? buf__hdr((b))->len = (n) : 0), (b)))

typedef struct {
  int * pickup_Ind;
  double *pickup_Val;
  int * lInd;
  double *lVal;
  int * simul_Ind;
  double *simul_Val;
} Data;

enum {
  size1 = ...,
  size2 = ...,
  size3 = ...
}

Data make_Data(void) {
  Data d;
  memset(&d, 0, sizeof(d));

  assert(buf_len(d->pickup_Ind) == 0);
  buf_resize(d.pickup_Ind, size1);
  buf_resize(d.pickup_Val, size1);
  buf_resize(d.lInd, size2);
  buf_resize(d.lVal, size2);
  buf_resize(d.simul_Ind, size3);
  buf_resize(d.simul_Val, size3);
}

int main(int argc, char **argv) {
  Data d = make_Data();
  assert(buf_len(d.pickup_Ind) == size1);
  d.pickup_Ind[0] = 10;
  assert(buf_len(d.pickup_Ind) == size1);
  buf_push(d.pickup_Ind, 11);
  assert(buf_len(d.pickup_Ind) == size1 + 1);
}

Если вы строите массивы, добавляя к ним элементы по одному в-первых, имеет смысл зарезервировать емкость для ожидаемого размера массива через buf_fit (он резервирует только память, но буфер сохраняет свою длину (например, ноль)). Резервирование емкости совершенно необязательно, однако, это предотвращает перераспределение массивов при добавлении к ним элементов.

Таким образом:

Data make_Data(void) {
  Data d;
  memset(&d, 0, sizeof(d));

  assert(buf_len(d->pickup_Ind) == 0);
  buf_fit(d.pickup_Ind, size1);
  buf_fit(d.pickup_Val, size1);
  buf_fit(d.lInd, size2);
  buf_fit(d.lVal, size2);
  buf_fit(d.simul_Ind, size3);
  buf_fit(d.simul_Val, size3);
}

int main(int argc, char **argv) {
  Data d = make_Data();
  assert(buf_len(d.pickup_Ind) == 0); // zero length: no data in the array (yet!)
  assert(buf_cap(d.pickup_Ind) >= size1); // but it has the capacity we need
  buf_push(d.pickup_Ind, 10);
  buf_push(d.pickup_Ind, 11);
  assert(buf_len(d.pickup_ind) == 2);
}

Если вы хотите использовать эластичные буферы в нескольких исходных файлах, вы ' Я буду работать против одного правила объявления (ODR). Таким образом, вам нужно будет выделить определения макросов и объявления функций из common.c и в common.h.

Если Data только выделяется один раз, есть нет необходимости освобождать его перед выходом из программы: операционная система уже сделает это за вас. В противном случае вы можете добавить sh функцию для выполнения этой работы:

void free_Data(Data *d) {
  buf_free(d.pickup_Ind);
  buf_free(d.pickup_Val);
  buf_free(d.lInd);
  buf_free(d.lVal);
  buf_free(d.simul_Ind);
  buf_free(d.simul_Val);
  assert(buf_len(d.pickup_Ind) == 0);
}
0 голосов
/ 12 марта 2020

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

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

/* Header file */
int* AllocateArray(size_t size);
void DeallocateArray(int *array);

int main(void) {
    const size_t size = 10;
    int *const array = AllocateArray(size);
    for (size_t i = 0; i < size; ++i) {
        printf("%d ", array[i]);
    }
    printf("\n");

    DeallocateArray(array);
    return 0;
}

/* Implementation */
int* AllocateArray(size_t size) {
    int *const array = malloc(size * sizeof(int));
    if (array == NULL) {
        // Allocation failed, handle it...
    }

    for (size_t i = 0; i < size; ++i) {
        array[i] = i;
    }

    return array;
}

void DeallocateArray(int *array) {
    if (array == NULL) {
        return;
    }
    free(array);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...