Как исправить?Вызывает исключение при попытке освободить динамически выделенную память - PullRequest
0 голосов
/ 29 декабря 2018

Это мой первый вопрос, и я пытался найти решение, но, даже если я его нашел, я его не узнал.

Так что, как следует из названия, проблема в том, чтов этом вызванном исключении «Исключение, выданное в 0x0F26372D (ucrtbased.dll) в lab10.exe: 0xC0000005: Место чтения нарушения доступа 0xCCCCCCC4.

Если для этого исключения есть обработчик, программа может быть безопасно продолжена»., что происходит, когда я вхожу в строку -> free (word).

Это случалось со мной несколько раз, когда я изучал malloc, но я упустил это из виду - подумал, что есть какая-то другая проблема.Но теперь я вижу, что я делаю что-то не так.

Смысл программы - написание структуры "слово".Мне нужно ввести предложение и «разрезать» его на слова, а затем каждое слово положить в структуру вместе с размером букв в слове и порядковым номером слова.

#include <stdio.h>
#include <string.h>

struct word {
    char text_word[50];
    unsigned sizee; //number of letters of the word
    unsigned number; //ordinal number of the word
};

void cutting_sentence(struct word *p, char *sen) { //sen is sentence
    int size_sen, i, j;

    size_sen = strlen(sen) + 1; //size of sentence

    p = (struct word*)malloc(size_sen * sizeof(struct word)); 
    if (p == NULL) {
        printf("\nNot enaugh memory!");
        return 0;
    }

    strcpy(p[0].text_word, strtok(sen, " ,.!?")); 
    p[0].sizee = strlen(p[0].text_word);
    p[0].number = 1;

    printf("word:%s \t size:%u \t ordinal number of the word:%u\n", 
        p[0].text_word, p[0].sizee, p[0].number);

    for (i = p[0].sizee - 1, j = 1;i < size_sen;++i) {
        if (*(sen + i) == ' ' || *(sen + i) == '.' || *(sen + i) == ','
        || *(sen + i) == '?' || *(sen + i) == '!') {
            strcpy(p[j].text_word, strtok(NULL, " ,.!?"));
            p[j].sizee = strlen(p[j].text_word);
            p[j].number = j + 1;

            printf("word:%s \t size:%u \t ordinal number of the 
                        word:%u\n", p[j].text_word, p[j].sizee, p[j].number);

            j++;
        }
    }
}

int main() {
    char sentence[1024];
    struct word *word;

    printf("Sentence: ");
    gets(sentence);

    cutting_sentence(&word, sentence);

    free(word);  //here is exception triggered

    return 0;
}

Ответы [ 3 ]

0 голосов
/ 30 декабря 2018

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

[Как уже указывалось], ваш первый аргумент должен быть struct word **.Но более простой способ - устранить его и изменить тип возвращаемого значения на struct word *.Это позволяет сделать код внутри функции более простым (то есть без двойной разыменования указателя)

Хотя выделение будет столько словарных структур, сколько символов во входной строке будет работать, это несколько необычно.

Лучший способ [по крайней мере, идиоматический] сделать это - использовать realloc внутри цикла.

В любом случае размер массива можно обрезать, чтобы использовать только то, что ему нужно, черезfinal realloc.

Я думаю, что ваш цикл, который сканирует sen в поисках разделителей, слишком сложен.Простое использование strtok в цикле даст тот же эффект с меньшей сложностью.

Кроме того, вы не передаете обратно count числа слов.Одним из способов является добавление дополнительного элемента в массив, который имеет нулевой размер (например, маркер конца списка)


Вот измененная версия, которая должна помочь:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct word {
    char text_word[50];
    unsigned sizee;                     // number of letters of the word
    unsigned number;                    // ordinal number of the word
};

struct word *
cutting_sentence(char *sen)
{                                       // sen is sentence
    int curcnt = 0;
    int maxcnt = 0;
    char *token;
    struct word *word;
    struct word *words;

    while (1) {
        token = strtok(sen," ,.!?\n");
        if (token == NULL)
            break;
        sen = NULL;

        if (curcnt >= maxcnt) {
            maxcnt += 100;
            words = realloc(words,sizeof(struct word) * (maxcnt + 1));
        }

        word = &words[curcnt];
        strcpy(word->text_word,token);
        word->number = curcnt;
        word->sizee = strlen(token);

        ++curcnt;
    }

    words = realloc(words,sizeof(struct word) * (curcnt + 1));

    // set end-of-list
    word = &words[curcnt];
    word->sizee = 0;

    return words;
}

int
main()
{
    char sentence[1024];
    struct word *words;
    struct word *word;

    printf("Sentence: ");
    fflush(stdout);

    fgets(sentence,sizeof(sentence),stdin);

    words = cutting_sentence(sentence);

    for (word = words;  word->sizee != 0;  ++word)
        printf("main: number=%u sizee=%u text_word='%s'\n",
            word->number,word->sizee,word->text_word);

    free(words);

    return 0;
}
0 голосов
/ 31 декабря 2018

следующий предложенный код:

  1. устраняет избыточный код
  2. правильно проверяет ошибки
  3. правильно выводит сообщение об ошибке (и текстовую причину, по которой система считает ошибкупроизошло stderr
  4. выполняет желаемую функциональность
  5. правильно инициализирует struct word указатель
  6. правильно обновляет struct word указатель
  7. изменено int sizee на size_t sizee, потому что функция: strlen() возвращает size_t, а не int
  8. , измененное int i на unsigned i, потому что объявление поля структуры number объявлено какunsigned
  9. документирует, почему каждый заголовочный файл включен
  10. выделяет экземпляр struct word для каждого символа в sentence Это «перебор». Максимально возможное количество словбыло бы, если бы каждое слово было только один символ. Таким образом, сразу же, размер выделенной памяти может быть сокращен пополам. Цикл, подсчет разделителей слов приведет к правильному количеству выделенной памяти.Я легко добавлю эту функцию.
  11. Обратите внимание, как используется функция: strtok().IE первоначальный вызов перед циклом, затем следующие вызовы в конце цикла

А теперь предложенный код:

#include <stdio.h>   // printf(), fgets(), NULL
#include <stdlib.h>  // exit(), EXIT_FAILURE, malloc(), free()
#include <string.h>  // strlen(),  strtok()


struct word 
{
    char text_word[50];
    size_t sizee; //number of letters of the word
    unsigned number; //ordinal number of the word
};

// notice the `**p` so can access the pointer in `main()` so it can be updated
void cutting_sentence(struct word **p, char *sen) 
{ //sen is sentence
    size_t size_sen = strlen(sen); //size of sentence
    struct word *wordptr = *p;

    wordptr = malloc(size_sen * sizeof(struct word)); 
    if ( !wordptr ) 
    {
        perror("malloc failed");
        exit( EXIT_FAILURE );
    }


    unsigned i = 0;
    char * token = strtok(sen, " ,.!?");
    while( token )
    {
        strcpy( wordptr[i].text_word, token ); 
        wordptr[i].sizee = strlen( token );
        wordptr[i].number = i;

        printf("word:%s\t Length:%lu]tordinal number of the word:%u\n", 
                wordptr[i].text_word, 
                wordptr[i].sizee, 
                wordptr[i].number);

        token = strtok( NULL, " ,.!?");
        i++;
    }
}

int main( void ) 
{
    char sentence[1024];
    struct word *wordArray = NULL;

    printf("Sentence: ");
    if( !fgets(sentence, sizeof( sentence ), stdin ) )
    {
        perror( "fgets failed" );
        exit( EXIT_FAILURE );
    }

    // remove trailing new line
    sentence[ strcspn( sentence, "\n") ]  = '\0';
    cutting_sentence(&wordArray, sentence);

    free( wordArray );  //here is exception triggered

    return 0;
}

Типичный прогон кода приводит к:

Sentence: hello my friend
word:hello   Length:5   ordinal number of the word:0
word:my  Length:2   ordinal number of the word:1
word:friend  Length:6   ordinal number of the word:2

Обратите внимание, что короткие слова приводят к неравномерному выводу.Вы можете исправить это.

0 голосов
/ 30 декабря 2018

Вы изменяете локальное значение переданного аргумента указателя, вам нужно изменить память в ее цели, чтобы вызывающая сторона обнаружила расположение выделенной памяти.Поскольку вы этого не сделали, вы пытаетесь освободить локальную переменную word, которая хранится в стеке main().

Первое, что нужно исправить, это не иметь переменную, идентичнуюимя типа, это просто зло.

Затем измените прототип функции, чтобы передать двойной указатель:

void cutting_sentence(struct word **p, char *sen);

И помните, что там, где вы использовали p, вам теперь нужно использовать*p или сначала назначьте локальный (word *) со значением адреса, содержащегося в нем.

void cutting_sentence(struct word **p, char *sen) { //sen is sentence
    int size_sen, i, j;

    size_sen = strlen(sen) + 1; //size of sentence

    *p = (struct word*)malloc(size_sen * sizeof(struct word)); 
    if (*p == NULL) {
        printf("\nNot enaugh memory!");
        return; //void cannot return a value
    }

и т. Д., Изменяя каждое использование p на *p.

, а затем

int main() {
    char sentence[1024];
    struct word *words;

    printf("Sentence: ");
    gets(sentence);

    cutting_sentence(&words, sentence);

    if (words != NULL)
       free(words);  //now valid

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...