Некорректная работа с памятью (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
, что освобождает память, выделенную под массив символов.
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д