2015-11-11 3 views
2

Итак, в конце каждой итерации, которую я делаю, я хочу, чтобы мой массив был равен моему новому массиву (который я назвал array_new). Я хочу, чтобы каждый элемент массива принимал то же значение, что и в array_new, но я заинтересован в том, чтобы как можно быстрее получить мой код и, таким образом, копировать все по элементам, поскольку этот текущий код не является вариантом:Быстрый способ скопировать массив

for(i=0;i<N_a;i++) { 
    for(j=0;j<N_b;j++) { 
    array[i][j] = array_new[i][j]; 
    } 
} 

Это занимает довольно много времени, потому что мои значения N_a и N_b очень велики. Есть ли способ просто изменить то, что каждый из них указывает, чтобы я мог быстрее начать свою следующую итерацию? Я пытался делать такие вещи, как

double *temp = *array; 
*array = *array_new; 
*array_new = temp; 

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

Любая помощь была бы высоко оценена!

+2

Исправьте ваше сообщение, чтобы указать (через теги), какой язык вы используете. Короткий, но полный пример того, что вы пытаетесь сделать, тоже поможет ... –

+0

Отредактировано сейчас, это более ясно? – thay2302

+2

'memcpy', если копия действительно необходима. Если нужно просто поменять два массива каждый раз, работайте с указателем, который будет обновляться с использованием текущего адреса массива (двойная буферизация). –

ответ

7

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

В c/c++ вы можете использовать memcpy, если это тот язык, который вы используете. У каждого языка есть что-то эквивалентное.

Edit: так как вы подтвердили использование c я могу получить более подробным:

memcpy(array_new,array,sizeof(VARIABLE_TYPE_of_ARRAY_ELEMENT)*N_a*N_b); 
+0

Что вы имеете в виду под «Поскольку размер памяти вашего массива фиксирован»? –

+1

«Известный» был, вероятно, лучшим словом. В отличие от передачи указателя массива на функцию, которая не «знает» фактический размер массива. – SunKnight0

+0

Держу пари, что оптимизатор распознает циклы в виде блок-копии и быстрее использует «memcpy'if». –

0

Ваших стрелочных подкачки коды просто немного выключено: вы разыменование ваших указателей, где вы не должны. В конце концов, точка этого кода заключается в том, чтобы избежать копирования данных, просто заменив два указателя. Вот правильные версии (в зависимости от того, используете ли вы истинный 2D массив или массив указателей на массивы):

//array is declared as 
double (*array)[N_b]; 

double (*temp)[N_b] = array; 
array = array_new; 
array_new = temp; 

или

//array is declared as 
double** array; 

double** temp = array; 
array = array_new; 
array_new = temp; 

Это все, что вам нужно, и это, безусловно, самый быстрый возможный способ обмена содержимым двух буферов. Гораздо быстрее, чем memcpy() ...

+0

Обе из них дают мне ошибку сегментации? – thay2302

+0

@ thay2302 Тогда у вас что-то не так с вашими массивами. Как вы объявили свои массивы, как вы их распределяете и как вы их уничтожаете? – cmaster

+0

Массивы были объявлены как «double ** array», «array_new», они были выделены с помощью «allocate2d (& array, N_a, N_b)» и «allocate2d (& array_new, N_a, N_b)» и уничтожаются с помощью «free2d (& array , N_a) "и" free2d (& array_new, N_a) ". – thay2302

0

Два ответа на этот вопрос сначала вам нужно понять, как массив представлен в памяти. Например. см. этот вопрос: How are multi-dimensional arrays formatted in memory?

Итак, сначала нам нужно знать, есть ли у вас статический массив или нет. Если это статический массив, то задача особенно проста, потому что данные размещаются последовательно в памяти. Это означает, что если у вас есть 2х2 статический массив, с содержанием {{9, 8}, {7, 6}} ваша память может выглядеть следующим образом:

Address 0 1 2 3 4 5 6 7 8 
Content ? ? 9 8 7 6 ? ? ? 

В этом случае переменную, которая объявлена ​​как это:

int[2][2] myArray; 

на самом деле указатель на адрес «2», и вы можете легко скопировать все это.с тетсру:

