在“理解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一些内存区域。我是对的吗?
答案 0 :(得分:7)
这实际上是关于尚未声明的函数的默认返回值。在您的第一个示例中,当编译器看到行c = check(10, 20);
时,它还不知道此函数将返回什么。标准说编译器应该假设返回值是int
。这就是这就是:int
的大小可能与int *
(指针)的大小不同。为了使编译器始终为此发出正确的机器代码,必须知道check
返回一个指针,这就是它需要声明的原因。这就是第二个例子的作用:它告诉编译器“会有一个名为'check'的函数,它看起来像这样”。
除此之外,这个例子非常糟糕。 check
的参数被压入堆栈,然后函数返回指向这些堆栈位置的指针。但是在功能退出后,不能保证这些堆栈位置再次有效。这是未定义的行为,这意味着允许编译器做任何它喜欢的事情,甚至让你的计算机爆炸。这个具体的例子实际上应该工作,因为它只打印指针(即它所指向的地址),但它实际上并不是解除引用它(这是,从指针指向的地址)。在大多数机器/编译器上,即使解除引用也应该“正确”工作,但您可能不会依赖它。
答案 1 :(得分:2)
如果在第一次使用函数之前没有函数原型,编译器会假定函数返回int
。
因此编译器假设您要将int
变量分配给int*
。 int
和int*
的大小可能会有所不同,具体取决于平台和编译器。
例如,对于无符号整数和指针,嵌入式系统具有相同的类型,因此在代码中,您将看到uint32_t
。
答案 2 :(得分:2)
你是对的,添加原型只会修复编译器警告/错误,但不会修复check
函数将返回指向局部变量的指针的问题。
但是,在尝试取消引用返回的指针之前,它不是未定义的行为。打印出来就可以了。
答案 3 :(得分:1)
有两个问题。
返回局部变量的地址。
此scnario称为http://en.wikipedia.org/wiki/Dangling_pointer。当Check()
执行完成时,可以将为局部变量分配的内存分配给某个其他功能。所以访问该内存会导致不确定的结果。
需要向前宣布。默认情况下,返回类型将被视为int
,但此处使用int*
。因此,添加int * check(int, int);
将解决Error message: Non portable pointer assignment in main
。
答案 4 :(得分:1)
我认为代码的主要“要点”是告诉您未声明的函数具有默认为int
的返回类型。这是真的。
然而,代码存在缺陷,因为check
函数返回指向局部变量的指针(参数i
或j
,具体取决于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
行为。p
和q
都是指向函数check()
的局部变量的指针。在函数check()
返回控制权之后main()
,然后p
和q
指向未定义的值。此外,请对您的代码进行以下更正:
printf("c = %p\n",(void*)c);
嘿卡特彼勒,我已经警告过你那本作者的书了,不是吗? : - )
编辑您在check()
之前忘记了main()
的函数声明。在我的编译器中它总是抛出警告信息。在main()函数之前添加以下内容:< / p>
int *check(int,int);