Программа вылетает, когда я запускаю .\pass_args.exe -a 5 -q (когда аргументы командной строки не указаны парами)

Я изо всех сил пытаюсь определить ошибку, которая приводит к сбою программы, когда код запускается с нечетным количеством аргументов командной строки. например

Программу можно запустить с аргументами командной строки: w : выберите тип генерируемой волны a : амплитуда волны f : частота волны если предоставленное значение недопустимо, функция passArgs немедленно вернется.

Чтобы воспроизвести ошибку:

.\pass_args.exe -a 5 -q

или

.\pass_args.exe -a 5 -w square -e

Это работает хорошо, если я бегу

.\pass_args.exe -a 5 -w square -e 10

pass_args.c

#include <stdio.h>
#include <unistd.h>
#include "pass_args.h"

int isValidFloat(const char *str)
{
    size_t len = strlen(str);
    if (len == 0)
    {
        return 0; // Empty string is not a valid float
    }

    if (!(str[0] >= '0') || !(str[0] <= '9')) // first char is not number
    {
        if (len == 1)
        { // sign without any digits is not a valid float
            return 0;
        }
        if (str[0] == '-')
        {
            str++; // move past the sign character
            len--;
        }
    }

    int dotFound = 0; // Flag to keep track of the decimal dot
    // Check that all remaining characters are digits (0-9) or a single decimal dot
    for (size_t i = 0; i < len; i++)
    {
        if (str[i] == '.')
        {
            if (dotFound)
            {
                return 0; // More than one decimal dot found, not a valid float
            }
            dotFound = 1; // Set dotFound to true after encountering the first dot
        }
        else if (str[i] < '0' || str[i] > '9')
        {
            return 0; // Non-digit or non-dot character found, not a valid float
        }
    }

    return 1; // String represents a valid float
}

void printArgumentManual()
{
    printf("Welcome\n");
};

int passArgs(int argc, char *argv[])
{
    int valid_float = 0;
    int wave_valid = 0;
    int freq_valid = 0;
    int amp_valid = 0;
    float tmp = 0.0;
    char *value;
    if (argc <= 2) // no command line argument used
    {
        printf("no option given\n");
        return 1;
    }
    printf("argc %d\n", argc);
    char **p_to_args = &argv[1];
    char **p_to_vals = &argv[2];

    while (*p_to_args != NULL)
    {
        if ((*p_to_args[0]) != '-' || (*p_to_args[1]) == '\0')
        {
            printf("Invalid options!\n");
            return 2;
        }
        if (*p_to_vals == NULL || *p_to_vals == '\0')
        {
            printf("unexpected values for arguments!\n");
            return 2;
        }
        switch ((*p_to_args)[1])
        {
        case 'w':
            if (!strcmp(*p_to_vals, "sine"))
            {
                waveforms = 1;
                wave_valid = 1;
                break;
            }

            else if (!strcmp(*p_to_vals, "triangular"))
            {
                waveforms = 2;
                wave_valid = 1;
                break;
            }

            else if (!strcmp(*p_to_vals, "sawtooth"))
            {
                waveforms = 3;
                wave_valid = 1;
                break;
            }
            else if (!strcmp(*p_to_vals, "square"))
            {
                waveforms = 4;
                wave_valid = 1;
                break;
            }
            else
            {
                printf("Invalid wave option.\n");
                return 2;
            }
        case 'a':
            valid_float = isValidFloat(*p_to_vals);
            if (valid_float == 0)
            {
                printf("Invalid float value is given\n");
                return 2;
            }
            tmp = strtod(*p_to_vals, NULL);
            if (tmp >= -5.0 && tmp <= 5.0)
            {
                amp = tmp;
                break;
            }
            else
            {
                printf("Invalid amplitude value!\n");
                return 2;
            }
        case 'f':
            valid_float = isValidFloat(*p_to_vals);
            if (valid_float == 0)
            {
                printf("Invalid float value is given\n");
                return 2;
            }
            tmp = strtod(*p_to_vals, NULL);
            if (tmp >= 0.1 && tmp <= 10.0)
            {
                freq = tmp;
                break;
            }
            else
            {
                printf("Invalid frequency value!\n");
                return 2;
            }
        default:
            printf("Unexpected arguments\n");
            return 2;
        }
        p_to_args += 2;
        p_to_vals += 2;
    }
    return 0;
}

