Не может создать программу, которая будет инвертировать строку
Вопрос
Я использую Linux. Я пытаюсь написать программу в C, которая напечатает строку назад. Вот мой код:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (){
char string[100];
printf ("Enter string:\n");
gets (string);
int length = strlen (string)-1;
for (length = length; length>=0; length--){
puts (string[length]);
}
}
И вот ошибка:
a.c:10: warning: passing argument 1 of ‘puts’ makes pointer from integer without a cast
/usr/include/stdio.h:668: note: expected ‘const char *’ but argument is of type ‘char’
/tmp/cc5rpeG7.o: In function `main':
a.c:(.text+0x29): warning: the `gets' function is dangerous and should not be used.
Что я должен делать?
Решение
Первый:
Никогда никогда больше никогда никогда использовать gets()
; Это будем Введите точку отказа в вашем коде. Там нет возможности сказать gets()
Насколько большой целевой буфер является, поэтому, если вы проходите размеры буфера, чтобы удерживать 10 символов, и в потоке ввода 100 символов 100 символов, gets()
Счастливо сохранит эти дополнительные 90 символов в памяти за пределы конца вашего буфера, потенциально сложив что-то важное. Переполнение буфера - это легкая эксплуатация вредоносных программ; Червь Морриса специально эксплуатировала gets()
Позвоните в Sendmail.
Использовать fgets()
вместо; Это позволяет указывать максимальное количество символов для чтения из входного потока. Однако, в отличие от gets()
, fgets()
Сохранит заканчивающий символ Newline к буферу, если для него есть место, поэтому вы должны учитывать это:
char string[100];
char *newline;
printf("Enter a string: ");
fflush(stdout);
fgets(string, sizeof string, stdin);
newline = strchr(buffer, '\n'); // search for the newline character
if (newline) // if it's present
*newline = 0; // set it to zero
Теперь это выходит из пути ...
Ваша ошибка исходит от того, что puts()
ожидает аргумент типа char *
, но вы проходите аргумент типа char
, Отсюда, отсюда «указатель из целочисленного без литого» сообщения (char
это интегральный тип). Чтобы написать один символ для STDOUT, используйте putchar()
или fputc()
.
Другие советы
Забыть, что функция gets()
Существует - это смертельный. Использовать fgets()
вместо этого (но обратите внимание, что он не удаляет новую строку в конце строки).
Вы хотите поставить один символ за раз: использовать putchar()
Чтобы написать это на STDOUT. Не забудьте добавить новую онлайн на вывод после петли.
Также, for (length = length; length >= 0; length--)
не является идиоматическим C. Использовать один из:
for ( ; length >= 0; length--)
for (length = strlen(string) - 1; length >= 0; length--)
for (int length = strlen(string) - 1; length >= 0; length--)
Последняя альтернатива использует функцию, добавленную в C99 (которая была доступна в C ++ длиной до).
Кроме того, мы могли бы обсудить length
является подходящим названием для переменной. Было бы лучше переименовали как i
или pos
Или что-то подобное, потому что, хотя он инициализируется до длины входа, он фактически используется в качестве индекса массива, а не как длина чего-либо.
Субъективность: Не помещайте пространство между именем функции и его списком параметров. Отцы основания C не делают этого - ни то, что вы.
Почему получает () летал?
Первый интернет-червь - Моррис Червь с 1988 года - эксплуатировал fingerd
Программа, которая использовала gets()
вместо fgets()
. Отказ С тех пор многочисленные программы были разбиты, потому что они использовали gets()
и нет fgets()
или другая альтернатива.
Фундаментальная проблема в том, что gets()
Не знает, сколько места доступно для хранения данных, которые он читает. Это приводит к «переполнению буфера», термин, который можно найти в вашей любимой поисковой системе, которая вернет огромное количество записей.
Если кто-то типы 150 символов ввода в примеру программа, то gets()
Будут хранить 150 символов в массиве, который имеет длину 100. Это никогда не приводит к счастью - это обычно приводит к счастью к сердечкому, но с тщательно выбранными входами - часто генерируется сценарием Perl или Python - вы, вероятно, можете получить программу для выполнения произвольного Другой код. Это действительно имеет значение, если программа когда-либо будет управляться пользователем с «повышенными привилегиями».
Кстати, gets()
скорее всего, будет удален из стандартной библиотеки C в следующем выпуске (C1x - см. N1494 из WG14.). Еще не будет исчезнуть из фактических библиотек C в течение длительного времени (20 лет?), Но его следует заменить на эту реализацию (или что-то подобное):
#undef NDEBUG
#include <assert.h>
char *gets(char *buffer)
{
assert("Probability of using gets() safely" == 0);
}
Еще одна небольшая деталь, обсуждалась частично под комментариями к главному вопросу.
Показанный код явно для C99; Декларация length
Часть Way через функцию недействительна в C89. Учитывая это, это «нормально» для main()
Функция не для явного возврата значения, поскольку стандарт C99 следует за проведением стандарта C ++ и позволяет вам пропустить возвращение из main()
и эффект такой же, как return(0);
или return 0;
в конце.
Как таковой, программа в этом вопросе не может быть строго не хватает, чтобы не иметь return
в конце. Тем не менее, я считаю, что является одним из более своеобразных решений по стандартизации, и значительно предпочел бы, если стандарты оставили это положение - или сделано что-то более радикальное, что позволяет повсеместному, но ошибочному void main()
Наблюдая за тем, что когда контроль возвращается из этого, результат заключается в том, что статус успеха возвращается в среду. Не стоит бороться, чтобы получить этот аспект стандарта, изменился - к сожалению - но как в качестве личного стиля, я не пользуюсь лицензией, предоставленной, чтобы опустить финал return
от main()
. Отказ Если код должен работать с компиляторами C89, он должен иметь явную return 0;
в конце (но затем заявление о length
должен быть исправлен тоже).
Вы также можете использовать рекурсию, чтобы сделать это. Я думаю, что это выглядит приятнее, тогда при использовании цикла.
Просто вызовите метод с помощью своей строки, а перед тем, как печатать Char в методе, вызовите метод снова с той же строкой, минус первый символ.
Это распечатает вас строку в обратном порядке.
Вы должны использовать putchar
вместо puts
Так что эта петля:
for (length = length; length>=0; length--){
puts (string[length]);
}
Будет:
for (length = length; length>=0; length--){
putchar (string[length]);
}
putchar
примет один символ в качестве параметра и распечатать его stdout
, что вы хотите. puts
, С другой стороны, напечатает всю строку к stdout
. Отказ Поэтому, когда вы передаете один символ функции, которая ожидает целую строку (Char Array, НУЛЕВОЙ Завершенная строка) компилятор запутается.
Использовать putc
или putchar
, в виде puts
указывается, чтобы взять char*
и вы кормите это char
.