2014-01-31 7 views
8

Мне нужно выделить несколько массивов одного типа и формы. В начале, я сделал что-то вроде:Выделение нескольких массивов того же типа

void alloc_arrays_v1(size_t nmemb) 
{ 
    int *a1, *a2, *a3; 

    a1 = malloc(nmemb * sizeof int); 
    a2 = malloc(nmemb * sizeof int); 
    a3 = malloc(nmemb * sizeof int); 

    /* do some stuff with the arrays */ 

    free(a1); 
    free(a2); 
    free(a3); 
} 

Чтобы избежать вызова malloc и free несколько раз, я изменил выше в:

void alloc_arrays_v2(size_t nmemb) 
{ 
    int *a, *a1, *a2, *a3; 

    a = malloc(3 * nmemb * sizeof int); 
    a1 = a; 
    a2 = a1 + nmemb; 
    a3 = a2 + nmemb; 

    /* do some stuff */ 

    free(a); 
} 

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

+3

Его полностью действительный код C, и да, вы можете сделать это с другими типами, включая структуры (арифметика указателя работает, если вы ее позволяете, и вы позволяете ей просто отлично). Запустите его в отладчике и выполните математику по адресам, начинающимся с 'a', чтобы подтвердить это. – WhozCraig

+0

@WhozCraig: Я делаю это в реальном случае :) – michaelmeyer

+2

Не уверен, что это связано с отладкой, поскольку я отлаживаю * много * кода реального мира. Но его полезно видеть в действии по строчке, шаг за шагом. Не думайте, что отладчики полезны только для поиска ошибок; они являются одинаково фантастическими инструментами для изучения * действительного * кода и просмотра того, как он работает на выбранной платформе. – WhozCraig

ответ

3

Он полностью действителен в C. Но не забудьте освободить только указатель a. Ваш этот метод похож на структуру взломать

Однако я думаю, что одна логическая проблема в этом коде является то, что если вы выйдете за пределы для a1 или a2 вы не сможете заметить, как вы будете получать доступ к действительной памяти адресов, то есть вы не получите Seg Fault.
Однако в первом случае вы можете «получить» SegFault и заметить свою ошибку.

+0

Спасибо за уточнения. Кроме того, остается ли он для структур? – michaelmeyer

+0

Доступ к массиву за его максимальным индексом - неопределенное поведение - на этой основе [struct hack is UB] (http://stackoverflow.com/q/3711233/183120), в то время как случай OPs никоим образом не является UB. Пулы памяти работают таким образом. – legends2k

+0

, заканчивая последнее предложение, или, что еще хуже, вы можете * не * получить segfault в первом фрагменте и, таким образом, * не * заметить свою ошибку, которая во многих мнениях (включая мои) намного хуже, чем сбой. скорее это крушение в ожидании, которое никогда не бывает забавным. В обоих случаях будьте осторожны с вашими границами указателей и вы будете в порядке. – WhozCraig

3

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

Стоит отметить, что

int a1, a2, a3, a4; 
int* a = &a1; 
int oops = *(a + 1); 

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

2

Совершенно верно.

Что вы делаете, по существу, такими же, как это:

void alloc_arrays_v1(size_t nmemb) 
{ 
    typedef int one_array[nmemb]; // this is one array 
    typedef one_array three_arrays[3]; // this are three arrays 

    one_array * a; 
    int *a1, *a2, *a3; 
    a = malloc(sizeof(three_arrays)); 

    a1 = a[0]; // a[0] is a one_array, which decays into an int * here. 
    a2 = a[1]; // the same 
    a3 = a[2]; // as above 

    /* do some stuff with the arrays */ 

    free(a); 
} 

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

Смежные вопросы