Войти

Показать полную графическую версию : raised exception class EAccesViolation при вызове LSQ_InsertFrontElement


pkkirill
17-03-2013, 07:52
что-то в функции LSQ_InsertFrontElement неправильно сделано

http://content.foto.mail.ru/mail/pk.kirill/_answers/i-138.jpg
вот фаилы:
.c http://yadi.sk/d/SMXZ5cLR3JVRr
.h http://yadi.sk/d/Go_5SIwB3IKuM
или ниже код:
//___________________________________

#ifndef LINEAR_SEQUENCE_H_INCLUDED
#define LINEAR_SEQUENCE_H_INCLUDED
#include <stdlib.h>


typedef int LSQ_BaseTypeT; /* Тип хранимых в контейнере значений */

typedef void* LSQ_HandleT; /* Дескриптор контейнера */

#define LSQ_HandleInvalid NULL /* Неинициализированное значение дескриптора контейнера */

typedef void* LSQ_IteratorT; /* Дескриптор итератора */

typedef int LSQ_IntegerIndexT; /* Тип целочисленного индекса контейнера */

/* Функция, создающая пустой контейнер. Возвращает назначенный ему дескриптор */
extern LSQ_HandleT LSQ_CreateSequence(void);

/* Функция, добавляющая элемент в начало контейнера */
extern void LSQ_InsertFrontElement(LSQ_HandleT handle, LSQ_BaseTypeT element);

#endif
//______________________________________________________________________________
//______________________________________________________________________________

typedef struct LSQ_HandleT //контейнер
{
//LSQ_BaseTypeT *ptr; //Тип хранимых в контейнере значений
LSQ_IntegerIndexT size; //Кол-во элементов //Тип целочисленного индекса контейнера
struct LSQ_Element *HeadElement;//указатель на первый элемент контейнера (вместо void - LSQ_Element)
struct LSQ_Element *TailElement;//указатель на последний элемент контейнера (вместо void - LSQ_Element)
};

typedef struct LSQ_Iterator
{
struct LSQ_Element *CurrentElement;//указатель на текущий эл-т
struct LSQ_HandleT *Container; //указатель на контейнер
};

typedef struct LSQ_Element
{
struct LSQ_Element *PrewElement; //указатели на пред. и след. элемент контейнера
struct LSQ_Element *NextElement;
LSQ_BaseTypeT Data;
LSQ_IntegerIndexT Index; //номер элемента
};
//______________________________________________________________________________

LSQ_HandleT LSQ_CreateSequence() //создать контейнер
{ // Потом все функции надо в отдельный фаил переместить [C++ Warning] linear_sequence.h(100): W8058 Cannot create pre-compiled header: code in header
struct LSQ_HandleT* handle = (struct LSQ_HandleT*)malloc(sizeof(struct LSQ_HandleT));
(*handle).size = 0;
(*handle).HeadElement = NULL;
(*handle).TailElement = NULL;
return (LSQ_HandleT)handle;
}

void LSQ_InsertFrontElement(LSQ_HandleT handle, LSQ_BaseTypeT element) /* Функция, добавляющая элемент в начало контейнера */
{
struct LSQ_Element* ElementHandle = (struct LSQ_Element*)malloc(sizeof(struct LSQ_Element));
struct LSQ_HandleT* con = handle; //делаем типизированный указатель
(*ElementHandle).Data = element;
(*con).size++; //raised exception class EAccesViolation
//(*handle).size++;
//(*(LSQ_Container *)handle).size++;
//((LSQ_Container *)handle)->size++;
if (((*con).size) == 1)
{
(*con).TailElement = ElementHandle;
(*ElementHandle).NextElement = NULL;
}else{
(*ElementHandle).NextElement = (*con).HeadElement;
(*con).HeadElement->PrewElement = ElementHandle;
}
(*ElementHandle).PrewElement = NULL;
(*con).HeadElement = ElementHandle;
}

lxa85
17-03-2013, 09:07
pkkirill, правильно, а что вы хотели?
Вы делаете указатель на некоторую область памяти, а затем делаете "указатель + 1" это несанкционированная попытка доступа к памяти. Такие фокусы запрещены ЕМНИП с 80386 процессоров, когда появился защищенный режим.
Сейчас попробую объяснить на пальцах.

