关于C ++(或C)中指针的函数范围

时间:2015-01-30 15:22:44

标签: c++ function pointers scope

我正在尝试编写可移植代码,允许函数像数组一样访问变量,即使它只是一个值。它背后的想法是代码不会生成大小为1的数组,但是如果它是一个数组,我需要能够遍历数组中的所有值。由于我不能使用sizeof(foo)来确定内存是否大于单个实例sizeof(foo)/sizeof(int)可能有效,但包含在主代码中太麻烦了。宏不会有帮助,因为如果我使用像我这样的三元运算符,期望#define ARRAY_OR_NOT(foo, type) (sizeof(foo)/sizeof(type) > 1) ? (foo) : (&foo)返回一个指针,以便通过索引进行访问。这个问题是编译器不喜欢在指针和非指针之间混合类型。

所以我的第二次尝试是函数重载。

int * convert(int value)
    {return &value;}
int * convert(int * value)
    {return value;}

我知道这不会起作用,因为第一个函数会在该函数范围内返回临时变量副本的地址。所以我的第三次尝试是

int * convert(int * value)
    {return value;}
int * convert(int ** value)
    {return *value;}

每次我调用convert时,都要传递值convert(&foo)的地址。 这应该工作,并且(我认为)它避免返回临时函数范围 地址。转换的结果可以通过索引来访问。在受控的for循环中,代码将平稳运行。程序会知道有多少元素有价值,但是在for循环中运行所有内容会比没有更快。

那么为什么我的第二个代码块产生"警告返回临时范围blahblahblah"警告?

更新:这里的主要XY问题。

基本上我试图将所有代码包装在一个循环中并访问变量中的每个值,每个循环迭代一个值。系统会知道该变量中有多少个值,但代码库太大以至于将if / else中的所有内容包装起来都会很慢。因此,使用索引访问for循环中某些值的方法是int foo = convert(&maybeArray)[counter];然后我会在for循环中多次使用foo。 出于某种原因,Visual Studio在使用第二个代码块时抛出错误。将此添加到OP。

另一种解决方案是使用重载运算符创建2个函数,这些函数基本上可以执行整个代码,而不需要转换每个变量,但代码库非常大,并且需要尽可能的可移植性。引用convert将是我相信的未来证据。

2 个答案:

答案 0 :(得分:2)

您已将此标记为C++,因此我假设您使用的是C ++编译器。

你的问题还有很多,所以我要简化。你想要一个C ++函数convert(x)

  
      
  1. 如果x是数组,则返回第一个元素的地址
  2.   
  3. 如果x不是数组,请返回&x
  4.   

(一般来说,也许你需要重新设计这一切,convert似乎是一个非常奇怪的功能。

template<typename T, size_t N>
auto convert(  T (&t) [N] ) -> T* {
    return t; // just let pointer decay work for us here
}
template<typename T>
auto convert( T &t) -> T* {
    return &t;
}

而且,在C ++中,我绝不会将sizeof用于我认为是数组的东西。这种模板技术是计算数组中元素数量的更安全的方法。

另外,您是否希望拥有指针数组,并希望将单个指针视为指针的单元素数组?如果是这样,那就小心翼翼。看起来像数组的东西实际上可能是指针,例如参数列表foo(int is_really_a_pointer[5]) { ...}中的数组。有关更多信息,请参阅@MSalters的评论。可能善于使用他的断言来捕获任何惊喜。如果您只是使用int,那么请不要在我的模板中使用typename T,为了清楚起见,请强制它int

最后,也许不是将数组转换为指针,而应该要求一个函数将非数组转换为对单元素数组的引用?

更新 以下是more complete example,其中显示了如何使用convertconvert_end查找数组的开头和结尾迭代数组中的所有元素;当然,非数组被视为一个元素的数组。

答案 1 :(得分:1)

在C中,只存在按值传递。将指针传递给函数时,其地址将复制到函数参数中。这只是意味着如果p是调用函数中的指针,那么函数调用

int x = 5;
int *p = &x;
int a = foo(p);   

用于功能定义

int foo(int *p1)
{
    return *p1*2;
}  

意味着:

  • 将地址p点复制到参数p1,即将pp1指向同一位置。
  • 函数foo中p1指向的位置的任何更改都会反映到*p,因为pp1指向同一位置。但是,如果在任何时候p1指向另一个位置,那么这并不意味着p也将指向该位置。 pp1是两个不同的指针。

当您将指针传递给指针时,就像在第二个块的最后一个片段中一样,

int * convert(int ** value)
{return *value;}  

如果*value在传递参数后更改为指向不同位置的点,则传递地址的指针也将使用此位置进行更新。在这种情况下,无需返回*value,但返回不会造成伤害。