Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   raised exception class EAccesViolation при вызове LSQ_InsertFrontElement (http://forum.oszone.net/showthread.php?t=256493)

pkkirill 17-03-2013 07:52 2112824

raised exception class EAccesViolation при вызове LSQ_InsertFrontElement
 
что-то в функции LSQ_InsertFrontElement неправильно сделано


вот фаилы:
.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 2112839

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

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

Посмотрите Переполнение буфера и Переполнение буфера для чайника(последняя для новичков, но не чайников)

pkkirill 18-03-2013 09:57 2113470

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

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

lxa85 18-03-2013 13:41 2113575

Цитата:

Цитата pkkirill
Я правильно понимаю? »

Понимаешь то правильно, только делаешь не правильно.
Смотри еще наглядней.
Есть карта политическая карта мира (оперативная память). На карте есть государства Европа, Россия, Китай и т.д. всё как полагается. Эта территория отведена под страны (под программы). Ты делаешь переменную-ссылку, допустим на Францию (con). А затем хочешь легким росчерком пера расширить ее границы. Мол, ребят, соседние государства, простите, но мне тут ваши луга и леса нужны, поэтому отныне вы (size+1, хопа!) мои! Ни тебе согласования границ (межевание, кадастровая регистрация, международные отношения), ни военной экспансии, ничего! Просто взял карандашом и нарисовал границы как тебе нравятся.
Непойдет. Неа :no:
Хочешь расширять границы -- вызывай процедуры согласования земель. Оператор new или ему подобный.

pkkirill 18-03-2013 17:12 2113712

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 2113750

Можно получить полный код проекта? (Если не полный, то воспроизводимый с инструкциями)
Какая среда разработки используется?
Цитата:

Цитата pkkirill
EAccesViolation »

Здесь есть достаточно интересный анализ возникновения данной ошибки. Правда на Delphi, но сути я думаю не изменит.

pkkirill 19-03-2013 08:29 2114152

вот все что из папки с проектом
среда C++ Builder 6

pkkirill 21-03-2013 19:05 2115759

все дело было в неправильном вызове функции 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();


Время: 19:07.

Время: 19:07.
© OSzone.net 2001-