Некорректная работа с памятью (calloc и free) - C (СИ)

Узнай цену своей работы

Формулировка задачи:

Суть задачи: Пользователь вводит с клавиатуры строку с разделителями в виде пробела. Надо выделить слова в предложении. Далее у пользователя запрашивается комбинация символов (слово). Нужно методом двоичного поиска выяснить, есть ли это слово в строке. p.s. требование преподавателя: использовать gets для считывания предложения, strtok для разбивки на слова и символ точка для выхода. p.s.s. на занятии нам рассказывали, что calloc() и free() надо приводить к нужному типу указателя, например:
  
    char **p;
    p = (char **) calloc(WORDS, sizeof(char *)); // выделение памяти для вспомогательного массива указателей
    p[0] = (char *) calloc(WORDS * SYMBOLS, sizeof(char)); // выделение памяти под предложение 
 
// какой-то код
 
    free((void **) p[0]); // освобождение памяти
    free((void **) p);
Я стараюсь уходить от этой практики, так как современный Си сам определяет к какому типу указателя надо приводить нетипизированный указатель, который возвращает calloc. Но (!) возникает следующая проблема. Компилятор код пропускает (только выводит предупреждение о том, что gets устарела и опасна). При завершении программы у меня ошибки. Вот код:
/**********************************************************************
 * laba9_string.c   15.11.2016
 * 
 * Пользователь вводит с клавиатуры строку с разделителями в виде ' '.
 * Надо выделить слова в предложении.
 * Далее у пользователя запрашивается комбинация символов.
 * Нужно методом двоичного поиска выяснить, есть ли это слово в строке.
 **********************************************************************/
 
#include <stdio.h>  /* printf, putchar, puts, gets */
#include <stdlib.h> /* calloc */
#include <string.h> /* strcmp */
 
#define WORDS 10    // максимум слов в предложении
#define SYMBOLS 10  // максимум символов в слове
 
void MySort(char **, int);
void MyBinarySearch(char **, int);

int main(void)
{
    int i, all_words;
    char **p;
    
// выделение памяти для вспомогательного массива указателей
    p = calloc(WORDS, sizeof(char *));
 
// выделение памяти под предложение, в т.ч. +10 на пробелы
    p[0] = calloc((WORDS * SYMBOLS) + 10, sizeof(char));
 
    printf("\n-----Введите предложение (не более 100 символов): \n");
    gets(p[0]);
 
// разделение слов на лексемы
    printf("\n----- Введены слова:");
    all_words = 0; // счётчик слов
    p[all_words] = strtok (p[0], " ");
    while(p[all_words] != NULL) {  //пока есть лексемы
        printf("\n  %s", p[all_words]);
        p[++all_words] = strtok (NULL, " ");
    }
 
// сортировка массива указателей на массивы символов (слова в словаре)
    MySort(p, all_words);
 
    printf("\n----- Слова отсортированы:\n");   
    for(i = 0; i < all_words; i++) {
        putchar(' ');
        puts(p[i]);
    }
 
// запрос произвольного слова и поиск его в словаре
    MyBinarySearch(p, all_words);
 
// освобождение памяти
    free(p[0]); 
    free(p);
 
    return 0;
}

// сортировка массива слов
void MySort(char **p, int all_words)
{ 
    size_t i, j;
    
    for(i = 0; i < all_words - 1; i++) {
        for(j = 0; j < all_words - 1 - i; j++){
            if(strcmp(p[j], p[j+1]) > 0) {
                char *tmp = p[j];
                p[j] = p[j + 1];
                p[j + 1] = tmp; 
            }
        }
    }
}

