【问题标题】:How do I properly turn a const char* returned from a function into a const char** in C?如何正确地将函数返回的 const char* 转换为 C 中的 const char**?
【发布时间】:2011-02-17 07:16:01
【问题描述】:

简而言之,我想这样做:

const char **stringPtr = &getString();

但是,我知道您不能 & on rvalues。所以我坚持这个:

const char *string = getString();
const char **stringPtr = &string;

我可以忍受两条线。我是否在介绍此 hack 的问题?我应该不用担心将stringPtr 从它声明的函数中传递出去,对吧?

编辑:我很抱歉最初没有包含完整的上下文。 我已经承担了暑期项目,即使用 OpenGL 进行图形从头开始用 C 语言构建视频游戏。我正在使用 libconfig 从文本文件中读取配置数据。

从配置文件中查找特定字符串的便捷函数如下所示:

int config_setting_lookup_string(const config_setting_t *setting,
                                 const char *name, const char **value)
{
  config_setting_t *member = config_setting_get_member(setting, name);
  if(! member)
    return(CONFIG_FALSE);

  if(config_setting_type(member) != CONFIG_TYPE_STRING)
    return(CONFIG_FALSE);


  *value = config_setting_get_string(member);
  return(CONFIG_TRUE);
}

分配值的方式意味着,如果您给函数一个未初始化的value,它会尝试取消对未定义垃圾的引用,这几乎总是会导致我出现段错误。我目前针对此问题的解决方法是先将 value 初始化为另一个指针,如下所示:

const char *dummyPtr;
const char **fileName = &dummyPtr;
config_setting_lookup_string(foo, "bar", fileName);

所以我试图找出重写函数最后一部分的最佳方法,这样我就不必执行这个两步初始化。我在想改变后的功能应该是这样的:

int config_setting_lookup_string(const config_setting_t *setting,
                                 const char *name, const char **value)
{
  config_setting_t *member = config_setting_get_member(setting, name);
  if(! member)
    return(CONFIG_FALSE);

  if(config_setting_type(member) != CONFIG_TYPE_STRING)
    return(CONFIG_FALSE);

  const char *string = config_setting_get_string(member);
  value = &string;
  return(CONFIG_TRUE);
}

【问题讨论】:

    标签: c pointers double-pointer const-char libconfig


    【解决方案1】:

    如果你调用的函数需要const char**,你可以这样做:

    const char *s = getString();
    myFunction(&s);
    

    由于在上面的例子中s被分配在堆栈上,如果你想从你的函数中返回一个const char**,你需要把它放在堆上:

    const char **sp = malloc(sizeof(const char *));
    *sp = getString();
    return sp;
    

    HTH

    【讨论】:

      【解决方案2】:

      string 在您的情况下是本地的,因此获取它的地址是一个坏主意,因为当您离开该方法时,本地的内存可以(并且可能会)重新用于其他目的。一般来说,在其作用域之外使用局部变量的地址并不是一个好主意。

      你想达到什么目的?

      【讨论】:

      • 之前应该添加的。感谢您的菜鸟耐心。现已编辑。根据文档,“config_lookup_string() 返回的字符串的存储由库管理,并在设置被破坏或设置值更改时自动释放;调用者不得释放该字符串。” hyperrealm.com/libconfig/libconfig_manual.html#The-C-API
      【解决方案3】:

      不,您不能按照您描述的方式更改config_setting_lookup_string()。您正在返回一个指向 string 变量的指针,但是一旦该函数结束,该变量就会超出范围并被销毁。

      但是,您可以很容易地解决最初的问题。保持 config_setting_lookup_string() 的定义不变,这样称呼它:

      const char *fileName = NULL;
      config_setting_lookup_string(foo, "bar", &fileName);
      

      【讨论】:

        【解决方案4】:

        从添加的信息来看,您似乎正在尝试调用一个函数,该函数希望通过其中一个函数参数返回一个字符串。在我看来,最好的方法是:

        const char* fileName;
        config_setting_lookup_string(..., &fileName);
        (...)
        return fileName;
        

        这将为堆栈上的 const char* 分配空间。函数调用将用它想要返回的字符串的地址填充指针。如果需要,这个指针值可以从函数中传递出去(不像指针的指针,它指向堆栈,并且在函数返回时无效)。 请注意,使用“getString()”初始化文件名​​可能会泄漏内存,因为指向返回字符串的指针将被覆盖,并且该字符串永远不会被释放。

        【讨论】:

          【解决方案5】:

          你需要这两行。但是,string 是栈上的一个局部变量,一旦超出范围,你可能就没有指向 getString() 返回的数据的指针了。

          【讨论】:

            【解决方案6】:

            我喜欢 nornagon 和 caf 的解决方案,

            const char *fileName;
            config_setting_lookup_string(foo, "bar", &fileName);
            

            但如果您可以更改config_setting_lookup_string,您也可以这样做:

            int config_setting_lookup_string(..., const char *&value)
            {
              ...
              const char *string = config_setting_get_string(member);
              value = string;
              ...
            }
            
            const char *fileName;
            config_setting_lookup_string(foo, "bar", fileName);
            

            【讨论】:

              【解决方案7】:

              如果您返回 stringPtr,您将返回一个指向局部变量 (string) 的指针。所以不,你不能那样做。

              你为什么要这样做?这可能会让我们提出更好的建议。

              更新: 好的,现在我明白你要做什么了。你做错了:

              value = &string;
              

              如果value 用作输出参数,则上述行无法工作,因为您分配给局部变量

              不要让额外的间接级别让您感到困惑。如果你正在编写一个具有T 类型的输出参数的函数,你可以这样写:

              void foo(T* value)
              {
                  *value = GetT();
              }
              

              现在将T 替换为const char*

              ...
              *value = string;
              ...
              

              现在您没有涉及任何临时的局部变量。当然,这就是代码最初的编写方式(并且那部分是正确的),所以这并不能真正帮助你。为了解决您的意图,您应该:

              1. config_setting_lookup_stringassert(value != NULL)
              2. 审核函数的调用者并修复它们以停止传递垃圾。他们应该这样做:

                const char* foo; config_setting_lookup_string(..., &foo);

              而不是:

              const char** foo;
              config_setting_lookup_string(..., foo);
              

              【讨论】:

              • 编辑并添加了我正在尝试做的事情的完整背景。基本上,我正在尝试重写一个通过 const char ** 返回字符串的库例程,以包含一些更适合我的样板初始化代码。
              猜你喜欢
              • 2019-09-10
              • 1970-01-01
              • 1970-01-01
              • 2015-04-02
              • 1970-01-01
              • 1970-01-01
              • 2013-12-31
              • 2012-01-16
              • 1970-01-01
              相关资源
              最近更新 更多