Вот мы получили указатель Handle. Он ссылается на некоторую ячейку памяти. Дальше, вместо того, чтобы вызвать отдельную процедуру выделения памяти, ты говоришь size+1. Что происходит в этом случае? (Во первых я не совсем понял, что за size, но предположу, что размер контейнера; Во вторых плюс один "чего"? Байт, Слово, Длинное слово?)
Указывая на некоторую ячейку А, мы хотим получить прямой доступ к ячейке А+1. Но! Никто не гарантирует, что ячейка А+1 свободна. В ней могут содержать данные других программ! Это потенциально ведет к нарушению целостной работы системы.

Посмотрите Переполнение буфера (http://ru.wikipedia.org/wiki/Переполнение_буфера) и Переполнение буфера для чайника (http://www.securitylab.ru/contest/212095.php)(последняя для новичков, но не чайников)

pkkirill
18-03-2013, 09:57
в поле size хранится кол-во элементов в контейнере
я хочу увеличить значение поля size в структуре, адрес которой хранится в переменной con
то есть по идее (*con).size и есть это значение?
а (*con).size++; должно увеличивать это значение на 1

Я правильно понимаю?
*con мы получаем саму структуру по ее адресу
(*con).size - получаем поле size данной структуры

lxa85
18-03-2013, 13:41
Я правильно понимаю? »
Понимаешь то правильно, только делаешь не правильно.
Смотри еще наглядней.
Есть карта политическая карта мира (оперативная память). На карте есть государства Европа, Россия, Китай и т.д. всё как полагается. Эта территория отведена под страны (под программы). Ты делаешь переменную-ссылку, допустим на Францию (con). А затем хочешь легким росчерком пера расширить ее границы. Мол, ребят, соседние государства, простите, но мне тут ваши луга и леса нужны, поэтому отныне вы (size+1, хопа!) мои! Ни тебе согласования границ (межевание, кадастровая регистрация, международные отношения), ни военной экспансии, ничего! Просто взял карандашом и нарисовал границы как тебе нравятся.
Непойдет. Неа :no:
Хочешь расширять границы -- вызывай процедуры согласования земель. Оператор new (http://ru.wikipedia.org/wiki/New_(C++)) или ему подобный.

pkkirill
18-03-2013, 17:12
size это просто число в структуре типа LSQ_HandleT*, которую мы уже создали в функции LSQ_CreateSequence(), память для этой структуры мы выделили (malloc) и даже присвоили значение полю size=0;
LSQ_HandleT LSQ_CreateSequence() //создать контейнер
{ // Потом все функции надо в отдельный фаил переместить [C++ Warning] linear_sequence.h(100): W8058 Cannot create pre-compiled header: code in header
struct LSQ_HandleT* handle = (struct LSQ_HandleT*)malloc(sizeof(struct LSQ_HandleT));
(*handle).size = 0;
(*handle).HeadElement = NULL;
(*handle).TailElement = NULL;
return (LSQ_HandleT)handle;
}

теперь в функции LSQ_InsertFrontElement память выделяется только для структуры типа LSQ_Element*,
а указатель на стр-ру типа LSQ_HandleT* (память для которой уже выделялась раннее) идет в качестве параметра данной функции,
который затем типизируется таким способом struct LSQ_HandleT* con = handle;

вот кстати C-фаил:
#include <stdio.h>
#include "linear_sequence.h"

int main()
{
LSQ_BaseTypeT e = 9;
LSQ_HandleT sec = LSQ_CreateSequence;
printf("LSQ_CreateSequence %d\n",sec);
LSQ_InsertFrontElement(sec,e);

getchar(); return 0;
}

lxa85
18-03-2013, 17:57
Можно получить полный код проекта? (Если не полный, то воспроизводимый с инструкциями)
Какая среда разработки используется?
EAccesViolation »
Здесь (http://www.gunsmoker.ru/2009/05/access-violation.html) есть достаточно интересный анализ возникновения данной ошибки. Правда на Delphi, но сути я думаю не изменит.

pkkirill
19-03-2013, 08:29
вот все что из папки с проектом (http://yadi.sk/d/iu4YFyN53N-PQ)
среда C++ Builder 6

pkkirill
21-03-2013, 19:05
все дело было в неправильном вызове функции CreateSequence:

#include <stdio.h>
#include "linear_sequence.h"

int main()
{
LSQ_BaseTypeT e = 9;
LSQ_HandleT sec = LSQ_CreateSequence;
printf("LSQ_CreateSequence %d\n",sec);
LSQ_InsertFrontElement(sec,e);

getchar(); return 0;
}

исправил на CreateSequence();




© OSzone.net 2001-2012