Вы действительно не должны зависеть от порядка, в котором они выполняются, при прочих равных условиях все три рецепта для этих предпосылок могут выполняться параллельно.
Единственное жесткое правило заключается в том, что все предпосылки должны выполняться до запуска целевого рецепта.
Если между x
, y
и z
нет зависимостей и нет параллельного выполнения, GNU make, похоже, запускает их в указанном вами порядке, но это не гарантируется в Docs.
Да, вы хотите избежать gets
. fgets
всегда будет читать новую строку, если буфер был достаточно велик, чтобы вместить ее (что дает вам знать, когда буфер был слишком мал и есть еще часть строки, ожидающая чтения). Если вам нужно что-то вроде fgets
, которое не будет читать новую строку (теряя индикацию слишком маленького буфера), вы можете использовать fscanf
с преобразованием scan-set, например: "%N[^\n]"
, где 'N' заменяется на размер буфера - 1.
Один простой (хотя и странный) способ удалить новую строку из буфера после чтения с помощью fgets
: strtok(buffer, "\n");
Это не то, как strtok
должен использоваться, но я использовал его так чаще, чем по назначению (чего я обычно избегаю).
Никогда не используйте получает
. Он не предлагает защиты от уязвимости, связанной с переполнением буфера (то есть вы не можете сказать, насколько велик буфер, который вы ему передаете, поэтому он не может помешать пользователю ввести строку, превышающую размер буфера, и затереть память).
Избегайте использования scanf
. При неосторожном использовании он может иметь те же проблемы переполнения буфера, что и ,
. Даже игнорируя это, у него есть другие проблемы, которые затрудняют правильное использование .
Обычно вместо этого следует использовать fgets
, хотя иногда это неудобно (нужно удалить новую строку, заранее определить размер буфера, а затем выяснить, что делать со строками, которые слишком длинные - вы сохраняете прочитанную часть и отбрасываете лишнее , отбрасываете все, динамически увеличиваете буфер и пытаетесь снова и т. д.). Доступны некоторые нестандартные функции, которые выполняют это динамическое распределение за вас (например, getline
в системах POSIX, общедоступная функция Чака Фалконера ggets
функция). Обратите внимание, что ggets
имеет семантику gets
в том смысле, что он удаляет за вас завершающую новую строку.
никогда не используйте gets(), это может привести к непредсказуемым переполнениям. Если ваш строковый массив имеет размер 1000, а я введу 1001 символ, я могу переполнить буфер вашей программы.
Вы правы, что никогда не должны использовать получает
. Если вы хотите использовать fgets
, вы можете просто перезаписать новую строку.
char *result = fgets(str, sizeof(str), stdin);
char len = strlen(str);
if(result != NULL && str[len - 1] == '\n')
{
str[len - 1] = '\0';
}
else
{
// handle error
}
Это предполагает отсутствие встроенных NULL. Другой вариант - POSIX getline
:
char *line = NULL;
size_t len = 0;
ssize_t count = getline(&line, &len, stdin);
if(count >= 1 && line[count - 1] == '\n')
{
line[count - 1] = '\0';
}
else
{
// Handle error
}
Преимущество getline
в том, что он выполняет выделение и перераспределение за вас, обрабатывает возможные встроенные значения NULL и возвращает счетчик, поэтому вы этого не сделаете. приходится тратить время на strlen
. Обратите внимание, что вы не можете использовать массив с getline
. Указатель должен иметь значение NULL
или быть свободным.
Я не знаю, в чем проблема с scanf
.
Попробуйте использовать fgets () с этой модифицированной версией вашего CharToInt ():
int CharToInt(const char *s)
{
int i, result, temp;
result = 0;
i = 0;
while(*(s+i) != '\0')
{
if (isdigit(*(s+i)))
{
temp = *(s+i) & 15;
result = (temp + result) * 10;
}
i++;
}
return result / 10;
}
It по существу проверяет введенные цифры и игнорирует все остальное. Он очень сырой, поэтому доработайте его и посолите по вкусу.