Сбой кода 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], сообщите об этом вашей функции или измените способ ее обработки. С указателями и указателями на указатели вы не можете экономить на проверке работоспособности при назначении значений.