基本上练习说“创建一个函数,它将一个数组作为参数及其大小,并返回一个新数组,其中包含作为参数给出的数组的三个最大值。”所以我认为我将获取数组并在函数中对其进行排序,然后将3个最高值赋予新数组并返回它。那是我的代码。
int *function(int *A, int k){
int B[3],i,j,temp;
//Sorting
for(i=k-1;i>0;i--){
for(j=1;j<=i;j++){
if(A[j-1] > A[j])
{
temp = A[j-1];
A[j-1] = A[j];
A[j] = temp;
}
}
}
i = 0;
while(i < 3){
B[i]= A[k-1];
i++;
k--;
}
return B;
}
int main (int argc, const char * argv[]) {
int A[5] = {1,8,7,4,6};
int size = 5;
int *func,i;
func = function(A,size);
for(i=0;i<3;i++)
printf("%d ",func[i]);
return 0;
}
结果我应该得到8 7 6但是我得到8 -1073743756 6.我找不到错误。当我想返回B时,我也会收到警告。它说“函数返回本地变量的地址”。也许这与这个问题有关。有什么想法吗?
答案 0 :(得分:3)
函数返回后,自动存储对象(例如int B[3]
)将被销毁,因此引用它们是非法的。在实践中,由于写入堆栈的各种内容,您将获得意外的值:
你可以:
malloc
(以及之后的free
)B
答案 1 :(得分:2)
变量B的'生命周期'是声明它的函数的持续时间。当它超出范围时,它不再存在,并且其存储器可能被重用于其他目的。您应该将所有编译器警告视为错误 - 它们通常是语义错误(与语法错误相反);也就是说,编译器理解代码,但它不太可能是你想要的,或者可能有无意或未定义的行为。
在这种情况下,编译器会告诉您究竟是什么问题。您需要问的是如何最好地解决错误。
当调用者需要由函数填充数组时使用的正常模式是调用者将数组提供给函数。因为数组在传递给函数时“衰减”到指针,所以传递长度也是正常的,这对于避免缓冲区溢出很有用。你可以让函数“知道”在你的情况下缓冲区长度总是3,但是它的可维护性较差而且安全性较低。
通常这样的函数返回一个指向调用者缓冲区的指针,或者在失败时返回NULL,因此它可以用于错误检查或用作另一个函数的参数。
示例:
int* fn( int* caller_buffer, int caller_buffer_length )
{
int i ;
for( i = 0; i < caller_buffer_length; i++ )
{
caller_buffer[i] = ... ;
}
}
然后
int my_buffer[3] = {0} ;
int my_buffer_length = sizeof(my_buffer) / sizeof(*my_buffer) ;
int* error_check = 0 ;
...
error_check = fn( my_buffer, my_buffer_length ) ;
if( error_check != 0 )
{
...
}
可以通过静态,全局或动态分配B来解决问题。所有这些解决方案我都称之为“快速而肮脏”。它们可以解决这个特定的问题,但不是一种可以很好地扩展到更复杂和更大的应用程序的一般模式。
function()
内本地的动态内存分配引发了谁负责释放分配的内存的问题?
本地静态分配有效,但如果您再次调用该函数,之前的数据将会丢失,这可能并不总是可以接受。它也没有重复,导致多线程应用程序或递归算法中的潜在问题。
全局数据是静态分配的,但作为全局可见的附加问题,因此不再受单一功能的控制。
答案 2 :(得分:1)
B是局部变量,当函数退出时消失。
在函数外部声明B,并通过指向函数传递它。
答案 3 :(得分:1)
B[]
正在运行时,function()
仅生成 ( local )。返回后它没有被引用。
如果您的任务文本被精确引用,您似乎必须深入了解malloc。然后我现在就说:
在文本之后使用malloc的原因:
“返回新数组”
“仅使用数组和计数器”,而不是第三个参数或重复使用 A 。
不要因为使用全局数组的诱惑而堕落;),你可能被允许使用静态? - (编辑:@Clifford对于为什么没有好点)
祝你好运!
修改强>
另外:你不“获取内存地址而不是值”。
当调用function()
时,会给出一个返回地址的地址。其次,该函数中 local 变量的内存被保留,并且它们的名称被赋予地址。 IE浏览器。类似的东西:
/* assuming 4 byte int */
[ 0xA4 ... 0xAF ] <-- int B[3] -- 3 * 4 = 12 bytes
[ 0xB0 ... 0xB4 ] <-- int i -- 4 bytes
[ 0xB5 ... 0xB9 ] <-- int j -- 4 bytes
[ 0xBA ... 0xBE ] <-- int temp -- 4 bytes
当函数返回时,这些区域被释放。因为没有使用电源来擦除它所保留的数据,但是当另一个操作使用该区域时,它可以随时被覆盖。
即。从您的代码可能是printf()
或者它可能是完全不同的东西。重点是它不是保留,可以用于“什么都有”。 (不做煎饼,但我猜你会那么做)。
因此,当您打印func
的值并获得2正确且错误时,这意味着第一个尚未被覆盖,而最后一个已被另一个呼叫覆盖。它甚至可以使用。
最后一个值不是地址,而是另一个解释为整数的值。它也不一定是一个int。如果另一个函数在该区域写了一个short int或char(最可能是4个字节),那么你所做的就是读取4个字节并将这些位解释为int。
说:
B[2] == 6 (on a 4 bytes, int 32, system)
Address: 0xAC 0xAD 0xAE 0xAF As bit sequence
Value : 6 0 0 0 ==> [0000 0110 0000 0000 0000 0000]
返回主,fun[2] -> [0xC 0xD 0xE 0xF]
在其他地方,函数定义char
(1个字节)并获取现在的免费地址0xD
它将值123写入该地址。
现在我们有:
fun[2]:
Address: 0xAC 0xAD 0xAE 0xAF As bit sequence
Value : 6 123 0 0 ==> [0000 0110 0111 1011 0000 0000]
或者如果我们在小端系统(就像我的)上翻译那么,我们得到一个整数
+--------- Least significant byte
|
Address: 0xAC 0xAD 0xAE 0xAF
Value : 6 123 0 0 ( == 0x06 0x7B 0x00 0x00 )
Sort to "human Anglo left right order"
0 0 123 6 => 0x00007B06 == 31494 (int, "normal human number"), and the number
you print when doing the for() loop in
main.
也可以使用像
那样的字节 +----- bytes of fun[2]
|
_________+_________
[ ]
char foo 0xAC |
int bar 0xAD 0xAE 0xAF 0xB0
[____+______________]
|
+---- bytes of bar
数字1和2正确的事实既不保证字节没有被改变。可以将相同的值写入该位置。 0可以写入int等的字节2
胡佛表示:
*作为一个半音符,只是为了进一步混淆,它可能是一个地址,但接着是该地址的整数表示。事实上,这不太可能......它可能是某些动作的返回地址,您将其解释为int。*
希望你能获得至少1%的收益。我主动学习自己,解释经常学习:)