Ошибка нарушение доступа для чтения

Задача: По данным n отрезкам необходимо найти множество точек минимального размера, для которого каждый из отрезков содержит хотя бы одну из точек.

В первой строке дано число 1≤n≤100 отрезков. Каждая из последующих n строк содержит по два числа 0≤l≤r≤109, задающих начало и конец отрезка. Выведите оптимальное число m точек и сами m точек. Если таких множеств точек несколько, выведите любое из них.

Мое решение:

void swap(int *a1, int *a2, int M);
void sort(int **a, int N, int M);
void greedy(int **a, int *x, int N);

int main()
{
int **a;//двумерный массив отрезков
int N;
int M=2;
int *x;//одномерный массив точек

cout << "Enter N: "; //ввод количества отрезков
cin>>N;

x = new int[N]; //инициализация массива, который потом станет массивом точек
for (int i=0; i<N; i++)
    x[i]=0;

a = new int *[N];
for (int i = 0; i < N; i++)
    a[i] = new int [M];
//ввод концов отрезков    
for (int i = 0; i < N; i++)
{
    for (int j = 0; j < M; j++)
    {
        cin >> a[i][j];
    }
}
//вывод до сортировки
cout <<endl << "Before sorting:" << endl;

for (int i = 0; i < N; i++)
{
    for (int j = 0; j < M; j++)
        cout << std::setw(3) << a[i][j] << " ";
        cout << endl;
}


sort(a, N, M);//сортировка массива

//вывод после сортировки
cout << endl << "After sorting:" << endl;

for (int i = 0; i < N; i++)
{
    for (int j = 0; j < M; j++)
        cout << setw(3) << a[i][j] << " ";

    cout << endl;
}
//вызов функции с жадным алгоритмом
greedy(a,x, N);

for (int i=0; i<=N; i++)
    cout<<x[i]<<' ';

system("pause");
return 0;
}


void swap(int *a1, int *a2, int M)//меняет 2 строки местами
{
for (int i = 0; i < M; i++)
{
    int temp = a1[i];
    a1[i] = a2[i];
    a2[i] = temp;
    }
}

void sort(int **a, int N, int M)//сортировка пузырьком отрезков по правой   точке 
{
for (int i = 0; i < N; i++)
    for (int j = N - 1; j > i; j--)
        if (a[j - 1][1] >a[j][1])
            swap(a[j - 1], a[j], M);
}

void greedy(int **a, int *x,  int N)
{
int i=0;
int k=0;
while (i<=N)
{
    x[k]=a[i][1];
    i++;
    while ((x[k]>=a[i][0]) && (x[k]<=a[i][1]))
    {i++;}
    k++;
}

}

Но программа падает с ошибкой: Нарушение прав доступа при чтении. Может, кто видит, почему?

Не понимаю один момент, который заключается в следующем: мне необходимо получить данные из двоичного файла (.bin), куда раннее были записаны данные в виде двух строчек string и двух чисел int (структуры, в общем), при исполнении кода:

void Opf() {
	if ((fl = fopen(flName, "rb")) == NULL) {
		cout << "Ошибка открытия файла..." << endl;
		exit(1);
	}
	nst = 0;
	TBook book;
	while (true)
	{
		int nwrt = fread(&book, sizeof(TBook), 1, fl);
		if (nwrt != 1) { break; }
		books[nst] = book;
		cout << books[nst].name << " " << " " << books[nst].author << " " 
			<< books[nst].yearof << " " << books[nst].pages << endl;
		nst++;
	}
	fclose(fl);
}

Выдаёт следующую ошибку:

Вызвано необработанное исключение: нарушение доступа для чтения.
**_Pnext** было 0x61747353.

