在现有程序中为选项参数添加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()函数,以使其熟悉。
答案 0 :(得分:2)
如果您更好地缩进该代码,则很明显,您正在argv
循环内修改argc
和while
,而不是在处理完所有选项之后执行一次。 / 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);
}