Не может создать программу, которая будет инвертировать строку

StackOverflow https://stackoverflow.com/questions/3627581

  •  26-09-2019
  •  | 
  •  

Вопрос

Я использую 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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top