В чём может быть ошибка или же как можно это обойти?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
#include <iostream>
#include <ctime>
//#include <stdio.h>
using namespace std;
struct Node
{
    int key;
    struct Node* next;
    struct Node* prev;
};
class List
{
private:
    int key = 0;
    size_t size = 0;
    Node* head = NULL;
    Node* tail = NULL;
public:
    List()
    {
        head = tail;
        size;
        cout << "List is created!" << endl;
    }
    List (int a)
    {
        int elementov{}, N{}, K{}, tmpHand[100] = {}, tmpRand{};
        if (a == 2)
            Rand();
 
        if (a == 1)
            Hand();
            
        cout << "Elements are created!" << endl;
    }
    ~List()
    {
        Node* current = head;
        while (current != 0) {
            Node* next = current->next;
            delete current;
            current = next;
        }
        head = 0;
        cout << "Destructor deleted list!" << endl;
    }
    
    
    Node* Get_node(int number);
    Node* Create_node(int key);
    void Insert(const int key);
    void Print();
    void Pop_front();
    void Swap(Node* const before1, Node* const before2);
    void Append(const int num);
    int Get_Value(int N);
    void Inverse_sublist(const int K, const int N);
    void Hand();
    void Rand();
};
 
 
// получение адреса элемента по его порядковому номеру (счет от 1 )
Node* List::Get_node(int number)
{
    int i;
    Node* scan = this->head;
 
    if (scan == nullptr)
        return 0;
 
    for (i = 1; i < number; i++)
        scan = scan->next;
 
    return scan;
}
 
void List::Hand()
{
    int tmpHand[100]{}, elementov{};
     for (int i = elementov; i > 0; i--)
            {
                cout << "Введите элемент списка: n" << endl;
                cin >> tmpHand[i];
                Append(tmpHand[i]);
            }
}
 
void List::Rand()
{
    int tmpRand{}, elementov{};
    for (int i = 0; i < elementov; i++)
    {
        tmpRand = rand() % 100;
        Insert(tmpRand);
    }
}
 
Node* List::Create_node(int key)
{
    Node* new_node = (Node*)malloc(sizeof(Node));
    if (new_node) {
        new_node->key = key;
        new_node->next = NULL;
    }
        return new_node;
    
}
// вставка элемента в начало списка
void List::Insert(const int key)
{
    Node* add = Create_node(key);
    if (this->head != NULL)
        add->next = this->head;
    this->head = add;
    this->size++;
}
 
// вывод списка на экран
void List::Print()
{
    Node* scan = this->head;
    printf("List items: ");
    while (scan)
    {
        printf("%d -> %p ", scan->key, scan->next);
        scan = scan->next;
    }
}
 
// удаление элемента из начала ЛОС
void List::Pop_front()
{
    Node* del = this->head;
    this->head = del->next;
    free(del);
    this->size--;
}
 
// обмен местами двух элементов ЛОС
void List::Swap(Node* const before1, Node* const before2)
{
    Node* self1, * self2, * tmp;
    // before1 = Get_node(list, N1-1);
    // before2 = Get_node(list, N2-1);
    self1 = before1->next;
    self2 = before2->next;
    tmp = before1->next;
    before1->next = before2->next;
 
    before2->next = tmp;
    tmp = self1->next;
    self1->next = self2->next;
    self2->next = tmp;
 
}
 
void List::Append(const int num)
{
    Node* const add_node = Create_node(num);
    this->size++;
 
    // если список пуст
    if (!this->head)
    {
        this->head = this->tail = add_node;
    }
 
    this->tail->next = add_node;
    this->tail = add_node;
}
 
int List::Get_Value(int N)
{
    Node* tmp = Get_node(N);
    return tmp->key;
}
 
void List::Inverse_sublist(const int K, const int N)
{
    int i, j;
    Node* left = Get_node(K - 1);
    if (left == nullptr)
        return;
    Node* right;
    for (i = 0; i < N / 2; i++)
    {
        //right = left->next;//может быть сделать так?
        right = left;
        for (j = 0; j < (N - 2 * i) && right->next != nullptr; j++)
            right = right->next;
 
        Swap(left, right);
        left = left->next;
    }
}
 
//--------------------------------------------------------------
 