// поиск слова в массиве методом двоичного поиска   
void MyBinarySearch(char **p, int all_words)
{   
    char find_word[SYMBOLS];
    size_t left, right, flag, index = 0;
 
    printf("\n Введите слово для поиска или '.' для завершения: ");
    gets(find_word);
    while(46 - find_word[0]) {
        left = flag = 0;
        right = all_words - 1;
        while(left <= right) {
            index = (left + right) >> 1;
            if(strcmp(find_word, p[index]) < 0)
                right = --index;        
            else if(strcmp(find_word, p[index]) > 0)
                left = ++index;         
            else{
                flag = 1;
                break;
            }
        }
        if(flag)
            printf("\n\tСлово есть в словаре\n");
        else
            printf("\n\tСлова в словаре нет\n");
        printf("\n Введите слово для поиска или '.' для завершения: ");
        gets(find_word);
    }
}
Компилятор:
laba9_string.c: In function ‘main’: laba9_string.c:33:5: warning: implicit declaration of function ‘gets’ [-Wimplicit-function-declaration] gets(p[0]); ^~~~ /tmp/ccL8e73T.o: In function `main': laba9_string.c:(.text+0x4f): warning: the `gets' function is dangerous and should not be used.
После того как программа выполнила свою задачу, я ввожу "." и вот такое завершение:
Введите слово для поиска или '.' для завершения: . *** Error in `./laba9': free(): invalid pointer: 0x00000000024dd081 *** ======= Backtrace: ========= /lib/x86_64-linux-gnu/libc.so.6(+0x70bcb)[0x7f95b30c5bcb] /lib/x86_64-linux-gnu/libc.so.6(+0x76fa6)[0x7f95b30cbfa6] /lib/x86_64-linux-gnu/libc.so.6(+0x7779e)[0x7f95b30cc79e] ./laba9[0x400876] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1)[0x7f95b30752b1] ./laba9[0x40062a] ======= Memory map: ======== 00400000-00401000 r-xp 00000000 08:01 4063409 /home/eberkopff/Dropbox/School/bmstu/prog/laba9 00601000-00602000 r--p 00001000 08:01 4063409 /home/eberkopff/Dropbox/School/bmstu/prog/laba9 00602000-00603000 rw-p 00002000 08:01 4063409 /home/eberkopff/Dropbox/School/bmstu/prog/laba9 024dd000-024fe000 rw-p 00000000 00:00 0 [heap] 7f95ac000000-7f95ac021000 rw-p 00000000 00:00 0 7f95ac021000-7f95b0000000 ---p 00000000 00:00 0 7f95b2e3e000-7f95b2e54000 r-xp 00000000 08:01 1310799 /lib/x86_64-linux-gnu/libgcc_s.so.1 7f95b2e54000-7f95b3053000 ---p 00016000 08:01 1310799 /lib/x86_64-linux-gnu/libgcc_s.so.1 7f95b3053000-7f95b3054000 r--p 00015000 08:01 1310799 /lib/x86_64-linux-gnu/libgcc_s.so.1 7f95b3054000-7f95b3055000 rw-p 00016000 08:01 1310799 /lib/x86_64-linux-gnu/libgcc_s.so.1 7f95b3055000-7f95b31ea000 r-xp 00000000 08:01 1311344 /lib/x86_64-linux-gnu/libc-2.24.so 7f95b31ea000-7f95b33e9000 ---p 00195000 08:01 1311344 /lib/x86_64-linux-gnu/libc-2.24.so 7f95b33e9000-7f95b33ed000 r--p 00194000 08:01 1311344 /lib/x86_64-linux-gnu/libc-2.24.so 7f95b33ed000-7f95b33ef000 rw-p 00198000 08:01 1311344 /lib/x86_64-linux-gnu/libc-2.24.so 7f95b33ef000-7f95b33f3000 rw-p 00000000 00:00 0 7f95b33f3000-7f95b3416000 r-xp 00000000 08:01 1310780 /lib/x86_64-linux-gnu/ld-2.24.so 7f95b35f6000-7f95b35f8000 rw-p 00000000 00:00 0 7f95b3611000-7f95b3615000 rw-p 00000000 00:00 0 7f95b3615000-7f95b3616000 r--p 00022000 08:01 1310780 /lib/x86_64-linux-gnu/ld-2.24.so 7f95b3616000-7f95b3617000 rw-p 00023000 08:01 1310780 /lib/x86_64-linux-gnu/ld-2.24.so 7f95b3617000-7f95b3618000 rw-p 00000000 00:00 0 7fff3f338000-7fff3f359000 rw-p 00000000 00:00 0 [stack] 7fff3f367000-7fff3f369000 r--p 00000000 00:00 0 [vvar] 7fff3f369000-7fff3f36b000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] Aborted
Помогите мне понять природу моей ошибки? Что я сделал не так? (работа в debian 9, компилирование GCC 6.2, запуск через терминал строкой: "gcc laba9_string.c -o laba9 && ./laba9" )

Решение задачи: «Некорректная работа с памятью (calloc и free)»

textual
Листинг программы
char *p_words;
...
pwords = p[0] = calloc((WORDS * SYMBOLS) + 10, sizeof(char));
...
free(pwords);

Объяснение кода листинга программы

  1. Объявлена переменная типа char * под названием p_words.
  2. Выполнена операция приведения типа: p_words присваивается значение p[0], которое возвращается функцией calloc.
  3. Функция calloc выделяет память под массив символов (char) с размером (WORDS * SYMBOLS) + 10.
  4. Значение sizeof(char) используется как размер каждого элемента массива.
  5. В случае успешного выделения памяти, p_words будет указывать на начало блока памяти, а p[0] будет содержать первый элемент этого блока.
  6. В случае неудачного выделения памяти, p_words будет равен NULL.
  7. В блоке памяти, выделенном функцией calloc, первый элемент будет содержать значение '\0'.
  8. Выполнена операция free с аргументом p_words, что освобождает память, выделенную под массив символов.

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

6   голосов , оценка 4.167 из 5