Повреждение кучи из-за выделения памяти с помощью malloc: почему это произошло?

Хорошо, я пытался реализовать 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;
}

Кстати, я новичок в указателях, так что не удивляйтесь, если есть ошибки.
Что я делаю неправильно?

0

Решение

Пожалуйста, будьте осторожны с другими предложениями! Ответ зависит от того, как будет использоваться ваша запись. В других ответах говорится, что вы должны изменить свой вызов 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 слишком велик для этого перемещения).

4

Другие решения

Замените строку с помощью malloc следующим образом:

int* midbuf = (int *) malloc(num*sizeof(int));

Проблема в том, что вы выделены не num элементы Int, но num байт.

3

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 ints. С int обычно занимает более одного байта, доступ к которому осуществляется за пределами.

1

нарушение доступа к памяти?

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

0

Проблема в том, что вы злоупотребляете num байтов в midbufи затем копирование num целиком в это. С int на большинстве платформ больше байта, у вас проблема. Измени свой malloc в num*sizeof(int) и у вас не будет этой проблемы.

0

Есть две проблемы, которые нужно рассмотреть

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 состояние.

0
#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 байта. Не беспокойтесь слишком сильно, если это звучит технически, это будет важно, когда вы доберетесь до чего-то действительно низкого уровня;)

-1
По вопросам рекламы [email protected]