int main(int argc, char* argv[])
{
    //logo();
    printf("В списке целых ненулевых элементов инвертировать K элементов начиная с Nn");
    srand((unsigned int)time(NULL));
    int i = 0, tmpRand = 0;
    int tmpHand[100] = {};
    //ClassList::Node* node_a = 0;
    //ClassList::Node* node_b = 0;
 
    FILE* config;
    char Conf_Name[50] = "testo.cfg", buffer[100];
    int sposob{}, elementov{}, K{}, N{};
    if ((config = fopen(Conf_Name, "r")) == NULL) {
        puts("Config file error!!!");
        puts("Press Enter!!!");
        std::cin.get(); exit(0);
    }
 
    fgets(buffer, 80, config);
    if (!strstr(buffer, "#!MYCONFIG")) {
        puts("Config file error!!!");
        puts("Press Enter!!!");
        std::cin.get(); fclose(config);
        exit(0);
    }
 
    while (true)
    {
        fgets(buffer, 80, config);
        if (feof(config))break;
        if (buffer[0] == '#')continue;
        if (buffer[0] == '!') { puts(buffer); continue; }
        if (strstr(buffer, "sposob=")) {
            sposob = atoi(buffer + strlen("sposob="));
            continue;
        }
        if (strstr(buffer, "elementov=")) {
            elementov = atoi(buffer + strlen("elementov="));
            continue;
        }
        if (strstr(buffer, "K=")) {
            K = atoi(buffer + strlen("K="));
            continue;
        }
        if (strstr(buffer, "N=")) {
            N = atoi(buffer + strlen("N="));
            continue;
        }
 
    }
    puts("=============Result of parsing config file ========");
    cout << "sposob = " <<  sposob << endl;
    cout << "elementov = " <<  elementov << endl;
    cout  << "K = " <<  K << endl;
    cout << "N = " <<  N << endl;
    cout << "Press Enter!!!" << endl;
    std::cin.get(); fclose(config);
 
 
    if (elementov > 20)
    {
        printf("Слишком много элементов в списке! Выход...n");
        return 1;
    }
    if (sposob != 1 && sposob != 2)
    {
        printf("Некорректный способ заполнения спискаn");
        return 1;
    }
    if (K + N > elementov)
    {
        printf("Некорректные данные в конфигурационном файле (N + K > элементовn)");
        return 1;
    }
    if (N > elementov)
    {
        printf("Некорректные данные: количество инвертируемых элементов больше чем элементов в спискеn");
        return 1;
    }
 
 
    // "объект" ЛОС с инициализацией
    List list(sposob);
    list.Print();
    list.Inverse_sublist(K, N);
    list.Print();
 
}

I am currently working on the BlackJack project, but there is an error showing «exception Unhandled: Unhandled exception thrown: read access violation. this was 0x4.». I am not quite sure which part I did wrong, and the program sometimes runs normally sometimes shows that exception. In draw_card function, it returns a value of a random number. For example: if we get 13, the value will be 10. It also returns the name of the card and the type of the card such as 13 corresponds to king.

int main()
{
    srand(time(0));
    unsigned bet;
    int player = 0 , dealer = 0;
    string card , type;

    cout << "You have $100. Enter bet: ";
    cin >> bet;
    
    cout << "Your cards are:" << endl; 
    player += draw_card(card, type, player);
    cout << "  "+card + " of " + type << endl;
    player += draw_card(card, type, player);
    cout << "  " + card + " of " + type << endl << endl << endl;
}

int draw_card(string& card, string& type, int drawer_points) {
    int randomNumber;  //between 1 and 13
    int suite;         //between 1 and 4 to determine the suite of the card.

    randomNumber = rand() % 13 + 1;
    suite = rand() % 4 + 1;
    
    card = getRank(randomNumber);
    type = getSuit(suite);

    if (randomNumber == 13 || randomNumber == 12 || randomNumber == 11) {
        return 10;
    }else if (randomNumber == 1) {
        int ace1 = 21 - (drawer_points + 1);
        int ace2 = 21 - (drawer_points + 11);

        return ace1 < ace2 ? 1 : 11;
    }
    else
    {
        return randomNumber;
    }
}


string getSuit(int suit) {
    
    switch (suit)
    {
    case 0:
        return "spades";
        break;
    case 1:
        return "clubs";
        break;
    case 2:
        return "diamonds";
        break;
    case 3:
        return "hearts";
        break;
    default:
        break;
    }
    
}

