【问题标题】:Optarg and Command Line ArgumentsOptarg 和命令行参数
【发布时间】:2013-11-13 21:54:57
【问题描述】:

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

然后我为命令做 switch case,例如:

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

我不确定是否需要 malloc 指针,因为我不完全理解 optarg。

file_name 是这样声明的:

char **file_name;

我应该这样做

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

然后malloc为字符串长度+1?

这种问题应该怎么做malloc呢?记住用户在 **argv 中输入了 file_name。

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

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.
}

【问题讨论】:

    标签: c malloc command-line-arguments


    【解决方案1】:

    '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;如果我在一个函数中这样做有关系吗? (我会把上面的代码贴出来)
    • 我的逻辑是我需要传递一个指向 file_name 指针的指针,以便在 main 中接收文件名。
    • 我做了一些工作示例(参见编辑后的文本),希望对您有所帮助。
    • 是的。我正在调用该函数,但没有给它 file_name 的地址。 &文件名。谢谢。
    【解决方案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]);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-25
      • 2012-10-04
      • 2010-12-08
      • 2012-01-28
      • 2013-03-24
      • 2013-04-09
      • 1970-01-01
      • 2014-05-30
      相关资源
      最近更新 更多