Хорошо, я пытался реализовать memmove просто как упражнение по программированию, и я получаю нарушение доступа к памяти в функции memmove, когда пытаюсь использовать malloc. Вот функция:
//Start
void* MYmemmove (void* destination, const void* source, size_t num) {
int* midbuf = (int *) malloc(num); // This is where the access violation happens.
int* refdes = (int *) destination; // A pointer to destination, except it is casted to int*
int* refsrc = (int *) source; // Same, except with source
for (int i = 0;num >= i;i++) {
midbuf[i] = *(refsrc + i); // Copy source to midbuf
}
for (int i = 0;num >= i;i++) {
refdes[i] = *(midbuf + i); // Copy midbuf to destination
}
free(midbuf); // free midbuf
refdes = NULL; // Make refdes not point to destination anymore
refsrc = NULL; // Make refsrc not point to source anymore
return destination;
}
Кстати, я новичок в указателях, так что не удивляйтесь, если есть ошибки.
Что я делаю неправильно?
Пожалуйста, будьте осторожны с другими предложениями! Ответ зависит от того, как будет использоваться ваша запись. В других ответах говорится, что вы должны изменить свой вызов malloc для учета размера int. Однако, если ваша функция memmove будет использоваться для обозначения «переместить это число байтов«тогда реализация будет неправильной. Я бы вместо этого использовал char *, так как это решает сразу несколько проблем.
Кроме того, int
обычно 4 байта, и char
обычно 1 байт. Если void*
адрес, который вы получаете, не выровнен по словам (не кратен 4 байтам), у вас возникнет проблема: чтобы скопировать int, не выровненный по словам, вам придется выполнить несколько операций чтения и маскировки битов. Это неэффективно.
Наконец, нарушение доступа к памяти произошло из-за того, что вы увеличили свой midbuf int
указатель каждый раз и движение вперед 4 байта за раз. Тем не менее, вы только выделили Num байтов, и, таким образом, в конечном итоге попытается получить доступ через конец выделенного региона.
/** Moves num bytes(!) from source to destination */
void* MYmemmove (void* destination, const void* source, size_t num) {
// transfer buffer to account for memory aliasing
// http://en.wikipedia.org/wiki/Aliasing_%28computing%29
char * midbuf = (char *) malloc(num); // malloc allocates in bytes(!)
char * refdes = (char *) destination;
char * refsrc = (char *) source;
for (int i = 0; i < num; i++) {
midbuf[i] = *(refsrc + i); // Copy source to midbuf
}
for (int i = 0; i < num; i++) {
refdes[i] = *(midbuf + i); // Copy midbuf to destination
}
free(midbuf); // free midbuf
// no need to set the pointers to NULL here.
return destination;
}
Копируя побайтово, мы избегаем проблем выравнивания и случаев, когда само num не может быть кратно 4 байтам (например, 3, поэтому int слишком велик для этого перемещения).
Замените строку с помощью malloc следующим образом:
int* midbuf = (int *) malloc(num*sizeof(int));
Проблема в том, что вы выделены не num
элементы Int, но num
байт.
int* midbuf = (int *) malloc(num); // This is where the access violation happens.
int* refdes = (int *) destination; // A pointer to destination, except it is casted to int*
int* refsrc = (int *) source; // Same, except with source
for (int i = 0;num >= i;i++) {
midbuf[i] = *(refsrc + i); // Copy source to midbuf
}
Вы malloc
только num
байт, но в цикле вы пытаетесь скопировать num
int
s. С int
обычно занимает более одного байта, доступ к которому осуществляется за пределами.
нарушение доступа к памяти?
Вы пытаетесь получить доступ к памяти, на которую у вас нет прав доступа. Возможно, у вас нулевой указатель или указатель указывает на другую программу или сегмент кода.
Проблема в том, что вы злоупотребляете num
байтов в midbuf
и затем копирование num
целиком в это. С int
на большинстве платформ больше байта, у вас проблема. Измени свой malloc
в num*sizeof(int)
и у вас не будет этой проблемы.
Есть две проблемы, которые нужно рассмотреть
1. Пространство памяти
(при условии, что MYmemmove
делает пользовательскую реализацию для перемещения ints
как следует из вопроса)
int* midbuf = (int *) malloc(num * sizeof(int));
malloc
на основе байтов, и будет выделять Num байт. int *
это указатель на ints
, Имея в виду midbuf[x]
будет иметь доступ к памяти из midbuf + sizeof(int)*x
, Вы хотите выделить Num ints
вместо этого (размер int зависит от архитектуры, обычно это 4 или 2 байта). Таким образом malloc(num * sizeof(int))
,
2. Массив индексов
for (int i = 0;num > i;i++) {
в C (и C ++) массивы основаны на 0, то есть первый индекс 0
, Вы сделали это правильно. Но это также означает, что если вы резервируете Num ints
, используемые индексы будут из 0
в num-1
, В ваших петлях, i
будет отличаться от 0
в num
, благодаря условию num >= i
это означает, что вы получите доступ num+1
Предметы. Так num > i
(или же i < num
) будет лучше for
состояние.
#include <stdlib.h> // did you included this?void* MYmemmove (void* destination, const void* source, size_t num) {
char *Source = source, *Destination = destination;
char *Middle = malloc( sizeof(char) * num ); // midbuf
for (int i = 0; i < num ; i++) {
Middle[i] = Destination[i]; // Copy source to midbuf
}
for (int i = 0; i < num ; i++) {
Destination[i] = Middle[i]; // Copy midbuf to destination
}
free(Middle); // free memory allocated previously with malloc
return destination;
}
Нарушение доступа может произойти из-за того, что вы не включили библиотеки, необходимые для malloc (стандартный c не выдает ошибки, если вы забыли определение функции). Вам не нужно помечать указатели как NULL, так как в C нет сборки мусора (указатели — это просто указатели. Адреса к точке в памяти, а не в самой памяти).
думать о указателях, как
адрес указателя
0x1243 0x4221
Направление -> {какие-то данные}
Направление = 0x1243
* Назначение = любое значение в настоящее время в адресах 0x4221
Вы также не можете индексировать пустые указатели. Сначала вы должны привести их к какому-либо типу, чтобы компилятор знал, какое смещение им нужно.
Пункт назначения [x] = * (Пункт назначения + x)
значение char равно 1 байту, поэтому указатель char действительно перемещается на x байтов, но int равен 4 байта, а указатель int будет перемещаться на 4 * x байта. Не беспокойтесь слишком сильно, если это звучит технически, это будет важно, когда вы доберетесь до чего-то действительно низкого уровня;)