string getRank(int rank) {
    switch (rank)
    {
    case 13:
        return "King";
        break;
    case 12:
        return "Queen";
        break;
    case 11:
        return "Jack";
        break;
    case 1:
        return "Ace";
        break;
    case 2:
        return "Two";
        break;
    case 3:
        return "Three";
        break;
    case 4:
        return "Four";
        break;
    case 5:
        return "Five";
        break;
    case 6:
        return "Six";
        break;
    case 7:
        return "Seven";
        break;
    case 8:
        return "Eight";
        break;
    case 9:
        return "Nine";
        break;
    case 10:
        return "Ten";
        break;
    default:
        break;
    }

user438383's user avatar

user438383

5,5858 gold badges28 silver badges41 bronze badges

asked Jan 18, 2022 at 18:12

Danny Zhao's user avatar

5

You generate

suite = rand() % 4 + 1;

This is a random number between 1 and 4 inclusive.

You then call

getSuit(suite);

But getSuit only has switch branches for values between 0 and 3 inclusive:

switch (suit)
{
case 0:
    return "spades";
    break;
case 1:
    return "clubs";
    break;
case 2:
    return "diamonds";
    break;
case 3:
    return "hearts";
    break;
default:
    break;
}

Not returning a value from a function that is declared to return a value is undefined behaviour.

answered Jan 18, 2022 at 18:27

konsolas's user avatar

konsolaskonsolas

1,00111 silver badges24 bronze badges

A few functions like getSuit and getRank in your code don’t return a value if only the default case of their switch statement is executed.

You can return an empty string in the default cases:

default:
        return ""; // empty string

And in the call site, check to see if the returned value is empty using the empty function.

Another way is to use std::optional<T> like below:

std::optional<string> getSuit( const int suit )
{
    switch (suit)
    {
    case 0:
        return "spades";
    case 1:
        return "clubs";
    case 2:
        return "diamonds";
    case 3:
        return "hearts";
    default:
        return { }; // empty optional
    }
}

And in the call site:

std::optinal<std::string> type { getSuit(suite) };

if ( type ) // if optional has value
{
    // extract and use the value inside of optional
    type.value( );
}

Keep in mind that if the optional does not have a value, using value() will throw. You can use value_or() instead which does not throw.

answered Jan 18, 2022 at 18:28

digito_evo's user avatar

digito_evodigito_evo

3,1742 gold badges13 silver badges40 bronze badges

2

#c #pointers #exception #null #sdl

#c #указатели #исключение #null #sdl

Вопрос:

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

GameScreenManager.cpp:

 #pragma once
#include <SDL.h>
#include "Commons.h"
#include "GameScreenManager.h"
#include "GameScreenLevel1.h"
#include "GameScreen.h"

GameScreenManager::GameScreenManager(SDL_Renderer* renderer, SCREENS startScreen)
{
    SDL_Renderer* mRenderer;
    mRenderer = NULL;
    ChangeScreen(startScreen);
}

GameScreenManager::~GameScreenManager()
{
    mRenderer = NULL;
    delete mCurrentScreen;
    mCurrentScreen = NULL;
}

void GameScreenManager::Render()
{
    mCurrentScreen->Render();
}

void GameScreenManager::update(float deltaTime, SDL_Event e)
{
    mCurrentScreen->Update(deltaTime, e);
}

void GameScreenManager::ChangeScreen(SCREENS newScreen)
{
    //Clear up the old screen
    if (mCurrentScreen != NULL)
    {
        delete mCurrentScreen;
    }

    GameScreenLevel1* tempScreen;


    switch (newScreen)
    {
    case SCREEN_INTRO:
        break;
    case SCREEN_MENU:
        break;
    case SCREEN_LEVEL1:
        tempScreen = new GameScreenLevel1(mRenderer);
        mCurrentScreen = (GameScreen*)tempScreen;
        tempScreen = NULL;
        break;
    case SCREEN_LEVEL2:
        break;
    case SCREEN_GAMEOVER:
        break;
    case SCREEN_HIGHSCORES:
        break;
    default:
            break;
    }
}
 

GameScreenManager.h:

 #pragma once
#ifndef _GAMESCREENMANAGER_H
#define _GAMESCREENMANAGER_H
#include <SDL.h>
#include "Commons.h"

class GameScreen;

class GameScreenManager
{
    private:
        SDL_Renderer*    mRenderer;
        GameScreen*      mCurrentScreen;

    public:
        GameScreenManager(SDL_Renderer* renderer, SCREENS startScreen);
        ~GameScreenManager();

        void Render();
        void update(float deltaTime, SDL_Event e);
        void ChangeScreen(SCREENS newScreen);
};

#endif //_GAMESCREENMANAGER_H
 

В настоящее время проблема возникает в строке 24;

     mCurrentScreen->Render();
 

Однако, если я закомментирую эту строку, она появится в строке 29:

     mCurrentScreen->Update(deltaTime, e);
 

«Возникло необработанное исключение: нарушение доступа для чтения.
это был nullptr. произошло »

Комментарии:

1. Программа часто вылетает за много миль от того места, где на самом деле была ошибка. Сообщение об ошибке this было nullptr предполагает, что вы должны выяснить, почему this это было nullptr . Было mCurrentScreen = (GameScreen*)tempScreen; пропущено?

Ответ №1:

По-видимому, поле mCurrentScreen имеет значение NULL при вызове Render() или update() . Либо защитите вызовы, проверив mCurrentScreen на NULL:

 void GameScreenManager::Render()
{
    if (mCurrentScreen != NULL)
        mCurrentScreen->Render();
}

void GameScreenManager::update(float deltaTime, SDL_Event e)
{
    if (mCurrentScreen != NULL)
        mCurrentScreen->Update(deltaTime, e);
}
 

или убедитесь, что установлен mCurrentScreen перед вызовом Render() или Update() .

Комментарии:

1. Я добавил операторы if, чтобы проверить, является ли mCurrentScreen != NULL, и действуйте соответственно, однако я все равно получаю исключение, однако на этот раз для операторов if.

2. установите для mCurrentScreen значение NULL после удаления его в ChangeScreen()

3.Если mCurrentScreen не гарантируется, что перед его использованием будет указано на что-то безопасное, вы обречены окружать каждое использование с if (mCurrentScreen != NULL) помощью . Это воспроизводит ошибку, потому что вы будете постоянно находить случаи, когда она не была установлена. и не проверялось. Вам гораздо лучше убедиться, что это mCurrentScreen всегда указывает на что-то безопасное.

4. Я установил mCurrentScreen равным NULL после удаления mCurrentScreen и все равно получаю исключение. Я даже полностью удалил этот оператор if и все равно не повезло.

5. Если исключение генерируется в операторе if, вероятно, что-то не так с вашей сборкой — попробуйте очистить / перестроить, удалить все промежуточные файлы и т.д. Вы также должны инициализировать mCurrentScreen равным NULL в конструкторе, но это не поможет вам создавать исключения для «if».

Ответ №2:

Как оказалось, я фактически пропустил строку кода, которая устанавливала mCurrentScreen, и оператор switch проходил неправильно, поэтому он не срабатывал. Кроме того, переменная mRenderer не была настроена правильно ни в одном из моих файлов cpp, поэтому она возвращала «Недопустимый рендеринг» всякий раз, когда я пытался его использовать. Ниже приведен рабочий код, спасибо всем за помощь, он направил меня в правильном направлении;

 #pragma once
#include <SDL.h>
#include "Commons.h"
#include "GameScreenManager.h"
#include "GameScreenLevel1.h"
#include "GameScreen.h"

GameScreenManager::GameScreenManager(SDL_Renderer* renderer, SCREENS startScreen)
{
    mRenderer = renderer;
    GameScreen* mCurrentScreen = NULL;
    ChangeScreen(startScreen);
}

GameScreenManager::~GameScreenManager()
{
    mRenderer = NULL;
    delete mCurrentScreen;
    mCurrentScreen = NULL;
}

void GameScreenManager::Render()
{
    mCurrentScreen->Render();
}

void GameScreenManager::Update(float deltaTime, SDL_Event e)
{
    mCurrentScreen->Update(deltaTime, e);
}

void GameScreenManager::ChangeScreen(SCREENS newScreen)
{
    //Clear up the old screen
    if (mCurrentScreen != NULL)
    {
        delete mCurrentScreen;
    }

    GameScreenLevel1* tempScreen;

    switch (newScreen)
    {
    case SCREEN_INTRO:
        break;
    case SCREEN_MENU:
        break;
    case SCREEN_LEVEL1:
        tempScreen = new GameScreenLevel1(mRenderer);
        mCurrentScreen = (GameScreen*)tempScreen;
        tempScreen = NULL;
        break;
    case SCREEN_LEVEL2:
        break;
    case SCREEN_GAMEOVER:
        break;
    case SCREEN_HIGHSCORES:
        break;
    default:
        break;
    }
}
 

Понравилась статья? Поделить с друзьями:
  • Ошибка нарушена процедура криптографической подготовки декларации
  • Ошибка нарушен формат представления декларации
  • Ошибка наружного блока кондиционера что это
  • Ошибка наружного блока кондиционера lessar ed
  • Ошибка наружного блока кондиционера haier