На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
[!] Как относитесь к модерированию на этом форуме? Выскажите свое мнение здесь
Модераторы: Qraizer
  
> Тем, кто задаёт вопросы на Stack Overflow: "Почему код не работает?"

    На сайте Stack Overflow много вопросов от людей, ещё только изучающих языки программирования.
    Лайфхак: ответы на многие эти вопросы можно получить сразу, запустив анализатор кода. Получится быстрее.


    user posted image

    Эту заметку меня побудила написать дискуссия "Segmentation fault when converting char * to char **" на сайте Stack Overflow. Человек, изучающий программирование, интересуется, что не так с его кодом.

    ExpandedWrap disabled
      #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.

    Ошибка здесь:

    ExpandedWrap disabled
      char *buffer = malloc(sizeof(char) * 100);
      buffer = "hello world !\n";
      ....
      free (buffer);

    Значение указателя перетирается. Чтобы скопировать строку в буфер, нужно использовать специальные функции, например strcpy. Внесём исправления.

    Исправленный код:

    ExpandedWrap disabled
      #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: насколько вы внимательны?"
    Сообщение отредактировано: vot -
    0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
    0 пользователей:


    Рейтинг@Mail.ru
    [ Script execution time: 0,0200 ]   [ 16 queries used ]   [ Generated: 23.04.24, 20:25 GMT ]