int main(int argc, char *argv[])
{
    int state = 0;

    state = passArgs(argc, argv);
    printf("state %d\n", state);
    printf("freq :%f\n", freq);
    printf("amp: %f\n", amp);
    printf("waveforms: %d\n", waveforms);
    return 0;
}

pass_args.h

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

// three arguments
float freq;    // 0.1 - 10.0 Hz
float amp;     // 0 - 2.5V
int waveforms; // 1 = Sine wave
               // 2 = Triangular wave
               // 3 = Sawtooth wave
               // 4 = Square wave

// This function prints the arguments usage for this program
void printArgumentManual();

// This function checks if the string is a valid float
// Argument:
//         str: pointer to the string
// Return:
//          1: not a valid float
//          0: a valid float
int isValidFloat(const char *str);

// This function pass the argument
// Argument:
//      argc: number of argument
//      argv: pointer to pointer of argument
// Return:
//      0: success
//      1: no command line argument used
//      2: invalid option
//      3: choose default setting while providing values
int passArgs(int argc, char *argv[]);

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

Пожалуйста, предоставьте минимальный воспроизводимый пример

ForceBru 09.04.2023 18:40

Скорее всего, ваш код обработки аргументов читает дальше конца argv.

Barmar 09.04.2023 18:40

Ваш код было бы легче читать и писать, если бы вы обращались к элементам массива следующим образом: p_to_args[0][0]

Barmar 09.04.2023 18:48

Или вместо арифметики указателей просто используйте индексы массива. argv[cur_arg][0] и argv[cur_val]

Barmar 09.04.2023 18:50
*p_to_vals == '\0' сравнивает указатель с символом. Вы, наверное, имели в виду p_to_vals[0][0] == '\0', или еще лучше, strlen(*p_to_vals) == 0.
Schwern 09.04.2023 18:54

Пожалуйста, уменьшите свой код, чтобы было легче найти вашу проблему. Следуйте этим рекомендациям, чтобы создать минимально воспроизводимый пример.

Community 09.04.2023 23:09

@Barmar Бармар, конечно, я обязательно рассмотрю возможность использования индексов массива в следующий раз. Спасибо за ваш вклад.

Jayden 10.04.2023 07:12

Вы также можете избежать всей этой проблемы, используя функцию getopts() для анализа параметров. Это позволит вам смешивать варианты, которые принимают аргументы, с теми, которые не требуют, чтобы все было в парах.

Barmar 10.04.2023 16:46

@Barmar Я пытался использовать это раньше, но если пользователь передает - aw, это будет воспринято как - w, то есть смотреть только на последний символ.

Jayden 11.04.2023 01:59

Это потому, что он реализует стандартную обработку опций, которая позволяет вам писать -a5 вместо -a 5. А флаги без аргументов можно комбинировать, например ls -alt вместо ls -a -l -t.

Barmar 11.04.2023 02:07
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
10
61
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

*p_to_args[1] делает не то, что вы думаете.

Вы хотите, чтобы это было так: (*p_to_args)[1]. Сначала разыменуйте указатель, затем посмотрите на его 2-й элемент.

Но это действительно так: *(p_to_args[1]). Сначала посмотрите на его второй элемент, а затем разыменуйте его.

С такими аргументами, как -a 5 -w square -e, если p_to_args[0] равно -e, то p_to_args[1] будет нулевым указателем. *p_to_args[1] пытается разыменовать нулевой указатель. Сбой программы.


Вместо этого убедитесь, что разыменование заключено в круглые скобки.

(*p_to_args)[1] == '\0'

Лучше: используйте обычный синтаксис массива.

if (p_to_args[0][0] != '-' || p_to_args[0][1] == '\0')        {

Лучшее: Ошибка при нечетном числе аргументов (argc четное).

    if (argc <= 2) // no command line argument used
    {
        fprintf(stderr, "no option given\n");
        return 1;
    }
    if (argc % 2 == 0 ) {
        fprintf(stderr, "options are not in pairs\n");
        return 1;
    }

Тогда вам не нужно проверять, является ли p_to_vals нулевым.

        if (p_to_args[0][0] != '-' || p_to_args[0][1] == '\0')        {
            fprintf(stderr, "expected a switch like -a");
            return 2;
        }
        if (p_to_vals[0][0] == '\0')
        {
            fprintf(stderr, "the value is empty\n");
            return 2;
        }

Демонстрация.

спасибо за ваш вклад. Я обязательно буду использовать обычный синтаксис массива. Это намного яснее.

Jayden 10.04.2023 07:11

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