Не могу очистить массив [закрыт]

119
17 ноября 2020, 09:40
Закрыт. Этот вопрос не по теме. Ответы на него в данный момент не принимаются.

Хотите улучшить этот вопрос? Обновите вопрос так, чтобы он вписывался в тематику Stack Overflow на русском.

Закрыт 1 год назад.

Улучшить вопрос

Задача программы: считать из файла строку, каждое слово из которой необходимо присвоить отдельному элементу массива. Далее, найти 3 самых длинных и 3 самых коротких слова, а затем вывести все слова в порядке, обратном алфавитному. Все задачи написанная мною программа решает, но я не могу очистить память. Проблема в куске программы, в котором элементам массива b присваивается строка из переменной token (все это в цикле while). Именно после сей действия не получается воспользоваться delete[]. Все массивы уже сделал одной размерности, но все равно не помогло. В чем может быть проблема? Код прилагаю ниже. Заранее спасибо!

#define _CRT_SECURE_NO_WARNINGS
#include "stdafx.h"
#include <stdlib.h>
#include <stdbool.h>
#include <iostream>
#include <locale.h>
#include <windows.h>
#include <ctype.h>
#include <fstream>
#include <malloc.h>
#include <conio.h>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
using namespace std;
void bigswap(int i, int len, int biggest[]) {
    if (len > biggest[0]) {
        biggest[4] = biggest[2];
        biggest[5] = biggest[3];
        biggest[2] = biggest[0];
        biggest[3] = biggest[1];
        biggest[0] = len;
        biggest[1] = i - 1;
    }
    else {
        if (len > biggest[2]) {
            biggest[4] = biggest[2];
            biggest[5] = biggest[3];
            biggest[2] = len;
            biggest[3] = i - 1;
        }
        else {
            if (len > biggest[4]) {
                biggest[4] = len;
                biggest[5] = i - 1;
            }
        }
    }
}
void littleswap(int i, int len, int little[]) {
    if (len < little[0]) {
        little[4] = little[2];
        little[5] = little[3];
        little[2] = little[0];
        little[3] = little[1];
        little[0] = len;
        little[1] = i - 1;
    }
    else {
        if (len < little[2]) {
            little[4] = little[2];
            little[5] = little[3];
            little[2] = len;
            little[3] = i - 1;
        }
        else {
            if (len < little[4]) {
                little[4] = len;
                little[5] = i - 1;
            }
        }
    }
}
void gettext(char **b, int kolslov) {
    printf("Слова, выведенные в порядке, обратном алфавитному:\n\n");
    for (int i = 0; i < kolslov; i++) {
        printf("%s\n", b[i]);
    }
    printf("\n\n");
}
void minusswap(char **b, int kolslov) {
    for (int i = 0; i < (kolslov - 1); i++) {
        for (int j = i + 1; j < kolslov; j++) {
            if ((int)b[i][0] < 91) {
                b[i][0] = (char)((int)b[i][0] + 32);
            }
            if ((int)b[j][0] < 91) {
                b[j][0] = (char)((int)b[j][0] + 32);
            }
            if (strcmp(b[i], b[j]) < 0) swap(b[i], b[j]);
        }
    }
}
void initialization(int biggest[], int little[]) {
    for (int i = 0; i < 6; i++) {
        biggest[i] = -1;
        little[i] = 100;
    }
}

