2012-03-25 36 views
0

基本上练习说“创建一个函数,它将一个数组及其大小作为参数创建并返回一个新数组,其中包含作为参数给出的数组的三个最大值。”所以我认为我会把数组和排序在函数中,然后将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时,我也会收到一个警告。它说“局部变量的函数返回地址”。也许这与这个问题有关。有任何想法吗?

回答

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()回避的是谁则负责释放分配的内存的问题?

本地静态分配的作品,但如果你调用函数第二次以前的数据都将丢失,这可能并不总是被接受。它也不是可重用的,在多线程应用程序或递归算法中造成潜在问题。

全局数据是静态分配的,但由于是全局可见的另一个问题,所以不再下一个功能的唯一控制权。

+0

+1对于一个反映和水平的答案。 – Morpfh 2012-03-25 12:49:11

3

函数返回后,自动存储对象(如int B[3])被销毁,因此引用它们是非法的。在实践中,你将得到的,因为写入栈各种东西意外的值:

您可以:

  • 得到B,静态存储
  • 使用malloc(后来free
  • 使用不同的方法总之,例如使呼叫者负责传递B
+1

所以我做了一些改变。我做了int * B,然后B =(int *)malloc(3 * sizeof(int)),程序工作,警告也不存在了。但写入B [3]和使用malloc写入数组B有什么区别?当我们从一开始就不知道数组的大小时,我们不使用malloc吗?在这个例子中,我从一开始就知道数组B的大小为3. – captain 2012-03-25 10:54:34

+0

这些建议不是为了建议的顺序;我会把名单倒过来。 – Clifford 2012-03-25 11:27:40

+0

@captain +1好子问题:) – Morpfh 2012-03-25 12:53:10

1

B是一个局部变量,函数退出的方式。

声明B函数外,并通过函数指针传递它。

1

B[]阵列仅function()运行时,(它是本地)。返回后它是un-refferenced。

如果您的任务文本被精确引用,看起来好像您将不得不挖掘malloc。然后我就现在说:

  • 不要投malloc的
  • 免费()时完成

原因使用malloc,以下文本

  1. “Return a new array”

  2. “仅使用阵列和计数器”,而不是第三个参数或重新使用A

不要因为使用全局数组的诱惑而失败;),你可能被允许使用静态? - (编辑:@Clifford关于为什么没有好点)

祝你好运!


编辑:
另外:你不“获取内存地址,而不是值”

function()被调用时,会给出返回地址。其次,该函数中的本地变量的内存被保留,并且它们的名称被赋予地址。 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 

当函数返回时,这些区域被释放。由于没有必要使用电源擦除停留在该处的数据,但在另一个操作使用该区域时可以随时覆盖它。

I.e.从你的代码可能是printf()或者它可能是完全不同的东西。要点是它不是保留并且可以用于“什么是”。 (不做煎饼,但我想你明白了)。

因此,当您打印func的值并得到2个正确和一个错误时,这意味着两个第一个尚未被覆盖,而最后一个被另一个调用覆盖。它甚至可以被使用。


上一个值不是地址,而是另一个值被解释为整数。它也不一定是一个整数。如果另一个函数向该区域写入短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个字节中

胡佛显示:

*作为一个半音符,只有进一步混淆,它可能是地址,但随后该地址的整数表示。事实上,这不是不太可能...它可能是一些行动的回报地址,你可以解释为一个整数。*

希望你至少得到1%。我主动学习自己和解释往往是学习:)