Некорректная работа с памятью (calloc и free) - C (СИ)
Формулировка задачи:
Суть задачи: Пользователь вводит с клавиатуры строку с разделителями в виде пробела. Надо выделить слова в предложении.
Далее у пользователя запрашивается комбинация символов (слово). Нужно методом двоичного поиска выяснить, есть ли это слово в строке.
p.s. требование преподавателя: использовать gets для считывания предложения, strtok для разбивки на слова и символ точка для выхода.
p.s.s. на занятии нам рассказывали, что calloc() и free() надо приводить к нужному типу указателя, например:
Я стараюсь уходить от этой практики, так как современный Си сам определяет к какому типу указателя надо приводить нетипизированный указатель, который возвращает calloc.
Но (!) возникает следующая проблема. Компилятор код пропускает (только выводит предупреждение о том, что gets устарела и опасна).
При завершении программы у меня ошибки. Вот код:
Компилятор:
После того как программа выполнила свою задачу, я ввожу "." и вот такое завершение:
Помогите мне понять природу моей ошибки? Что я сделал не так?
(работа в debian 9, компилирование GCC 6.2, запуск через терминал строкой: "gcc laba9_string.c -o laba9 && ./laba9" )
char **p;
p = (char **) calloc(WORDS, sizeof(char *)); // выделение памяти для вспомогательного массива указателей
p[0] = (char *) calloc(WORDS * SYMBOLS, sizeof(char)); // выделение памяти под предложение
// какой-то код
free((void **) p[0]); // освобождение памяти
free((void **) p);/**********************************************************************
* 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
Решение задачи: «Некорректная работа с памятью (calloc и free)»
textual
Листинг программы
char *p_words; ... pwords = p[0] = calloc((WORDS * SYMBOLS) + 10, sizeof(char)); ... free(pwords);
Объяснение кода листинга программы
- Объявлена переменная типа char * под названием
p_words. - Выполнена операция приведения типа:
p_wordsприсваивается значениеp[0], которое возвращается функциейcalloc. - Функция
callocвыделяет память под массив символов (char) с размером (WORDS * SYMBOLS) + 10. - Значение
sizeof(char)используется как размер каждого элемента массива. - В случае успешного выделения памяти,
p_wordsбудет указывать на начало блока памяти, аp[0]будет содержать первый элемент этого блока. - В случае неудачного выделения памяти,
p_wordsбудет равен NULL. - В блоке памяти, выделенном функцией
calloc, первый элемент будет содержать значение '\0'. - Выполнена операция
freeс аргументомp_words, что освобождает память, выделенную под массив символов.