int main() {
    char **b, *buffer, *token, delims[] = " \n.,!?/<>|)(*:;\"";
    const int len_text = 300;
    int max_len = 0, size_len = 0, Nslov = 0, kolslov = 0, menu = 0;
    int biggest[6], little[6];
    FILE *load = NULL;
    setlocale(LC_ALL, "Russian");
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);
    printf("Данная программа считывает ваш текст из файла, находит в нем три самых длинных и три самых коротких слова, а также располагает все слова в порядке, обратном алфавитному.\n\n\n");
    system("pause");
    system("cls");
    for (;;) {
        load = fopen("FILE.txt", "r");
        fscanf_s(load, "%i\n", &kolslov);
        initialization(biggest, little);
        b = new char*[kolslov];
        /*for (int i = 0; i < kolslov; i++) {
            b[i] = new char[30];
        }*/
        buffer = new char[300];
        token = new char[300];
        fgets(buffer, len_text, load);
        printf("Первоначальный текст:\n\n%s\n\n\nНайденные слова:\n\n", buffer);
        token = strtok(buffer, delims);
        int i = 0;
        while (token != NULL)
        {
            int len = strlen(token);
            b[i] = new char[300];
            b[i] = token;
            Nslov++;
            printf("%s\n", b[i]);
            i++;
            bigswap(i, len, biggest);
            littleswap(i, len, little);
            token = strtok(NULL, delims);
        }
        printf("\n\nТри самых длинных слова в данном тексте:\n\n%s\n%s\n%s\n\n", b[biggest[1]], b[biggest[3]], b[biggest[5]]);
        printf("\nТри самых коротких слова в данном тексте:\n\n%s\n%s\n%s\n\n\n", b[little[1]], b[little[3]], b[little[5]]);
        minusswap(b, kolslov);
        gettext(b, kolslov);
        system("pause");
        for (int i = 0; i < kolslov; i++) {
            printf("\n%s\n", b[i]);
            delete[] b[i];
        }
        delete[] b;
        fclose(load);
        system("pause");
        system("cls");
    }
    system("pause");
}

Код того места, где появляется проблема, которая в дальнейшем вызывает ошибку:

while (token != NULL)
        {
            int len = strlen(token);
            b[i] = new char[300];
            b[i] = token;
            Nslov++;
            printf("%s\n", b[i]);
            i++;
            bigswap(i, len, biggest);
            littleswap(i, len, little);
            token = strtok(NULL, delims);
        }

Код, при прохождении которого появляется ошибка:

for (int i = 0; i < kolslov; i++) {
    printf("\n%s\n", b[i]);
    delete[] b[i];
}
delete[] b;

Ошибка: вызвано срабатывание точки останова в функции delete_scalar.cpp

//
// delete_scalar.cpp
//
//      Copyright (c) Microsoft Corporation. All rights reserved.
//
// Defines the scalar operator delete.
//
#include <crtdbg.h>
#include <malloc.h>
#include <vcruntime_new.h>

void __CRTDECL operator delete(void* const block) noexcept
{
    #ifdef _DEBUG
    _free_dbg(block, _UNKNOWN_BLOCK);
    #else
    free(block);
    #endif
}

Ошибка в строке: _free_dbg(block, _UNKNOWN_BLOCK);

Answer 1

Проблема явно с выделениями памяти. Мне к примеру очень не нравится переменная kolslov - там может оказаться все, что угодно.

А причина похоже в строках b[i] = new char[300]; b[i] = token; - вначале выделяем память, а потом ее перезатираем. Но это лишь цветочки. Массив token создан до входа в цикл. А это значит, что один и тот же массив будет присвоен элементам массива b. И когда память освобождается, то пытаемся удалить один и тот же блок дважды. И получаем от runtime по пальцам.

Но потом я посмотрел ещё внимательней и понял, что тут все очень печально. Следим за руками:

  • вначале для token выделяем память
  • потом в него записываем результаты strtok (предварительно выделенную память уже потеряли)
  • потом, это указатель на средину buffer размазываем по массиву b (да, теперь b хранит указатели на средину buffer, плюс, память, выделенная под элементы массива b уже теряется.
  • в конце, когда память освобождается, delete[] получает указатель в середину массива buffer и пытается его удалить, но это не самая лучшая идея и крешится.

Что делать? как минимум, не заниматься писанием на си и полуручным управлением памятью (или все таки переписать все на си и поменять тег). Также не стоит смешить си и с++ функции. И напоследок, изучить, как работает strtok (и узнать, что она портит исходный массив. Но у нее есть парная функция, которая этого не делает).

READ ALSO
Проблема с JS/jQuery и Brackets

Проблема с JS/jQuery и Brackets

Вот такая проблема JS/jQuery

131
Почему ajax запрос завершается с ошибкой?

Почему ajax запрос завершается с ошибкой?

У меня есть REST контроллер, который может удалять/вставлять/редактировать данные из бд, отображаю на jsp странице таблицу с соответствующими...

109
Почему не открывается модальное окно?

Почему не открывается модальное окно?

Сделал модальное окно с помощью jqueryВесь html код располагается на jsp странице, также использую spring-boot, tomcat

133