大多数网站都这样说:
C编程不允许将整个数组作为参数返回 一个功能。但是,您可以通过返回指向数组的指针 指定没有索引的数组名称。
我刚从指针开始,据我所知,指针变量是一个存储内存地址的变量。当我们使用*取消引用它时,我们得到那个内存地址并保存那里存储的值。此外,在数组的情况下,指针必须指向第一个元素。
现在,如果我们的函数返回一个指向数组第一个元素的指针,如下例所示:
int * myFunction() {
.
.
.
}
在那种情况下,
要记住的第二点是C不提倡返回 函数外部的局部变量的地址,所以你会这样做 必须将局部变量定义为静态变量。
在计算机编程中,静态变量是一个变量 静态分配,以便其生命周期或"范围"延伸到 整个计划的运行。
另一个网站说,
静态存储类指示编译器保留本地 在程序的生命周期中存在的变量而不是 每次进入和离开时创建和销毁它 范围。
有人请给我一个明确的基本解释,静态变量究竟是什么以及它在这个上下文中的相关性(从函数返回数组)。
我真的很困惑。
答案 0 :(得分:1)
我们将取消引用它的内容是什么以及如何解决?
函数返回的指针变量。
通过使用适当的运算符*
,示例:
int z = 5;
int* pointer_to_z = &z; // get memory address of z and store that in pointer_to_z
int can_i_have_my_z_back_please = *z; // check what value is at that memory address and store it, a copy is made here.
“返回指针的函数”是否表示它正在返回 指针指向的内存地址?
它返回一个指针变量,该变量保存值的内存地址。基本上,“指向”一个值与“拥有它的地址”相同。
究竟什么是静态变量? [我冲浪得足够但没找到 任何令人满意的事情。
关于静态变量已经存在很多好的SO答案。总结(仅进入变量的生命周期而不是它的链接)静态变量一旦初始化就对程序的其余部分有效,这意味着它的生命周期不像局部变量那样受范围限制:
void hello()
{
int x = 5;
} // x destroyed here..
void hello_static()
{
static int x = 5;
} // x will only be destroyed at the "end" of the program
这反过来意味着返回本地静态变量的指针(内存地址)是完全安全的,因为静态变量仍然可以访问:
int* return_my_static()
{
static int a = 5;
return &a;
}
int main()
{
int* pointer_to_static = return_my_static(); // get the memory address of the static
printf("%i", *pointer_to_static); // print out the value by dereferencing
}
但是,对于本地非静态变量这样做会导致未定义的行为,因为指向的变量(它的内存地址)不再有效,因为它已被销毁:
int* return_local()
{
int a = 5;
return &a;
} // a is destroyed here.. oopsies
int main()
{
int* pointer_to_local = return_local(); // get the memory address of the local.
//local variable has been destroyed now and 'pointer_to_static' now points to garbage memory!
printf("%i", *pointer_to_local); // Try to print out the value by dereferencing, this is undefined behaviour, anything can happen.
}
请注意,上面的代码可能会运行并输出预期的结果,但这很幸运,这是未定义的行为,应该不惜一切代价避免,因为此时可能发生任何事情。
答案 1 :(得分:0)
问题3:
int a;
void foo() {
int b
static int c;
}
int main() {
foo();
}
当程序启动时,a和c的内存被分配并保持分配,直到程序退出。因此,在任何给定时间,确切地存在于a和c上。每当有人(这里是主要的)调用foo时,b就被分配在堆栈上,直到该函数返回。
关于问题3前面的引用:
返回a和c的地址没有问题,因为只要程序持续存在就会存在,但是将地址返回给b是一个错误,因为只要调用者手中拿到指针,指针就会指向内存无效。
问题1:
通过在前面放一个星号来取消引用指针。指针指向的并不重要。它是一个数组,你可以递增或递减指针以获得你想要达到的索引,就像一个简单的补充:*(p + 4)将访问第5个元素(因为*(p + 0)是第一个,所以*(p + 1)是第二个,依此类推。)
您可以写p [4]而不是写*(p + 4)。
所以假设你的功能看起来像这样:
int * myFunction() {
static int array[8];
return array;
}
然后return语句将返回数组的地址,该地址与数组的第一个元素的地址完全相同。
所以,有int * p = myFunction();然后,您可以使用直观的语法p [0] = 42访问该数组; ...; p [7] = 23;
问题2:
返回指针的函数是返回指针的函数。指针是一个东西,它指向内存中的一个点。通常称为内存地址,但C语言并不关心。所以,实际上,“返回指针的函数”意味着它返回指针所指向的内存地址,是的。
答案 2 :(得分:0)
回到前面:
静态变量究竟是什么?
static
存储持续时间的对象在程序首次启动时为其分配了存储空间,并且该存储一直保持到程序退出为止。如果对象具有static
存储持续时间:
static
关键字示例:
#include <stdio.h>
int g_var; // static storage duration
void foo( void )
{
static int s_var = 10; // static storage duration
int l_var = 10; // auto storage duration
printf( "g_var = %d, s_var = %d, l_var = %d\n", g_var++, s_var++, l_var );
}
在此代码段中,g_var
和s_var
都有static
个存储时间; g_var
因为它是在文件范围s_var
声明的,因为它是使用static
关键字声明的。凭借static
存储持续时间,g_var
被隐式初始化为0.请注意s_var
在程序启动时初始化一次 - 它将 not 在后续调用10
时重新初始化为foo
。因此,每次调用foo
时,输出都将是
g_var = 0, s_var = 10, l_var = 10
g_var = 1, s_var = 11, l_var = 10
g_var = 2, s_var = 12, l_var = 10
...
l_var
的存储时间为auto
- 其生命周期仅限于foo
函数的生命周期。每次调用foo
时,新 l_var
实例的存储都会在函数入口处分配和初始化,并在函数退出时释放。这很重要 - 当l_var
退出时,foo
不再存在,因此当foo
返回<时,指向它的任何指针都将变为无效 SUP> 1
这就是为什么你不能做像
这样的事情int * bar( void )
{
int array[N];
...
return array;
}
因为array
在bar
退出后不再存在,并且返回的指针无效。
现在,解决这个问题的一种方法是将数组声明为static
:
int * bar( void )
{
static int array[N];
...
return array;
}
在这种情况下,当函数退出时array
不会消失,因此指针仍然有效。
...然而
这会产生其他问题。只创建了一个array
实例,它包含了另一个bar
调用写入的最后一个实例。代码不再是 re-entrant ;它不能在执行中期安全地中断,然后在第一次调用完成之前由另一个函数调用。创建一个static
数组只是为了让你可以干净地返回指向它的指针通常错误的答案。
将目标数组作为参数传递给函数:
void foo( int *array, size_t arraySize )
{
...
array[i] = some_value;
...
}
或动态分配一个数组并将指针返回给它:
int * bar( void )
{
int *array = malloc( sizeof *array * N );
if ( array )
{
// initialize array contents
}
return array;
}
这个问题是其他人负责在你完成后释放那些记忆。
“返回指针的函数”是否意味着它返回指针指向的内存地址?
该函数返回指针的值,这是另一个对象的地址。在上面的代码中,bar
返回表达式 array
的值,结果是array
的第一个元素的地址。
在上面bar
的第二种情况中,返回的值等于&array[0]
。
我们将取消引用它的内容是什么以及如何解决?
您可以通过两种方式取消引用指针 - 使用*
取消引用运算符,或使用[]
下标运算符。
下标操作a[i]
定义为*(a + i)
- 给定地址a
,偏移i
元素(不是字节< / strong>)来自a
并取消引用结果。因此,您可以从bar
返回指针,并使用它执行以下操作:
int *p = bar();
printf( "p[0] = %d\n", *p );
printf( "p[0] = %d\n", *(p + 0) );
printf( "p[0] = %d\n", p[0] );
那么,这是否意味着数组和指针是一回事? 没有。数组不是指针;但是,在大多数情况下,数组表达式(即“{元素数组T
”类型的表达式)将被转换(“衰减”)为指针表达式(“指向T
“的指针。
<小时/>
l_var
占用的内存位置仍然存在,因此指针的值不会突然变成垃圾或类似的东西;但是,该内存位置现在可供其他人使用,如果您尝试读取或写入该位置,则可能会导致问题。