Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.145.186.6] |
|
Сообщ.
#1
,
|
|
|
На сайте Stack Overflow много вопросов от людей, ещё только изучающих языки программирования. Лайфхак: ответы на многие эти вопросы можно получить сразу, запустив анализатор кода. Получится быстрее. Эту заметку меня побудила написать дискуссия "Segmentation fault when converting char * to char **" на сайте Stack Overflow. Человек, изучающий программирование, интересуется, что не так с его кодом. #include <unistd.h> #include <stdio.h> #include <string.h> #include <fcntl.h> #include <assert.h> char **get_words(char *buffer, char delimiter) { printf("buffer = %s\n", buffer); char **words = malloc(sizeof(char *) * 100); if (words == NULL) { printf("Malloc Error\n"); exit(84); } for (int i = 0; i < 100; i++) { words[i] = malloc(sizeof(char) * 100); if (words[i] == NULL) { printf("Malloc Error\n"); exit(84); } } int word_count = 0; int l = 0; for (int i = 0; buffer[i] != '\0' && buffer[i] != '\n'; i++, l++) { if (buffer[i] == delimiter) { words[word_count][l] = '\0'; word_count++; l = -1; } else words[word_count][l] = buffer[i]; } words[word_count][l] = '\0'; return (words); } int main() { char *buffer = malloc(sizeof(char) * 100); buffer = "hello world !\n"; char **words = get_words(buffer, ' '); printf("words[0]= %s\n", words[0]); free (buffer); char **reply = get_words("Second call\n", ' '); printf("reply[0] = %s\n", reply[0]); } Таких вопросов достаточно на Stack Overflow. И часто на них отвечают медленно и неохотно. Это обоснованно. Согласитесь, не хочется изучать достаточно большой текст программы только ради того, чтобы найти какую-то скучную ошибку. Эти ошибки, как правило, связаны с ещё недостаточным знанием языка, и ответ, скорее всего, сведётся к совету прочитать определённый раздел книги или документации. Это не снобизм со стороны более опытных разработчиков. Им просто не очень интересно тратить время на то, чтобы разбираться, что не так с лабораторными работами. Вернёмся к вопросу на Stack Overflow, про который я говорил выше. Вопрос висел уже пару дней, а ответа всё нет. Как человеку продвинуться дальше? Одним из помощников в обучении программированию может стать статический анализатор. Это программа, которая выполняет code review и сообщает о подозрительных участках кода. Статические анализаторы не заменяют практику обзора кода, выполняемого коллегой, но хорошо дополняют его и позволяют находить многие ошибки на самом раннем этапе. Запустим online-версию анализатора PVS-Studio для приведённого в вопросе кода. Первым интересным и важным предупреждением является сообщение: V1031 The 'malloc' function is not declared. Passing data to or from this function can be affected. Без объявления функции malloc программа уже работает непонятным образом. В языке Си считается, что если функция не объявлена, то она возвращает int. А на самом деле это указатель. Чем это опасно, рассказано в заметке "Красивая 64-битная ошибка на языке Си". Исправим эту проблему, добавив #include <stdlib.h>. Теперь вывод анализатора изменится, и мы видим следующую серьёзную проблему: 43:1: note: V773 The 'buffer' pointer was assigned values twice without releasing the memory. A memory leak is possible. Ошибка здесь: char *buffer = malloc(sizeof(char) * 100); buffer = "hello world !\n"; .... free (buffer); Значение указателя перетирается. Чтобы скопировать строку в буфер, нужно использовать специальные функции, например strcpy. Внесём исправления. Исправленный код: #include <unistd.h> #include <stdio.h> #include <string.h> #include <fcntl.h> #include <assert.h> #include <stdlib.h> char **get_words(char *buffer, char delimiter) { printf("buffer = %s\n", buffer); char **words = malloc(sizeof(char *) * 100); if (words == NULL) { printf("Malloc Error\n"); exit(84); } for (int i = 0; i < 100; i++) { words[i] = malloc(sizeof(char) * 100); if (words[i] == NULL) { printf("Malloc Error\n"); exit(84); } } int word_count = 0; int l = 0; for (int i = 0; buffer[i] != '\0' && buffer[i] != '\n'; i++, l++) { if (buffer[i] == delimiter) { words[word_count][l] = '\0'; word_count++; l = -1; } else words[word_count][l] = buffer[i]; } words[word_count][l] = '\0'; return (words); } int main() { char *buffer = malloc(sizeof(char) * 100); if (buffer == NULL) exit(84); strcpy(buffer, "hello world !\n"); char **words = get_words(buffer, ' '); printf("words[0]= %s\n", words[0]); free (buffer); char **reply = get_words("Second call\n", ' '); printf("reply[0] = %s\n", reply[0]); } Этот код ещё нельзя назвать красивым и безопасным, но он работает. Так что такой способ поиска ошибок вполне может помочь в процессе обучения. Дополнительные ссылки: Статический анализ кода. PVS-Studio: online версия. PVS-Studio: бесплатное использование для студентов. Это сообщение было перенесено сюда или объединено из темы "Тем, кто задаёт вопросы на Stack Overflow: "Почему код не работает?"" Эта тема была разделена из темы "Челлендж от анализатора PVS-Studio: насколько вы внимательны?" |