Я инициализирую 2 массива так:

x = (double*) malloc(sizeof(double)*n);
xPlus1 = (double*) malloc(sizeof(double)*n);

Во-первых, я не уверен, что именно сейчас представляет собой x или xPlus1, указатель на массив, полный двойников, или массив, полный указателей на двойники? : /

Ответ на этот вопрос, вероятно, влияет на это, но если я выполняю эти различные операции, я не могу заставить его делать то, что я хочу, а именно копировать значения из xPlus1 в x. xPlus1 и x содержат разные значения для каждого индекса, потому что печать после простого цикла for дает желаемый эффект:

for (int i = 0; i < n; i++) {
    x[i] = xPlus1[i];
}

Но используя ...

memcpy(x, xPlus1, sizeof(x));
memcpy(x, &xPlus1, sizeof(x)); 

Если я обращаюсь к x после любого из них в той же функции, x не изменяется, сохраняются старые значения.

memcpy(&x, &xPlus1, sizeof(x)); 

Я считаю, что это заставляет x и xPlus1 указывать на одно и то же место в памяти по выходным данным, которые я получаю. Это потому, что если я изменю x или xPlus1 после этой копии, то оба значения изменятся, если я напечатаю оба массива.

memcpy(&x, xPlus1, sizeof(x)); 

Умирает, исключение: необработанное исключение по адресу 0x011D5626 в MPITemplate.exe: 0xC0000005: место записи нарушения прав доступа 0x00000000.

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

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

Благодарность,

Майк

1
starlight54 4 Ноя 2014 в 18:06
1
xPlus1 УЖЕ является указателем на malloc'd памяти. когда вы выполняете &xPlus1, вы получаете адрес самого указателя, а НЕ память malloc'd. например вы не копируете в свой блок malloc, вы копируете туда, где существует указатель, и уничтожаете все, что идет после него.
 – 
Marc B
4 Ноя 2014 в 18:09
3
Вы пробовали memcpy(x, xPlus1, n * sizeof(double));?
 – 
mch
4 Ноя 2014 в 18:10
X - указатель double, указывающий на блок памяти, выделенный для двойных элементов n. xplus1 тоже делает то же самое, но они находятся в разных местах памяти. если вы напечатаете адреса для всех x и xplus1, вы увидите, что все они разные. Если вы используете & x в качестве аргумента, вы используете указатель указателя, что неверно. Исключение, которое вы получили, в основном говорит вам, что из-за того, что вы одновременно копировали, записывали и читали из одного и того же места, у вас есть проблемы с доступом.
 – 
ha9u63a7
4 Ноя 2014 в 18:14
Тогда я получаю указатели на указатели, которые не работают, думаю, это просто удача, что это не убивает программу, когда я использую memcpy (x, & xPlus1, sizeof (x)); Тогда я думаю, что он использует размер указателя «x», когда я помещаю sizeof (x) не в размер массива, на который он указывает? Я попробую использовать n * sizeof (double)
 – 
starlight54
4 Ноя 2014 в 18:18
Удача - это просто утешение. если вы посмотрите документацию по memcpy, там написано void * memcpy ( void * destination, const void * source, size_t num );, вы ясно увидите, что выполнение memcpy(x, xPlus1, sizeof(x)) полезно для вас. Кроме того, бит const source означает, что ваши исходные данные не изменяются, что вы в конечном итоге сделали и получили ошибку нарушения прав доступа при попытке использовать указатель указателя.
 – 
ha9u63a7
4 Ноя 2014 в 18:20

3 ответа

Лучший ответ

Я инициализирую 2 массива так:

Нет, ты не. Вы не показали определение x и xPlus1, но если это массивы, например:

double x[10];

Ваш код не компилируется. Предполагая, что ваш код компилируется, x и xPlus1 являются указателями на удвоение. Они близки, но не одно и то же.

Во-первых, я не уверен, что именно сейчас представляет собой x или xPlus1, указатель на массив, полный двойников, или массив, полный указателей на двойники? : /

Опять же, вы должны опубликовать их определение, и тогда ваш вопрос не будет иметь никакого смысла. Это указатели, и все, что вы им назначаете, не меняет этого факта. Таким образом, это указатели, содержащие адрес размера блока памяти sizeof(double) * n. Что будет в этой памяти, зависит от вас, вы можете рассматривать это как массив двойников или что-то еще, размер которого меньше или равен sizeof(double) * n.

