﻿# Тем, кто учится программировать и решил написать вопрос на Stack Overflow: "Почему код не работает?"

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

![0959_PVS_education_1_ru/image2.png](https://import.viva64.com/docx/blog/0959_PVS_education_1_ru/image2.png)

Эту заметку меня побудила написать дискуссия "[Segmentation fault when converting char \* to char \*\*](https://stackoverflow.com/questions/72478692/segmentation-fault-when-converting-char-to-char/)" на сайте Stack Overflow\. Человек, изучающий программирование, интересуется, что не так с его кодом\.

```cpp
#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](https://pvs-studio.ru/ru/blog/terms/0073/) и сообщает о подозрительных участках кода\. Статические анализаторы не заменяют практику обзора кода, выполняемого коллегой, но хорошо дополняют его и позволяют находить многие ошибки на самом раннем этапе\.

[Запустим](https://godbolt.org/z/svdEPrW8n) online\-версию анализатора PVS\-Studio для приведённого в вопросе кода\. Первым интересным и важным предупреждением является сообщение: [V1031](https://pvs-studio.ru/ru/docs/warnings/v1031/) The 'malloc' function is not declared\. Passing data to or from this function can be affected\.

Без объявления функции _malloc_ программа уже работает непонятным образом\. В языке Си считается, что если функция не объявлена, то она возвращает _int_\. А на самом деле это указатель\. Чем это опасно, рассказано в заметке "[Красивая 64\-битная ошибка на языке Си](https://pvs-studio.ru/ru/blog/posts/cpp/0033/)"\. Исправим эту проблему, добавив _\#include <stdlib\.h\>_\.

Теперь [вывод анализатора](https://godbolt.org/z/ehqsaeMqW) изменится, и мы видим следующую серьёзную проблему: 43:1: note: V773 The 'buffer' pointer was assigned values twice without releasing the memory\. A memory leak is possible\.

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

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

Значение указателя перетирается\. Чтобы скопировать строку в буфер, нужно использовать специальные функции, например [_strcpy_](https://en.cppreference.com/w/c/string/byte/strcpy)\. Внесём исправления\. 

[Исправленный код](https://godbolt.org/z/Kar998xbv):

```cpp
#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]);
}
```

Этот код ещё нельзя назвать красивым и безопасным, но он работает\. Так что такой способ поиска ошибок вполне может помочь в процессе обучения\.

**Дополнительные ссылки:**

1. [Статический анализ кода](https://pvs-studio.ru/ru/blog/terms/0046/)\.
1. PVS\-Studio: [online версия](https://pvs-studio.ru/ru/pvs-studio/godbolt/)\.
1. PVS\-Studio: [бесплатное использование для студентов](https://pvs-studio.ru/ru/order/for-students/)\.