Почему от добавления printf зависит значение переменной? Или влияние printf на корректность работы программы

Задача: Создать функцию, которая разбивает строку символов на слова. Слова разделены пробелом. Функция возвращает массив указателей, каждый из которых ссылается на массив символов (слова). Слова должны заканчиваться нуль-терминатором.

Пример кода:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

int count_words(char *str)   //подсчет количества слов в заданной строке
{
int i;
int words;

i = 0;
words = 0;
while (str[i] != '\0')
{
    if (str[i] == ' ')
        words++;
    i++;
}
words = words + 1;
return (words);
}

char    **split_whitespaces(char *str)
{
int i;
int j;
int k;
int len;    //длина слова
int w;
char    **dest;  //целевой массив

i = 0;
k = 0;
j = 0;

len = 0;

w = 0;
w = count_words(str);

dest = (char**)malloc(sizeof(char*) * w);  //выделение памяти под массив указателей

while (str[i] != '\0')
{
    while (str[i] != ' ' && str[i] != '\0')  //определяем длину каждого слова
    {
        i++;
        len++;
    }
    len++;  //для добавления нуль-терминатора
    //printf("len = %d\n", len);  //волшебный printf
    dest[k] = (char*)malloc(sizeof(char) * len); //выделение памяти под конкретное слово
    dest[k][len - 1] = '\0'; 
    len = 0;
    k++;
    i++;
}
i = 0;
k = 0;
while (i < w)  //наполнение ранее созданных массивов
{
    j = 0;
    while (dest[i][j] != '\0')
    {
        dest[i][j] = str[k];
        j++;
        k++;
    }
    k++;
    i++;
}
return (dest);
}

int main(int argc, char **argv)
{
char    str[15] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', ' ', 'g', 'o', '\0'};
char    **word;

word = split_whitespaces(str);
printf("%s\n%s\n%s", word[0], word[1], word[2]);

return (0);
}

Вопрос/проблема: Если не прописывать "волшебный printf", то длина каждого массива будет равна 2, не зависимо от длины слова. Если же прописать printf, то в итоге получим необходимый результат. В чем подвох? Почему так происходит? Какое влияние printf оказывает на значение переменной?


Ответы (2 шт):

Автор решения: Sergey

У Вас тут слишком много ошибок, что бы разобраться, какая из них - самая главная.

Для начала - совет. Объявление массива символов:

char    str[15] = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', ' ', 'g', 'o', '\0'};

Полностью эквивалентно гораздо более простому и понятному:

char    str[] = {"Hello, World go"};

Далее... Подозреваю, что записывая условие в операторе while таким образом:

while (str[i] != ' ' && str[i] != '\0') 

Вы, не предполагали, что записали вот это:

while ((str[i] !=  (' ' && str[i])) != '\0') 

Приоритет && выше приоритета операции сравнения !=

Ещё по поводу функции count_words. А что будет, если слова отделены друг от друга ДВУМЯ пробелами? А тремя? А знаком пунктуации?

Ещё бросилось в глаза:

dest[k][len - 1] = '\0';

Но вы только что делали len++ ?! Кстати говоря - совершенно напрасно. По выходу из цикла len УЖЕ указывает на разделитель слов.

Короче: убирайте ошибки одну за другой, а там уже будет видно....

→ Ссылка
Автор решения: cshells

Оказалось, проблема заключалось вот в чем:

dest[k] = (char*)malloc(sizeof(char) * len); //выделение памяти под конкретное слово
dest[k][len - 1] = '\0'; 

После выделения памяти таким образом нужно сразу заполнить его любыми символами, добавив:

dest[k] = (char*)malloc(sizeof(char) * len);
while (j < len)
{
 dest[k][j] = ' ';
 j++;
 }
dest[k][len - 1] = '\0';

Теперь, при обращении к элементам массива dest для его наполнения, программа отрабатывает корректно.

А по-хорошему, переделать код так, чтобы массивы заполнялись сразу нужными значениями.

P.S. Почему добавление строки printf все исправляло, я так и не понял.

→ Ссылка