Вызов исальфы, вызывающий ошибку сегментации - PullRequest
0 голосов
/ 28 мая 2018

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

#include <stdio.h>
#include <string.h>
#include <ctype.h>

int main(int argc, char *argv[])
{
    printf("TEST");

    for (int k=0; k<(strlen(argv[1])); k++)
    {
        if (!isalpha(argv[1])) {
            printf("Enter only alphabets!");
            return 1;
        }
    }

    return 0;
}

Я выяснил, что именно эта строка вызывает проблему

if (!isalpha(argv[1])) {

и заменяет argv[1] с argv[1][k] решает проблему.

Однако мне довольно любопытно, что программа приводит к ошибке сегментации, даже не печатая TEST.Я также ожидаю, что функция isalpha неправильно проверит, младший байт указателя char* равен argv[1], но, похоже, это не так.У меня есть код для проверки количества аргументов, но он не показан здесь для краткости.

Что здесь происходит?

Ответы [ 4 ]

0 голосов
/ 28 мая 2018
  1. printf не было сброшено
  2. неявное преобразование из указателя в целое число , которое должно было генерировать хотя бы диагностику во время компиляции для нарушения ограничения , получило число, которое быловне диапазона для isalpha.isalpha реализация в виде справочной таблицы означает, что ваш код получил доступ к таблице вне границ, поэтому поведение не определено.
  3. Почему вы не получили диагностику, возможно,в одной части из-за , как isalpha реализован как макрос.На моем компьютере с Glibc 2.27-3ubuntu1 isalpha определяется как

    # define isalpha(c)     __isctype((c), _ISalpha)
    # define __isctype(c, type) \
        ((*__ctype_b_loc ())[(int) (c)] & (unsigned short int) type)
    

    , макрос содержит неудачное приведение к int, что отключит вашу ошибку!


Одна из причин, по которой я публикую этот ответ после стольких других, заключается в том, что вы не исправили код , он по-прежнему страдает от неопределенного поведения при наличии расширенных символов и char, являющихсяподписанный (что обычно происходит в x86-32 и x86-64).

Правильный аргумент для isalpha - (unsigned char)argv[1][k]! C11 7.4 :

Во всех случаях аргументом является int, значение которого должно быть представлено как unsigned char или равным значению макроса EOF. Если аргумент имеет любое другое значение, поведение не определено.

0 голосов
/ 28 мая 2018

Как правило, бессмысленно обсуждать, почему неопределенное поведение приводит к тому или иному результату.

Но, возможно, не вредно пытаться понять, почему что-то происходит, даже если это выходит за рамки спецификации.

Существует реализация isalpha, в которой используется простой массив для поиска всех возможных значений unsigned char.В этом случае значение, переданное в качестве параметра, используется в качестве индекса в массиве.В то время как реальный символ ограничен 8 битами, целое число - нет.Функция принимает int в качестве параметра.Это позволяет также вводить EOF, который не вписывается в unsigned char.

Если вы передаете адрес, такой как 0x7239482342, в вашу функцию, это далеко за пределами указанного массива, и когда процессор пытаетсячтобы прочитать запись с этим индексом, он падает с края света.;)

Вызов isalpha с таким адресом - это место, где компилятор должен выдать предупреждение о преобразовании указателя в целое число.Что вы, вероятно, игнорируете ...

Библиотека может содержать код, который проверяет допустимые параметры, но он также может просто полагаться на то, что пользователь не передает вещи, которые не должны быть переданы.

0 голосов
/ 28 мая 2018

Прежде всего, соответствующий компилятор должен дать вам диагностическое сообщение здесь.Не допускается неявное преобразование указателя в параметр int, ожидаемый isalpha.(Это нарушение правил простого назначения, 6.5.16.1.)

Что касается того, почему «TEST» не печатается, это может быть просто потому, что stdout не очищен.Вы можете попробовать добавить fflush(stdout); после printf и посмотреть, решит ли это проблему.В качестве альтернативы добавьте перевод строки \n в конце строки.

В противном случае компилятор может изменить порядок выполнения кода, если нет побочных эффектов.То есть разрешено выполнять весь цикл до printf("TEST");, если он печатает TEST до того, как потенциально напечатает "Enter only alphabets!".Такая оптимизация, скорее всего, не произойдет здесь, но в других ситуациях они могут произойти.

0 голосов
/ 28 мая 2018

Мне довольно любопытно, что программа приводит к ошибке сегментации, даже не печатая. ТЕСТ

printf не печатается мгновенно, но записывает данные во временный буфер.Конец вашей строки с \n, если вы хотите сбросить ее до фактического вывода.

и замена argv [1] на argv [1] [k] решает проблему.

isalpha предназначен для работы с одиночными символами.

...