Но используя ...

memcpy(x, xPlus1, sizeof(x));
memcpy(x, &xPlus1, sizeof(x)); 

Итак, первая строка кода копирует sizeof (double *), вероятно, 8 байтов, то есть одно двойное (что является просто совпадением, что на 64-битной платформе sizeof (double *) == sizeof (double)) из памяти, на которую указывает xPlus1, в память указано x. Итак, вы в основном скопировали один элемент, такой же, как (если вы используете 32-битную платформу, вы бы просто скопировали половину double):

x[0] = xPlus1[0]; 

Вторая строка копирует память, где указатель xPlus1 находится на блоке памяти, на который указывает x. Итак, вы скопировали double * в double x [0], что не имеет особого смысла:

x[0] = (double) xPlus1;

Этот код:

memcpy(&x, &xPlus1, sizeof(x)); 

В основном это сделал (просто запутанный способ):

x = xPlus1;

Следующий код:

memcpy(&x, xPlus1, sizeof(x)); 

Эквивалентно этому:

x = (double *)xPlus1[0]; 

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

Итак, ваш фактический код должен быть:

memcpy( x, xPlus1, sizeof( double ) * n );
2
Slava 4 Ноя 2014 в 18:36
Спасибо за подробный ответ, я считаю, что это совпадение, поскольку он скомпилирован для 32-разрядной версии, он скопировал 4 байта, которые на самом деле были одинаковыми для xPlus1 и x, поэтому, похоже, не повлияли. Теперь я больше понимаю malloc, вы просто заранее выделяете некоторую память, я предполагаю, что это по дизайну, что он может затем использовать нотацию x [3] (например), чтобы определить, что в основном является местоположением 4-го двойника в память, на которую указывает x.
 – 
starlight54
4 Ноя 2014 в 18:53

И x, и xPlus1 должны быть типа double*. Это указатели на массив двойников n.

Итак, когда вы это сделаете:

memcpy(x, xPlus1, sizeof(x));

Поскольку x - это просто double*, он копирует только sizeof(double*) байтов ... то есть 8. Что вы хотите сделать:

memcpy(x, xPlus1, n * sizeof(*x));

Поскольку тип *x - double, поэтому n * sizeof(*x) будет общим байтом памяти, принадлежащей xPlus1: n double s.

4
Barry 4 Ноя 2014 в 18:22
Я просто отлаживаю это сейчас, это имеет смысл, когда я проверяю sizeof (x), он фактически показывает unsigned int для размера 4, но если затем он копирует 4 байта в начало массива x из xPlus1, как получается x [ 0] все еще остается таким же при печати, не должно ли это каким-то образом его разрушить? Если только они не совпадают?
 – 
starlight54
4 Ноя 2014 в 18:26
32-битная машина? Это зависит от того, каким будет x[0] ... независимо от того, эти 8 байтов будут неким допустимым значением double - возможно, ваше назначение просто случайно не изменило младшие 4 байта.
 – 
Barry
4 Ноя 2014 в 18:35
Действительно, это имеет смысл, да, он все равно компилируется для 32-битной версии
 – 
starlight54
4 Ноя 2014 в 18:42

Вы не учли декларации.
Добавляя тип,

double* x = (double*) malloc(sizeof(double)*n);

Проясняет, что x является указателем на double.
В этом конкретном случае двойное x указывает на первый элемент в массиве двойных n.

Что-то вроде этого:

       (------- n doubles  -----)        
      ___________________________
x ===>| | | | | | | | | | | | | |
      ---------------------------

&x даст вам адрес самой переменной x . Это сильно отличается от адреса, который содержит переменная x .
(Если у вас есть int x = 1;, &x, скорее всего, не будет 1.)

memcpy принимает два указателя, один на адресат, а другой на источник, и размер копируемой памяти.
Но sizeof(x) не дает вам размер выделенного вами массива; он дает вам размер x, который является указателем.
(Размер измеряется в кратных sizeof(char), который по определению равен 1, а sizeof(double*) будет 4 (32 бита) или 8 (64 бита) на большинстве современных машин. Таким образом, вы копируете 32 или 64 бит.)

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

Так,

memcpy(x, xPlus1, sizeof(double) * n);

Должен работать как ожидалось.

3
molbdnilo 4 Ноя 2014 в 18:41