Возвращает без команды возврата - PullRequest
8 голосов
/ 14 февраля 2020

C язык программирования, скомпилированный с помощью g cc, терминал bash в WSL

Я написал рекурсивную функцию, чтобы найти наименьшее число в массиве, которое прекрасно работает.

/*01*/    int minimo(int array[], int n)
/*02*/    {
/*03*/      static int min = 0;
/*04*/    
/*05*/      if (n == N)
/*06*/      {
/*07*/          return array[n-1];
/*08*/      }
/*09*/      else
/*10*/      {
/*11*/          min = minimo(array, n+1);
/*12*/          if(array[n]<min){
/*13*/              min = array[n];
/*14*/          }
/*15*/      }
/*16*/    }

Единственная проблема состоит в том, что она не должна работать, потому что она не возвращает вызывающей стороне "min" ...

int main()
{
    //Var
    int array[N] = {10, 2, 5, 1, 7};
    printf("Min: %d\n", minimo(array, 0));
}

Моя проблема на самом деле является проблемой, но не на моей машине, на которой функция работает так, как она есть; это проблема на ноутбуках и IDE моих друзей, я попытался скопировать в XCode на Macbook друга, и это не сработало бы, если строка "return min;" не был добавлен в конце функции.

Между строками 15-16 я должен добавить return min;

/*15*/      }
            return min;
/*16*/    }

Мои вопросы , потому что вы следующее:

  1. Как функция может возвращать переменную автоматически ?
  2. Возможно ли, что она возвращает только переменная , которую я создал (stati c int min)?
  3. Или это «проблема», связанная с stati c атрибут, который имеет переменная?
  4. Имеет ли это какое-либо отношение к природе функции ( recursive )?

Это мой первый пост, будьте добры, если я нарушаю какое-либо правило форума.

Ответы [ 4 ]

5 голосов
/ 14 февраля 2020

Моя проблема на самом деле проблема, но не на моем компьютере, на котором функция работает так же хорошо, как она есть; это проблема на ноутбуках и IDE моих друзей, я попытался скопировать в XCode на Macbook друга, и это не сработало бы, если строка "return min;" не был добавлен в конце функции.

Типичный пример неопределенное поведение . Работает на одной машине, но не на другой. Работает днем, а не ночью. Работает с одним компилятором, но не с другим. При вызове неопределенного поведения стандарт C не предъявляет никаких требований к поведению кода.

Стандарт C11 6.9.1.12

Если} которая завершает функцию, достигается, и значение вызова функции используется вызывающей стороной, поведение не определено.

В вашем коде именно это и происходит. Вы вызываете неопределенное поведение, когда пытаетесь напечатать возвращаемое значение.

Вопреки тому, что многие считают, полностью разрешено опускать оператор возврата в не пустую функцию. Поведение становится неопределенным, если вы попытаетесь использовать несуществующее возвращаемое значение.

Чтобы избежать этого, всегда компилируйте как минимум с -Wall -Wextra.

2 голосов
/ 14 февраля 2020

Как функция может автоматически возвращать переменную?

Следует протоколу. Он знает, что возвращаемая функция должна найти возвращаемое значение в некотором месте, и явное return из этой функции заполнит это место. Если вы не вызовете return, в данном месте будет сохранено некоторое случайное значение.

Возможно ли, что оно вернет единственную переменную, которую я создал (stati c int min) ?

Нет, неопределено, что он возвращает. Это может быть что угодно.

Или это «проблема», связанная с атрибутом stati c, который имеет переменная?

Опять же, то, что она возвращает, не определено .

Имеет ли это какое-либо отношение к природе функции (рекурсивной)?

Да и нет. Если функция определена как внешняя, возвращаемое значение следует другому протоколу, как в случае функций stati c.

В конечном коде может произойти все что угодно, язык C не навязывает способ реализации функции, будь то рекурсивный или нет. Например, в случае, если функция является рекурсивной и может быть предварительно вычислена, только конечное значение может быть заменено в месте вызова. Это также правильно, поскольку время, поскольку конечный результат программы является ожидаемым результатом, соответствует операционной семантике, которая определяет C в ISO9899.

Я цитирую от официального document:

4 В абстрактной машине все выражения оцениваются в соответствии с семантикой. Реальная реализация не должна оценивать часть выражения, если она может сделать вывод, что его значение не используется и что не возникает никаких побочных эффектов (включая любые, вызванные вызовом функции или доступом к энергозависимому объекту).

Он также может заменить вызов значением этого вызова, и это правильно.

Так что на все ваши вопросы ответ будет неопределенное поведение .

1 голос
/ 14 февраля 2020

Как функция может возвращать переменную автоматически?

Я случайно, min переменная находится в правильном регистре возврата для ABI.

Возможно ли, что он возвращает единственную переменную, которую я создал (stati c int min)?

Я думаю, это больше связано с тем, что она использовалась непосредственно перед выходом из функции , но я предполагаю здесь: это не поведение, определенное языком C, и оно работает случайно.

Или это «проблема», связанная с атрибутом stati c, что переменная имеет?

Имеет ли это какое-либо отношение к природе функции (рекурсивной)?

Поскольку это было случайное поведение, могло бы быть или нет. Разница между случайным и детерминированным c заключается в том, что у вас так много переменных, которые вы перестаете объяснять.

0 голосов
/ 14 февраля 2020

Полагаю, вы где-то определили N (вероятно, N = 5 в вашем случае).

Большинство компиляторов автоматически добавляет выражение "return 0", если выражение return отсутствует.

* См. Комментарии для получения дополнительной информации. На самом деле это неопределенное поведение *

В вашей рекурсивной функции лучше передать оставшуюся длину массива и остановиться, когда вы достигнете n == 0.

Избегайте смотреть в глобальных переменных или определяет внутренние функции.

int minimo(int array[], int n)
{
  ...
  if (n == 0)
  ...
            min = minimo(array, n-1);
  ...
}

(требуется другое изменение)

На самом деле вы должны знать длину массива только для основной функции, поэтому вызывайте ее как:

printf("Min: %d\n", minimo(array, N));
...