【问题标题】:Parsing arguments in C using getopt使用 getopt 在 C 中解析参数
【发布时间】:2023-03-07 03:40:01
【问题描述】:

我正在尝试解析传递给我的程序的参数以在函数中使用它们。 参数的格式是:

emp ­­-p one.txt two.txt three.bin ­-­o file.emp

我想将 -p 之后的参数保存在 char **arg_pack 中,并将 -o 之后的参数保存在 char **arg_output 中。

这是我的部分代码:

#define OPTION_STRING "p:u:r:l:d:o:i:ah"
#define OP_ARG_PACK        'p'

extern char *optarg;
extern int optind, opterr, optopt;

char **arg_pack;
char **arg_output;

int arg_pack_count = 0;
int arg_output_count = 0;

while ((res = getopt(argc, argv, OPTION_STRING)) != -1 )
{
    if (res == (int) OP_ARG_PACK)
    {   
        int index = optind - 1;
        arg_pack_count++;
        while(index < argc)
        {   
            *arg_pack = malloc(strlen(argv[index])+1 );
            strcpy(arg_pack[index], argv[index]);
            index++;

            if ( (index<argc) && ((argv[index])[0] == '-') )
            {         
                optind = index - 1;
                break;
            }
        }
        emp_pack(arg_pack,arg_output);
    }
}

这给了我一个分段错误。这是为什么呢?

【问题讨论】:

  • 你忘了问问题。
  • 请注意,就getopt() 而言,-p 选项后面只有一个文件名(因此在您的示例中,optarg 将被设置为指向字符串"one.txt"调用)。假设您使用 GNU getopt() 函数,在处理了 -o 选项后,其他两个文件名将作为非选项参数提供。如果您使用该函数的经典版本(或者如果您在环境中设置 POSIXLY_CORRECT),则 two.txt 参数不是选项参数;它是第一个非选项参数,其他参数,包括-o,也是非选项参数。

标签: c parsing getopt


【解决方案1】:

根据 Linux 手册页

默认情况下,getopt() 会在扫描时置换 argv 的内容,因此 最终所有的非选项都在最后。

因此,当您尝试在 while 循环中索引 argv 时,您正在索引的 argv 可能与您开始使用的 argv 不同。

【讨论】:

  • 这是很好的信息,但没有回答 OP 关于为什么会出现段错误事件的问题。
【解决方案2】:

关于此代码:

extern char *optarg;
extern int optind, opterr, optopt;

char **arg_pack;
char **arg_output;

int arg_pack_count = 0;
int arg_output_count = 0;

while ((res = getopt(argc, argv, OPTION_STRING)) != -1 )
{
    if (res == (int) OP_ARG_PACK)
    {   
        int index = optind - 1;
        arg_pack_count++;
        while(index < argc)
        {   
            *arg_pack = malloc(strlen(argv[index])+1 );
            strcpy(arg_pack[index], argv[index]);
            index++;

            if ( (index<argc) && ((argv[index])[0] == '-') )
            {         
                optind = index - 1;
                break;
            }
        }
            emp_pack(arg_pack,arg_output);
}

段错误的原因是使用了不指向任何已分配内存的指针(带有偏移索引)。

对malloc() 的调用不断覆盖变量中的指针(如果有):char **arg_pack;

getopt() 只能访问 'found' 选项之后的下一个参数,并且不会处理无效选项,也不会处理选项之后的(预期)多个值。

分配所需内存的一种更简单(虽然有点浪费)的方法是:

char * argpack = NULL;
if (NULL == (argpack = malloc( argc * sizeof(char *) ) ) )
{ // then malloc failed
    perror( "malloc for -p array of pointers failed" );
    exit( EXIT_FAILURE );
}

// implied else, malloc successful

if( NULL == (argoutput = malloc( argc * sizeof( char *) ) ) )
{ // then malloc failed
    perror( "malloc for -o array of pointers failed" );
    free( argpack );
    exit( EXIT_FAILURE );
}

// implied else, malloc successful

while( .... )
{
    .... // use `strdup()` to set the pointers
}

然而,这并不是所发布代码逻辑的全部错误。

建议:

size_t argpackIndex = 0;
size_t argoutputIndex = 0;

char lastSeenOption = '\0';

for( int x=1; x<argc; x++ ) // 1 to skip over executable file name
{
    if( '-' == argv[x][0] )
    {
        lastSeenOption = tolower(argv[x][1]);
    }

    else
    {
         switch( lastSeenOption )
         {
             case 'p':
                argpack[ argpackIndex ] = strdup( argv[x] );
                argpackIndex++;
                break;

             case 'o':
                argoutput[argoutputIndex ] = strdup( argv[x] );
                argoutputIndex++;
                break;

             default:
                fprinf( stderr, "ignoring invalid option: <%c> for parameter value: <%s>\n", 
                        lastSeenOption,
                        argv[x] );
                break;
        } // end switch
    } // end if
} // end for

【讨论】:

    【解决方案3】:
    char **arg_pack; 
    

    arg_pack 指向 NULL。就在这里:

    *arg_pack = malloc(strlen(argv[index])+1 );
    

    我认为这会取消引用空指针并尝试分配给它。

    试试类似的东西

    int arg_pack_max=10;
    arg_pack=malloc(arg_pac_max*sizeof(char *))
    

    如果 arg_pack_count 达到 arg_pack_max,realloc() 并为 arg_pack 获得更多空间

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-28
      • 2018-07-26
      • 1970-01-01
      • 2010-11-06
      • 2015-03-25
      相关资源
      最近更新 更多