Цикл while не прерывается при добавлении дополнительного ключевого слова int? - PullRequest
0 голосов
/ 08 июля 2019

Я делал некоторые упражнения для кодовых войн и должен был создать функцию digital_root (рекурсивно складывать все цифры числа вместе, пока не останется только одна цифра). Я был совершенно уверен, что все сделал правильно, но по какой-то причине моя петля while не разорвалась, хотя мои отпечатки показали, что len равно 1.

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

int digital_root(int n) {
  char number[10];
  sprintf(number, "%d", n);

  int len = strlen(number);
  printf("Outer print: %s %d %d\n", number, n, len);
  int sum = 0;
  while(len > 1)
  {
    sum = 0;
    for(int i = 0; i<len; i++)
    {
      sum += number[i] - '0';
    }
    sprintf(number, "%d", sum);
    int len = strlen(getal);       //!!!
    printf("Inner print: %s %d %d\n", number, sum, len);


  }

  return sum;

}

Мне потребовалось много времени, чтобы понять, что случилось. Я заметил, что при копировании вставил ключевое слово 'int', когда пересчитывал len в цикле while (строка отмечена !!!). Когда я удалил это (потому что не нужно было переопределять его как int, оно уже было), все вдруг заработало, как и предполагалось.

Это меня смутило. Почему это имеет значение? Я понимаю, что переопределение это плохая практика, но я не понимаю, как это привело бы к разрыву цикла while?

Используется компилятор Clan3.6 / C11.

(Ps. Когда я попробовал один и тот же код в TIO, он работал в обоих случаях ...)

Ответы [ 2 ]

4 голосов
/ 08 июля 2019

Вы не переопределяете существующую переменную, вы определяете новую переменную.

Рассмотрим этот пример:

#include <stdio.h>

int main(void) {
    int x = 42;
    printf("Outside, start.     x (%p) = %d\n", (void *)&x, x);
    {
        printf("Inner block, start. x (%p) = %d\n", (void *)&x, x);
        int x = 123;
        printf("Inner block, end.   x (%p) = %d\n", (void *)&x, x);
    }
    printf("Outside, end.       x (%p) = %d\n", (void *)&x, x);
    return 0;
}

Пример вывода:

Outside, start.     x (0x7ffd6e6b8abc) = 42
Inner block, start. x (0x7ffd6e6b8abc) = 42
Inner block, end.   x (0x7ffd6e6b8ab8) = 123
Outside, end.       x (0x7ffd6e6b8abc) = 42

[ Демонстрационная версия ]

Эта программа выводит адрес памяти и значение x. Большинство случаев использования x относятся к внешней переменной, объявленной в начале main. Но во внутреннем блоке после int x = 123; все вхождения x относятся ко второй отдельной переменной, которая также называется x (но в остальном независима).

Когда выполнение покидает внутренний блок, внешняя переменная x снова становится видимой.

Это также называется shadowing .

В вашем коде внешний len никогда не изменяется, поэтому while(len > 1) всегда имеет значение.


Кстати, теневое копирование является очень распространенной концепцией в большинстве языков, которые поддерживают блочную область видимости:

0 голосов
/ 08 июля 2019

Ваш второй int len создает вторую параллельную переменную, которая исчезает в конце блока {}.Оригинал len затем возвращается к жизни, совершенно без изменений.Без второго int исходная переменная изменяется.При этом оригинальная len фактически является неизменной постоянной и бесконечной петлей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...