关于 C++(或 C)中的指针的函数作用域

Function scope regarding pointers in C++ (or C)

本文关键字:指针 函数 作用域 C++ 关于      更新时间:2023-10-16

我正在尝试编写可移植代码,允许函数访问数组等变量,即使它只是一个值。它背后的想法是代码不会生成大小为 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(&foo) 。这应该有效,并且(我认为)它避免返回临时函数范围地址。转换的结果可以通过索引访问。在受控的 for 循环中,代码将平稳运行。程序会知道有多少元素是值,但在 for 循环中运行所有元素会比不运行所有元素更快。

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

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

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

另一种解决方案是使用重载运算符制作 2 个函数,这些运算符基本上可以执行整个代码,而无需转换每个变量,但代码库非常大,这需要尽可能可移植。我相信,参考convert将更能证明未来。

您已经将其标记为C++,所以我假设您使用的是C++编译器。

你的问题中有很多内容,所以我要简化一下。您需要一个C++函数convert(x)它将:

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

(一般来说,也许你需要重新设计整个事情,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以清楚起见。

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

更新 下面是一个更完整的示例,展示了如何使用convertconvert_end来查找数组的开头和结尾,以迭代数组中的所有元素;当然,非数组被视为一个元素的数组。

在 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,但返回不会造成伤害。