Когда я запускаю этот фрагмент c, он каждый раз выводит что-то действительно случайное, а затем segfaults... Код:
#include <stdio.h>
#include <stdlib.h>
int parse(void) {
int i = 0;
int system(const char *command);
char line[1024];
scanf("%[^\n]", line);
system(line);
do {
line[i] = "\0";
i++;
} while (i != 1024);
parse();
}
int main(void) {
parse();
return 0;
}
Чего я ожидал, так это приглашения, и когда вводится любая команда оболочки (я использовал pwd для тестирования), печатается вывод команды и возвращается приглашение. И вот что произошло на самом деле:
Вывод:
> pwd
/home/runner/c-test
sh: 1: �: not found
sh: 1: : not found
sh: 1: ׀: not found
signal: segmentation fault (core dumped)
Во-вторых, line[i]
— это один символ, один char
. "\0"
— это строка с завершающим нулем, массив из двух элементов (оба являются завершающим нулем), который распадается на указатель на свой первый элемент. Почему вы назначаете этот указатель символу line[i]
? Разве компилятор не выдает предупреждение об этом? Затем вам нужно включить больше предупреждений и рассматривать их как ошибки.
В-третьих, почему вы используете рекурсию вместо цикла?
В-четвертых, вы не выводите подсказку, так почему вы ее ожидаете?
И вы на самом деле делаете не терминал, а программу, которая работает как оболочка.
вы называете себя - потребление вашего стека будет увеличиваться с каждой итерацией
@0___________ это хвостовая рекурсия, которая в любом случае оптимизируется до цикла. Не сказать, что это хорошо, но он не будет потреблять больше памяти стека.
@Tenobaal нет, не будет, так как ему нужно добавлять пространство стека для локальных переменных при каждом вызове godbolt.org/z/T3Peqh45n Потребление стека будет расти
@0___________ gcc делает, я пробовал. Время жизни значений локальных переменных заканчивается рекурсивным вызовом. "-foptimize-sibling-calls Оптимизировать родственные и хвостовые рекурсивные вызовы. Включено на уровнях -O2, -O3, -Os." из документации gcc
Также это объяснил здесь
@Tenobaal gcc в этом случае не работает. Этот случай не может быть оптимизирован хвостом. см. мою ссылку.
@0___________ Понятно... можешь объяснить почему?
@Tenobaal, потому что он должен сохранять копию локальных переменных при каждом вызове.
@0___________ а почему? Они больше не нужны в момент рекурсивного вызова, что должно позволить компилятору его оптимизировать.
Причина вашего сбоя, скорее всего, объясняется следующим:
scanf("%[^\n]", line);
означает продолжать чтение до тех пор, пока во входном потоке не появится новая строка. Поэтому, как только он завершается, следующий символ во входном потоке становится новой строкой.
В следующий раз, когда вы сделаете
scanf("%[^\n]", line);
эта новая строка по-прежнему является первым символом, поэтому scanf
вернется, не дожидаясь, пока пользователь введет какой-либо ввод.
Поскольку вы выполняете рекурсию, это будет происходить снова и снова и снова... Тогда, скорее всего, через некоторое время произойдет сбой системы из-за переполнения стека.
Решение: прочитайте эту новую строку из входного потока перед повторным вызовом scanf
.
Помимо этого вы должны:
Удалить int system(const char *command);
Установите максимальную ширину поля scanf
Проверьте возвращаемое значение scanf
Измените "\0"
на '\0'
(или удалите весь цикл do-while, так как он вам не нужен)
Используйте цикл while(1) { ... }
вместо рекурсивных вызовов
Решение: не используйте scanf
с таким неограниченным буфером.
@Dúthomhas Реальным решением было бы удалить весь код и сделать его совершенно другим. Но смысл этого ответа в том, чтобы объяснить, почему код ОП ведет себя именно так. Я не собираюсь переписывать код ОП. Мы не бесплатная служба кодирования
#include <stdio.h>
#include <stdlib.h>
int parse(void)
{
static char line[1024];
while(1)
{
printf(">>>");
if (!fgets(line, 1024, stdin)) return 1;
system(line);
}
}
int main(void) {
parse();
}
https://www.onlinegdb.com/wmPB3ZGNQ
Вы действительно предлагаете решение с использованием рекурсии?
@SupportUkraine Не имеет значения, рекурсия будет оптимизирована godbolt.org/z/qjqEnrnYT
Эта оптимизация просто случайный эффект, вы приучаете к вредным привычкам. -- О, и вы не объясняете свое решение.
Во-первых, почему вы предоставляете свой собственный прототип функции
system
вместо того, чтобы использовать тот, что предоставлен<stdlib.h>
?