主要的非便携式指针分配

时间:2013-04-23 10:07:57

标签: c pointers

在“理解C中的指针”一书中,在解释了一个参数之后,存在一些已解决的问题。第22页,问题N.5 我将附上代码和解释。在那之后,我会有问题。

#include <stdio.h>

int main()
{
    int *c;
    c = check(10, 20);
    printf("c = %p\n",c);
    return 0;
}

int * check(int i, int j)
{
    int *p, *q;
    p = &i;
    q = &j;
    if(i >= 45)
    {
        return p;
    }
    else
    {
        return q;
    }
}

输出: 错误消息:主

中的非可移植指针分配
  

说明错误的原因很简单。整数是   传递给check()的是i和j,然后是他们的地址   分配给p和q。然后在下一个语句中,i的值是   针对45进行测试,并将地址存储在p或地址中   存储在q中的是返回。看来这个地址就是   收集在main()中的c,然后打印出来。那里   是错误。函数check()无法返回   整数指针。它可以返回的只是一个普通的整数。从而   只是将c声明为整数指针是不够的。我们必须做   程序中的以下修改使其正常工作

#include <stdio.h>

int * check(int, int);

int main()
{
    int *c;
    c = check(10, 20);
    printf("c = %p\n",c);
    return 0;
}
int *check(int i, int j)
{
    ......
    ......
}

在我看来,这没有意义。 作者为了在第一段代码上故意发出错误,试图在main中使用一个指向未分配的内存区域的指针。 但他“试图”解决问题的方式根本不正确,他没有改变任何东西!相反,他应该在check()函数中使用malloc一些内存区域。我是对的吗?

7 个答案:

答案 0 :(得分:7)

这实际上是关于尚未声明的函数的默认返回值。在您的第一个示例中,当编译器看到行c = check(10, 20);时,它还不知道此函数将返回什么。标准说编译器应该假设返回值是int。这就是这就是:int的大小可能与int *(指针)的大小不同。为了使编译器始终为此发出正确的机器代码,必须知道check返回一个指针,这就是它需要声明的原因。这就是第二个例子的作用:它告诉编译器“会有一个名为'check'的函数,它看起来像这样”

除此之外,这个例子非常糟糕。 check的参数被压入堆栈,然后函数返回指向这些堆栈位置的指针。但是在功能退出后,不能保证这些堆栈位置再次有效。这是未定义的行为,这意味着允许编译器做任何它喜欢的事情,甚至让你的计算机爆炸。这个具体的例子实际上应该工作,因为它只打印指针(即它所指向的地址),但它实际上并不是解除引用它(这是,从指针指向的地址)。在大多数机器/编译器上,即使解除引用也应该“正确”工作,但您可能不会依赖它。

答案 1 :(得分:2)

如果在第一次使用函数之前没有函数原型,编译器会假定函数返回int

因此编译器假设您要将int变量分配给int*intint*的大小可能会有所不同,具体取决于平台和编译器。

例如,对于无符号整数和指针,嵌入式系统具有相同的类型,因此在代码中,您将看到uint32_t

答案 2 :(得分:2)

你是对的,添加原型只会修复编译器警告/错误,但不会修复check函数将返回指向局部变量的指针的问题。

但是,在尝试取消引用返回的指针之前,它不是未定义的行为。打印出来就可以了。

答案 3 :(得分:1)

有两个问题。

  1. 返回局部变量的地址。

    此scnario称为http://en.wikipedia.org/wiki/Dangling_pointer。当Check()执行完成时,可以将为局部变量分配的内存分配给某个其他功能。所以访问该内存会导致不确定的结果。

  2. 需要向前宣布。默认情况下,返回类型将被视为int,但此处使用int*。因此,添加int * check(int, int);将解决Error message: Non portable pointer assignment in main

答案 4 :(得分:1)

我认为代码的主要“要点”是告诉您未声明的函数具有默认为int的返回类型。这是真的。

然而,代码存在缺陷,因为check函数返回指向局部变量的指针(参数ij,具体取决于i value),这是一个未定义的行为(幸运的是,指针永远不会被解引用)。

答案 5 :(得分:1)

您将返回在check()函数堆栈处分配的局部变量的地址。 当check()函数以函数堆栈结束时,你不能将地址返回给不再存在的变量!

您可以将代码更改为:

#include <stdio.h>
int * check(int* i, int* j);
int main()
{
    int *c;
    int n1,n2;
    n1=10;
    n2=20;
    c = check(&n1, &n2);
    printf("c = %p\n",c);
    return 0;
}

int * check(int* i, int* j)
{
    int *p, *q;
    p = i;
    q = j;
    if((*i) >= 45)
    {
        return p;
    }

    return q;

}

答案 6 :(得分:0)

您正在返回局部变量的地址。取消引用这些是C中的undefined行为。pq都是指向函数check()的局部变量的指针。在函数check()返回控制权之后main(),然后pq指向未定义的值。此外,请对您的代码进行以下更正:

printf("c = %p\n",(void*)c);
嘿卡特彼勒,我已经警告过你那本作者的书了,不是吗? : - )

编辑您在check()之前忘记了main()的函数声明。在我的编译器中它总是抛出警告信息。在main()函数之前添加以下内容:< / p>

int *check(int,int);