Сбой кода C в Windows, но не в Linux

Я новичок в C, и я тестировал свою программу в Fedora, используя gcc и gdb для отладки. У меня есть программа, которая принимает данные от пользователя. Если первой введенной строкой является "создать", то я смотрю на вторую команду, а если это "объект", тогда я перехожу к функции createObject.

Надеюсь, мой код сделает это немного понятнее:

static void parseCmd(char **input) {
    if(!strcmp(input[0], "create")) {
        if(!strcmp(input[1], "object")) {
            if(input[2] && strcmp(input[2], ""))
                createObject(input[2]);
            else
                printf("Object needs a name\n");
        }
        else
            printf("Command needs more parameters\n");
    }
    else
        printf("Command not recognized\n");
}

Когда я тестирую ввод просто "создать объект" (без пробела после объекта, просто клавиша ENTER)

В Linux это печатает "Объекту нужно имя"

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

4 ответа

Решение

Вы вошли в область потенциальных нарушений доступа или неопределенного поведения (ну, неопределенные значения):

input[2] && strcmp(input[2], "")

Если длина input только 2, то это чтение за приемлемую точку для чтения. В худшем случае это вызовет сбой (как это делает Windows), а в лучшем случае ОС допустит это, и вы получите случайное значение. (Похоже, что Linux рассматривает либо его, либо *input[2] как 0).

В любом случае, вместо чтения содержимого, к которому у вас нет доступа, передайте длину ввода и проверьте это.

static void parseCmd( char **input, size_t num) { //or just int if size_t isn't already defined
    //compare num
}

--Редактировать--

Как отметил Даниэль Фишер, по-видимому, argv[argc] действительно допустимое чтение, и он гарантированно будет нулевым указателем.

Предполагая, что вы действительно проходите argv для функции это означает, что вы можете положиться на это поведение. Ваши два других оператора if не проверяют это, хотя и для обобщения функции все же лучше передать длину (или, как сказал paulsm4, вы должны изучить функцию getopt - она ​​сильно разбирает параметры) проще, чем накатывать собственный метод разбора).

У вас есть код, который говорит:

if(input[2] && strcmp(input[2], ""))

Видимо, пытаясь обнаружить, если input[2] присутствует и не пусто.

Однако это не сработает. НЕТ обещаний, что отсутствие третьего параметра input[2] быть NULL или "",

input[2] в этот момент, вероятно, будет иметь значение мусора, но мусор все равно пройдет ваш тест!

У вас есть несколько вариантов, чтобы исправить это.
Либо вызывающий этой функции должен гарантировать, что элементы, для которых не установлены допустимые данные, вместо этого будут установлены на ноль / ноль.

Или метод, который я бы предпочел, вы меняете сигнатуру функции на что-то вроде этого:

static void parseCmd(char **input, int num_inputs);

И передайте количество входов вместе с массивом ввода.

У вас есть проблема в этой строке:

if(input[2] && strcmp(input[2], ""))

input [2] в вашем тесте не существует "create object", это объясняет, почему он вылетает.

Надеюсь, это поможет.

С уважением.

Вы, сэр, бьете в память, что у вас нет доступа, чтобы бить.

Я отсылаю вас к

Как проверить правильность указателя?

Любой, кто хочет знать, как он передает вещи:

int main(void) 
{ 
    char* values[] = {"1", "2", "3"};
    parseCmd(values);
} 

Это происходит, когда вы пытаетесь получить доступ к вводу [2], но это может произойти в любом случае, если вы не знаете, что вы принимаете. Я бы порекомендовал проверить работоспособность, когда вы получаете ввод. Если они ничего не помещают в значения [2], сообщите об этом вашей функции или измените способ ее обработки. С указателями и указателями на указатели вы не можете экономить на проверке работоспособности при назначении значений.

Другие вопросы по тегам