int [2][2] newArray; 
memcpy(&newArray, &myArray, sizeof(int)*2*2); 

Обратите внимание, что это копии, начиная с Wherever "MyArray" точек (в моем примере это 2) столько байт, как 2 * 2 * SizeOf (INT). Таким образом, в 4 раза больше инт. (Для простоты мой пример предполагает размер одного байта для int, но, конечно, в большинстве систем он равен 4 байтам).

Если у вас есть динамический массив, то это совсем другая история. В этом случае ваша память для массива объявлен как это:

int** myArray; 

также может выглядеть следующим образом:

Address 0 1 2 3 4 5 6 7 8 
Content 9 8 0 6 ? ? 7 6 ? 

Обратите внимание, что указатель myArray все еще указывает на адрес «2». Однако по адресу «2» вы не найдете первое значение, а вместо этого указатель указывает на «0». И здесь вы найдете значения первой «строки», которые равны 9 и 8. Рядом с адресом «2» в номере «3» вы найдете указатель на свою вторую «строку», которая начинается с позиции 6. Как вы можете см., вы все равно можете найти все свои данные, но вы не можете скопировать их за один раз. Для того, чтобы скопировать весь массив, по крайней мере, нужно внешний ряд:

int SIZE_X = 2; 
int SIZE_Y = 2; 
int** newArray = malloc(sizeof(int*)*SIZE_X); 
for(i = 0; i < SIZE_X; ++i) { 
    newArray[i] = malloc(sizeof(int)*SIZE_Y); 
    memcpy(newArray[i], myArray, SIZE_Y*sizeof(int)); 
} 

Это должно быть быстрее, чем с помощью двух петель, если memcpy can use more efficient ways to copy than a copy loop.

+0

Не следует, чтобы строка # 3 была такой: 'int ** newArray = (int **) malloc (sizeof (int *) * SIZE_X);'? Если нет, что означает эта версия? И когда я должен его использовать? – Rad

+0

@Rad: Вы добавили бросок, который не имеет эффекта (по крайней мере, я считаю, что он работает без него, это слишком давно, что я проверил), и вы использовали 'sizeof (int *)' вместо 'sizeof (int)'. Все системы, о которых я знаю, реализуют 'int *' как простой 'int', так что это было бы одинаково. Однако я согласен с тем, что лучше писать 'int *', поэтому я изменил свой ответ. – yankee

+0

Спасибо за информацию. Моя точка была 'sizeof (int *)', а не кастинг. Просто, чтобы убедиться, что я правильно понял, что об этом: 'sizeof (char *)'. То, как я понимаю, 'sizeof (type *)' возвращает размер адреса на машине (может быть 4 или 8), но 'sizeof (type)' возвращает размер этого конкретного типа (например, если он возвращает 'char' 1). Правильно ли это? – Rad

0

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

#define N_a 2 
#define N_b 3 

typedef struct arr 
{ 
    int val[N_a][N_b]; 
} arr; 

arr array  = {{{11,12,13},{14,15,16}}}; 
arr array_new = {{{21,22,23},{24,25,26}}}; 

int main() 
{ 
    arr *p_array; 
    arr *p_array_new; 

    p_array  = &array; 
    p_array_new = &array_new; 
    printf("%d %d\n", p_array->val[1][2], p_array_new->val[1][2]); 
    // output: 16 26 

    p_array  = &array_new; 
    p_array_new = &array; 
    printf("%d %d\n", p_array->val[1][2], p_array_new->val[1][2]); 
    // output: 26 16 
} 
+0

Извините, я изо всех сил стараюсь следовать этому. Итак, что же делает блок typedef struct? Что, если у меня уже есть все элементы из моих массивов «array» и «array_new»? – thay2302

+0

Он просто инкапсулирует определение/размеры массива, чтобы помочь с индексированием. Если у вас уже есть данные массива, просто инициализируйте указатели на него: 'arr * p_array = your_array_address;' – nnn

+0

Итак, если у меня есть значения, тогда я должен просто использовать «* p_array = & array», «* p_array_new = & array_new», "p_array = & array_new" и "p_array_new = & array"? – thay2302