选项参数和命令行参数

3

我正在从用户那里获取命令行参数。

然后,我会针对这些命令使用开关语句,例如:

    case 'f':
         *file_name = optarg;
         break;

我不确定是否需要为指针分配内存,因为我不完全理解optarg。

这是file_name的声明方式:

char **file_name;

我应该做什么?

int length = strlen(optarg); // This gives a warning about types when compiling.

那么为字符串长度+1分配内存吗?

对于这种问题应该如何进行malloc?请记住,用户将文件名输入**argv。

编辑: 这是我调用此函数的方式,仍然出现分段错误。

int main(int argc, char **argv)
{
   char **file_name;
   parser(argc, argvm file_name);
}

void parser(int argc, char **argv, char **file_name)
{
  // Switch cases.
}
2个回答

7

'optarg'只是argv[]中元素的一个指针。因此,不分配内存并复制'optarg'指向的值是安全的。

假设你的程序使用以下参数:

myapp -a "hello" -b "world"

你的代码是:

#include <stdio.h>
#include <getopt.h>

void parse_options(int argc, char* argv[], char ** first_arg, char ** second_arg)
{
  const char* opt_string = "a:b:";
  int opt = -1;
  opt = getopt(argc, argv, opt_string);
  while (opt != -1) {
    switch(opt) {
      case 'a':
        *first_arg = optarg; /* points to argv[2]="hello" */
        break;
      case 'b':
        *second_arg = optarg; /* points to argv[4]="world" */
        break;
      default:
        break;
      }
    opt = getopt(argc, argv, opt_string);
  }
}

int main(int argc, char* argv[])
{
  char* first = 0;
  char* second = 0;
  parse_options(argc, argv, &first, &second);
  printf("first=%s, second=%s\n", first, second);
  return 0;
}

我的输出:

freebsd% gcc -Wall main.c
freebsd% ./a.out -a hello -b world
first=hello, second=world

我在这一行代码 file_name = optarg; 不断地收到"分段错误"的提示。这是否与我将其放在一个函数内有关呢?(我将在上面发布代码) - Mike John
我的逻辑是,我需要传递一个指向file_name指针的指针,以便在主函数中接收文件名。 - Mike John
我做了一些工作示例(请参见编辑后的文本),希望这可以帮到你。 - dnk
是的,没错。我调用了函数但没有给它文件名的地址。&file_name。谢谢。 - Mike John

2

你说你有:

char **file_name;
...
switch (opt)
{
case 'f':
     *file_name = optarg;
     break;
...
}

代码崩溃的原因是您没有分配空间或初始化变量file_name
您需要根据您想要发生的情况进行更改。通常情况下,您会将file_name的定义更改为:
char *file_name = 0;
...
switch (opt)
{
case 'f':
     file_name = optarg;
     break;
...
}

这可以让您在循环/开关之后检测文件名是否已提供,如果没有,则可以提供默认值或报告错误。在某些情况下,您可以检测先前是否提供了文件名并进行对象化。
另一种方案是允许在命令行上多次使用“-f”。然后,您需要建立一个指针数组,并保持计数。您可以编写如下内容:
char **file_name = 0;
size_t num_files = 0;
size_t max_files = 0;
...
switch (opt)
{
case 'f':
     if (num_files == max_files)
     {
         size_t new_files = (max_files + 2) * 2;
         void  *new_space = realloc(file_name, new_files * sizeof(*file_name));
         if (new_space == 0)
             ...report out of memory error...
         file_name = new_space;
         max_files = new_files;
     }
     file_name[num_files++] = optarg;
     break;
...
}

这里使用了realloc()的奇特属性,如果传入的指针为NULL,则模拟malloc()。或者,您可以在循环外部进行初始malloc()分配,并在循环内部执行(相同的)realloc()。计算大小时,首次分配4个条目,然后是12个,然后是28个等等。如果您担心过度分配,可以在循环结束后再次使用realloc()调整大小到正确的大小,但这可能不会对事情产生太大影响。
循环后,您将获得一个文件列表,可以使用以下方法处理:
for (size_t i = 0; i < num_files; i++)
    process_file(file_name[i]);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接