表现出奇怪行为的getopt()函数

时间:2019-02-11 18:44:29

标签: c command-line-interface command-line-arguments getopt command-line-tool

在现有程序中为选项参数添加getopt()会导致异常行为。

程序输入一个字符串,然后从文件中读取单词(每个换行),并检查该字符串是否在文件中;如果存在,则将该字符串发送到Existing.txt文件中;如果不是,转到Non-existing.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都会出现段错误,并且stackdump类似于Exception: STATUS_ACCESS_VIOLATION at rip=001801C189A

然后我尝试-./check -nNexname.txt -eExname.txt inFile.txt。这一次它不会崩溃,但是仅生成并写入第一个选项的参数文件,而第二个它仅写入默认值。

如果我尝试仅使用一个这样的选项-./check -nNexname.txt inFile.txt来执行此操作,那么它只会在我写出第一个单词后停止程序。

编辑:当我这样做./check -n Nexname.txt -eExname.txt inFile.txt

时,它也不会出现段错误

有人可以向我解释此行为的原因(以及如何解决)。

我知道我可以使用主函数args来做同样的事情,但是我想尝试一下getopt()函数,以使其熟悉。

2 个答案:

答案 0 :(得分:2)

如果您更好地缩进该代码,则很明显,您正在argv循环内修改argcwhile,而不是在处理完所有选项之后执行一次。 / p>

答案 1 :(得分:0)

为默认文件名创建char数组。
将FILE指针设置为NULL。
将命令选项复制到char数组中。
检查文件名是否重复。
打开文件。
扫描来自stdin的单词。
扫描输入文件中的单词,尝试找到匹配项。
读取输入文件后,将其倒回标准输入中的下一个单词。
关闭所有文件。

#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);
}