Функция getopt () демонстрирует странное поведение - PullRequest
0 голосов
/ 11 февраля 2019

Добавление getopt () для аргументов опции к уже существующей программе приводит к странному поведению.

Программа принимает строковый ввод, затем читает слова из файла (каждый на новой строке) и проверяет, является ли строканаходится в файле. Если это так, строка отправляется в файл Existing.txt и, если нет, она переходит в Non -isting.txt.Проблема с getopt () и странным поведением, которое он демонстрирует (опции -n и -e для изменения несуществующих и существующих файлов соответственно)

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

int main(int argc, char *argv[]) {  
    char word[80];
    char word_in_file[80];
    int ch;


FILE *existing = fopen("Existing.txt", "w");      //Open the existing and non_existing file streams   
FILE *non_existing = fopen("Non-existent.txt", "w");

    while((ch = getopt(argc, argv, "n:e:")) != -1){
    switch(ch){
        case 'n':     
            non_existing = fopen(optarg, "w");
            break;

        case 'e':               
            existing = fopen(optarg, "w");
            break;
        default:
            fprintf(stderr,"Unknown option argument: %s", optarg);
            return 1;
    }
        argc -= optind;
        argv += optind;
}

printf("Enter ZA WARDSU:\n");
while (scanf("%79s[^\n]", &word)) { //Main loop that scans input 
    if(strcmp(word ,"exit") == 0){
        printf("You are now done!\n");
        break;
    }
    FILE *input = fopen(argv[1], "r"); // The stream is initialised here in order to reset it for every loop, the next loop just begins from where it last cut off

    while ((fscanf(input, "%79s[^\n]\n", &word_in_file) != EOF)) { // loop that scans the input file 
        if(strcmp(word_in_file, word) == 0 ){                       //if word is in the input file, print it to the existing file 
            fprintf(existing, "%s\n", word);    
            break;  

        }              

    }
    if (strcmp(word, word_in_file) != 0 )       //if word isn't in the input file, print it to the non_existing file 
        fprintf(non_existing, "%s\n", word);    //In main loop because it needs to do this check after it's gone through all the words

}   

fclose(existing);      //close some data streams
fclose(non_existing);
return 0; 
}

Поэтому, когда я запускаю его таким образом,- ./check -n Nexname.txt -e Exname.txt inFile.txt это просто segfaults, а стекдамп - что-то вроде Exception: STATUS_ACCESS_VIOLATION at rip=001801C189A

Затем я пытаюсь - ./check -nNexname.txt -eExname.txt inFile.txt. На этот раз он не падает, но только создает и записывает в файл аргументов первого параметраи для второго он просто записывает в значение по умолчанию.

И если я пытаюсь сделать это только с одной опцией, подобной этой - ./check -nNexname.txt inFile.txt, это просто останавливает программу после того, как я пишу в первом слове.

Редактировать: Это также не вызывает segfault, когда я делаю это таким образом ./check -n Nexname.txt -eExname.txt inFile.txt

Может кто-нибудь, пожалуйста, объясните мне причину этого поведения (и как это исправить).

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

Ответы [ 2 ]

0 голосов
/ 13 февраля 2019

Создание массивов символов для имен файлов по умолчанию.
Установите для указателей FILE значение NULL.
Скопируйте параметры команды в массивы символов.
Проверьте наличие повторяющихся имен файлов.
Откройте файлы.
Сканировать слово из стандартного ввода.
Сканировать слова из входного файла, пытаясь найти совпадение.
После прочтения входного файла перемотайте его на следующее слово из стандартного ввода.
Закрыть всефайлы.

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

void useage ( char *name);

int main ( int argc, char *argv[]) {
    char non_existing_file[80] = "Non-existent.txt";//default file name
    char existing_file[80] = "Existing.txt";
    char input_file[80] = "Default.txt";
    char word[80] = "";
    char word_in_file[80] = "";
    int ch = 0;
    //do not open files. Could be argument or default
    FILE *existing = NULL;
    FILE *non_existing = NULL;
    FILE *input = NULL;

    opterr = 0;//suppress default error messages

    while ( ( ch = getopt ( argc, argv, "n:e:")) != -1) {
        switch ( ch) {
            case 'n':
                if ( optarg) {//optarg not NULL
                    strncpy ( non_existing_file, optarg, 79);
                    non_existing_file[79] = 0;//make sure zero terminated
                }
                break;
            case 'e':
                if ( optarg) {
                    strncpy ( existing_file, optarg, 79);
                    existing_file[79] = 0;
                }
                break;
            case '?':
                if ( optopt == 'e' || optopt == 'n') {
                    fprintf ( stderr, "option -%c requires an argument.\n", optopt);
                }
                else {
                    fprintf ( stderr, "\ninvalid option -%c\n", optopt);
                }
            default:
                useage ( argv[0]);
                return 1;
        }
    }

    if ( ! strcmp ( non_existing_file, existing_file)) {
        fprintf ( stderr, "\nduplicate file names for options -e and -n\n");
        useage ( argv[0]);
        return 1;
    }
    if ( optind < argc) {//another argument to process
        if ( ! strcmp ( non_existing_file, argv[optind])
        || ! strcmp ( argv[optind], existing_file)) {
            fprintf ( stderr, "\ninput file name matches file name for options -e or -n\n");
            useage ( argv[0]);
            return 1;
        }
        strncpy ( input_file, argv[optind], 79);
        input_file[79] = 0;
    }

    //open files

    if ( NULL == ( input = fopen ( input_file, "r"))) {
        fprintf ( stderr, "could not open %s\n", input_file);
        return 1;
    }
    else {
        printf ( "%s opened\n", input_file);
    }

    if ( NULL == ( existing = fopen ( existing_file, "w"))) {
        fclose ( input);//close the already opened
        fprintf ( stderr, "could not open %s\n", existing_file);
        return 1;
    }
    else {
        printf ( "opened %s\n", existing_file);
    }

    if ( NULL == ( non_existing = fopen( non_existing_file, "w"))) {
        fclose ( input);//close the already opened
        fclose ( existing);
        fprintf ( stderr, "could not open %s\n", non_existing_file);
        return 1;
    }
    else {
        printf ( "opened %s\n", non_existing_file);
    }

    int found = 0;
    printf ( "Enter ZA WARDSU:\n");
    while ( 1 == scanf ( "%79s", word)) { //Main loop that scans stdin
        if ( strcmp ( word , "exit") == 0) {
            printf ( "You are now done!\n");
            break;
        }
        found = 0;
        while ( 1 == fscanf ( input, "%79s", word_in_file)) { // loop that scans the input file
            if ( strcmp ( word_in_file, word) == 0 ) {//if word is in the input file, print it to the existing file
                fprintf ( existing, "%s\n", word);
                found = 1;
                break;
            }
        }
        if ( ! found) {//if word isn't in the input file, print it to the non_existing file
            fprintf ( non_existing, "%s\n", word);//In main loop because it needs to do this check after it's gone through all the words
        }
        rewind ( input);//back to start of input to check for next word
    }

    fclose ( existing);
    fclose ( non_existing);
    fclose ( input);
    return 0;
}

void useage ( char *name) {
    fprintf(stderr
    , "\nUsage:\n\t%s [-eopte] [-noptn] [opt]\n or\n\t%s [-e opte] [-n optn] [opt]\n"
    , name, name);
}
0 голосов
/ 11 февраля 2019

Если вы отступите в этом коде лучше, будет ясно, что вы изменяете argv и argc внутри цикла while вместо того, чтобы делать это один раз после обработки всех опций.

...