指针是否被认为是 C 中通过引用调用的方法?
Are pointers considered a method of calling by reference in C?
在我大学的 C 编程 class 中,她所写的教授和随后的书在引用 时使用术语 call or pass by reference C 中的指针
我的教授认为 'call by reference function' 的示例:
int sum(int *a, int *b);
我的教授认为 'call by value function' 的示例:
int sum(int a, int b);
我 read C 不支持引用调用。据我了解,指针按值传递。
基本上,不正确说指针是 C 的引用传递方式吗?如果说你不能在 C 中通过引用传递但可以使用指针作为替代方法,更正确吗?
2015 年 11 月 11 日更新
从我提出问题的方式来看,我相信术语的争论已经结束,事实上我看到了两个具体的区别。
- pass-by-reference(今天主要使用的术语):specific 术语在 C++
等语言中使用
- pass-by-reference(我的教授使用的术语作为解释指针的范例):general 在 C++ 等语言开发之前使用的术语,因此在术语之前被重写
阅读@Haris 更新后的答案后,我明白了为什么这不是那么黑白分明。
你不能在 C 中通过引用传递,但可以使用指针作为替代方法
是的,没错。
再详细一点。无论您将什么作为参数传递给 c 函数,它都仅按值传递。无论是变量值还是变量地址。
不同之处在于您发送的内容。
当我们按值传递时,我们将变量的值传递给函数。当我们通过引用传递时,我们将变量的别名传递给函数。 C 可以将指针传递给函数,但这仍然是按值传递。它是将指针的值,即地址,复制到函数中。
如果您要发送一个变量的值,那么函数只会接收该值,更改不会影响原始值。
如果你发送一个变量的地址,那么也只发送值(在这种情况下是地址),但是因为你有一个变量的地址,它可以用来改变原始值。
作为示例,我们可以查看一些 C++ 代码来理解按值调用和按引用调用之间的真正区别。摘自 this 网站。
// Program to sort two numbers using call by reference.
// Smallest number is output first.
#include <iostream>
using namespace std;
// Function prototype for call by reference
void swap(float &x, float &y);
int main()
{
float a, b;
cout << "Enter 2 numbers: " << endl;
cin >> a >> b;
if(a>b)
swap(a,b); // This looks just like a call-by-value, but in fact
// it's a call by reference (because of the "&" in the
// function prototype
// Variable a contains value of smallest number
cout << "Sorted numbers: ";
cout << a << " " << b << endl;
return 0;
}
// A function definition for call by reference
// The variables x and y will have their values changed.
void swap(float &x, float &y)
// Swaps x and y data of calling function
{
float temp;
temp = x;
x = y;
y = temp;
}
在此 C++ 示例中,使用了 参考变量(C 中不存在)。引用 this 网站,
"A reference is an alias, or an alternate name to an existing variable...",
和
"The main use of references is acting as function formal parameters to support pass-by-reference..."
这与使用指针作为函数参数不同,因为,
"A pointer variable (or pointer in short) is basically the same as the other variables, which can store a piece of data. Unlike normal variable which stores a value (such as an int, a double, a char), a pointer stores a memory address."
所以,基本上当一个人通过指针发送地址和接收时,一个人只发送值,但是当一个人是 sending/receiving 一个引用变量时,一个人发送一个别名,或者一个参考。
**更新:2015 年 11 月 11 日**
在C Chatroom中争论了很长时间,在阅读了这个问题的评论和答案之后,我意识到可以有另一种方式来看待这个问题,即另一种观点。
让我们看一些简单的 C 代码
int i;
int *p = &i;
*p = 123;
在这种情况下,可以使用术语,p 的值是对 i 的引用。所以,如果是这样的话,那么如果我们将相同的指针 (int* p
) 发送到一个函数,有人会争辩说,因为 i
的引用被发送到函数,因此这可以被称为 参考传递.
所以,这是一个术语和看待场景的方式的问题。
我不会完全不同意这个论点。但是对于一个完全照章办事的人来说,这是错误的。
注意: 更新灵感来自 this 聊天。
来自 C99 标准(强调我的):
6.2.5 Types
20 Any number of derived types can be constructed from the object and function types, as
follows:
...
— A pointer type may be derived from a function type or an object type, called the referenced type. A pointer type describes an object whose value provides a reference to an entity of the referenced type. A pointer type derived from the referenced type T is sometimes called ‘‘pointer to T’’. The construction of a pointer type from a referenced type is called ‘‘pointer type derivation’’. A pointer type is a complete object type.
综合以上,你教授说的有道理,是正确的。
指针按值传递给函数。如果指针指向一个有效的实体,它的值提供对一个实体的引用。
引用在这里是一个重载的术语;通常,引用只是引用某物的一种方式。指针指的是指向的对象,传递(按值)指向对象的指针是 C 中按引用传递的标准方式。
C++ 引入了引用类型作为表示引用的更好方式,并在技术英语中引入了歧义,因为我们现在可以使用术语 "pass by reference" 来指代使用引用类型通过引用传递对象。
在 C++ 上下文中,IMO 已弃用前一种用法。但是,我相信前一种用法在没有歧义的其他上下文(例如纯 C)中很常见。
你的教授是对的。
按值,它被复制。
参考一下,没抄,参考说在哪
通过值,您将一个 int 传递给一个函数,它被复制,对副本的更改不会影响原始。
通过引用,传递与指针相同的 int,它不是复制的,您正在修改原始文件。
通过引用,数组总是通过引用,你的数组中可能有十亿个项目,只说它在哪里会更快,你正在修改原始数据。
Does C even have ``pass by reference''?
Not really.
Strictly speaking, C always uses pass by value. You can simulate pass by reference yourself, by defining functions which accept pointers and then using the &
operator when calling, and the compiler will essentially simulate it for you when you pass an array to a function (by passing a pointer instead, see question 6.4 et al.).
Another way of looking at it is that if an parameter has type, say, int *
then an integer is being passed by reference and a pointer to an integer is being passed by value.
Fundamentally, C has nothing truly equivalent to formal pass by reference or c++ reference parameters.
为了证明指针是按值传递的,让我们考虑一个使用指针交换数字的例子。
int main(void)
{
int num1 = 5;
int num2 = 10;
int *pnum1 = &num1;
int *pnum2 = &num2;
int ptemp;
printf("Before swap, *Pnum1 = %d and *pnum2 = %d\n", *pnum1, *pnum2);
temp = pnum1;
pnum1 = pnum2;
pnum2 = ptemp;
printf("After swap, *Pnum1 = %d and *pnum2 = %d\n", *pnum1, *pnum2);
}
不是交换数字,而是交换指针。现在为相同的
创建一个函数
void swap(int *pnum1, int *pnum2)
{
int *ptemp = pnum1;
pnum1 = pnum2;
pnum2 = temp;
}
int main(void)
{
int num1 = 5;
int num2 = 10;
int *pnum1 = &num1;
int *pnum2 = &num2;
printf("Before swap, *pnum1 = %d and *pnum2 = %d\n", *pnum1, *pnum2);
swap(pnum1, pnum2);
printf("After swap, *pnum1 = %d and *pnum2 = %d\n", *pnum1, *pnum2);
}
轰!没有交换!
一些tutorials mention pointer reference as call by reference which is misleading. See the this answer for the difference between passing by reference and passing by value。
C 按值、句点传递参数。但是,指针是一种机制,可用于有效 通过引用传递参数。就像一枚硬币可以 有效地 用作螺丝刀一样,如果你有合适的螺丝类型:一些螺丝槽甚至被选择为可以很好地与硬币一起使用。他们仍然没有把硬币变成真正的螺丝刀。
C++ 仍然按值传递参数。 C++ 引用比指针更受限制(尽管有更多的隐式转换)并且不能成为数据结构的一部分,并且它们的使用看起来更像通常的引用调用代码,但是它们的语义非常迎合为了满足按引用调用参数的需要,仍然比纯按引用调用实现(如 Fortran 参数或 Pascal var
参数)更切实,并且您可以在函数调用上下文之外很好地使用引用。
在支持按引用传递的语言中,存在一种方法,通过该方法可以为函数提供一些东西,这些东西可用于标识调用者知道的变量,直到被调用的函数 returns,但只能存储在之后不存在的地方。因此,调用者可以知道,由于将某个函数传递给它的引用而将对变量执行的任何操作都将在函数 returns.
时完成。
比较 C 和 C# 程序:
// C // C#
int x=0; int x=0;
foo(&x); foo(ref x);
x++; x++;
bar(); bar();
x++; x++;
boz(x); boz(x);
C 编译器无法知道 "bar" 是否会改变 x,因为
foo() 收到一个不受限制的指向它的指针。相比之下,C# 编译器
知道 bar() 不可能改变 x,因为 foo() 只接收一个
对它的临时引用(在 .NET 术语中称为 "byref")
该 byref 的任何副本都无法在 foo()
returns.
传递指向事物的指针允许代码做可以用 pass-by-ref 语义完成的相同事情,但是 pass-by-ref 语义使代码成为可能为它不会做的事情提供更有力的保证。
"Passing by reference"是一个概念。是的,您正在将指针的值传递给函数,但在那个实例中,该指针的值被用于引用变量。
有人用螺丝刀类比来解释,将指针的传递称为引用传递是错误的,说你可以用硬币拧螺丝,但这并不意味着你会调用硬币螺丝刀。我会说这是一个很好的类比,但他们得出了错误的结论。事实上,虽然你不会说硬币是螺丝刀,但你仍然会说你用它拧紧了螺丝。即,即使指针与 C++ 引用不同,您使用它们所做的事情 IS 通过引用传递。
在我大学的 C 编程 class 中,她所写的教授和随后的书在引用 时使用术语 call or pass by reference C 中的指针
我的教授认为 'call by reference function' 的示例:
int sum(int *a, int *b);
我的教授认为 'call by value function' 的示例:
int sum(int a, int b);
我 read C 不支持引用调用。据我了解,指针按值传递。
基本上,不正确说指针是 C 的引用传递方式吗?如果说你不能在 C 中通过引用传递但可以使用指针作为替代方法,更正确吗?
2015 年 11 月 11 日更新
从我提出问题的方式来看,我相信术语的争论已经结束,事实上我看到了两个具体的区别。
- pass-by-reference(今天主要使用的术语):specific 术语在 C++ 等语言中使用
- pass-by-reference(我的教授使用的术语作为解释指针的范例):general 在 C++ 等语言开发之前使用的术语,因此在术语之前被重写
阅读@Haris 更新后的答案后,我明白了为什么这不是那么黑白分明。
你不能在 C 中通过引用传递,但可以使用指针作为替代方法
是的,没错。
再详细一点。无论您将什么作为参数传递给 c 函数,它都仅按值传递。无论是变量值还是变量地址。
不同之处在于您发送的内容。
当我们按值传递时,我们将变量的值传递给函数。当我们通过引用传递时,我们将变量的别名传递给函数。 C 可以将指针传递给函数,但这仍然是按值传递。它是将指针的值,即地址,复制到函数中。
如果您要发送一个变量的值,那么函数只会接收该值,更改不会影响原始值。
如果你发送一个变量的地址,那么也只发送值(在这种情况下是地址),但是因为你有一个变量的地址,它可以用来改变原始值。
作为示例,我们可以查看一些 C++ 代码来理解按值调用和按引用调用之间的真正区别。摘自 this 网站。
// Program to sort two numbers using call by reference.
// Smallest number is output first.
#include <iostream>
using namespace std;
// Function prototype for call by reference
void swap(float &x, float &y);
int main()
{
float a, b;
cout << "Enter 2 numbers: " << endl;
cin >> a >> b;
if(a>b)
swap(a,b); // This looks just like a call-by-value, but in fact
// it's a call by reference (because of the "&" in the
// function prototype
// Variable a contains value of smallest number
cout << "Sorted numbers: ";
cout << a << " " << b << endl;
return 0;
}
// A function definition for call by reference
// The variables x and y will have their values changed.
void swap(float &x, float &y)
// Swaps x and y data of calling function
{
float temp;
temp = x;
x = y;
y = temp;
}
在此 C++ 示例中,使用了 参考变量(C 中不存在)。引用 this 网站,
"A reference is an alias, or an alternate name to an existing variable...",
和
"The main use of references is acting as function formal parameters to support pass-by-reference..."
这与使用指针作为函数参数不同,因为,
"A pointer variable (or pointer in short) is basically the same as the other variables, which can store a piece of data. Unlike normal variable which stores a value (such as an int, a double, a char), a pointer stores a memory address."
所以,基本上当一个人通过指针发送地址和接收时,一个人只发送值,但是当一个人是 sending/receiving 一个引用变量时,一个人发送一个别名,或者一个参考。
**更新:2015 年 11 月 11 日**
在C Chatroom中争论了很长时间,在阅读了这个问题的评论和答案之后,我意识到可以有另一种方式来看待这个问题,即另一种观点。
让我们看一些简单的 C 代码
int i;
int *p = &i;
*p = 123;
在这种情况下,可以使用术语,p 的值是对 i 的引用。所以,如果是这样的话,那么如果我们将相同的指针 (int* p
) 发送到一个函数,有人会争辩说,因为 i
的引用被发送到函数,因此这可以被称为 参考传递.
所以,这是一个术语和看待场景的方式的问题。
我不会完全不同意这个论点。但是对于一个完全照章办事的人来说,这是错误的。
注意: 更新灵感来自 this 聊天。
来自 C99 标准(强调我的):
6.2.5 Types
20 Any number of derived types can be constructed from the object and function types, as follows:
...
— A pointer type may be derived from a function type or an object type, called the referenced type. A pointer type describes an object whose value provides a reference to an entity of the referenced type. A pointer type derived from the referenced type T is sometimes called ‘‘pointer to T’’. The construction of a pointer type from a referenced type is called ‘‘pointer type derivation’’. A pointer type is a complete object type.
综合以上,你教授说的有道理,是正确的。 指针按值传递给函数。如果指针指向一个有效的实体,它的值提供对一个实体的引用。
引用在这里是一个重载的术语;通常,引用只是引用某物的一种方式。指针指的是指向的对象,传递(按值)指向对象的指针是 C 中按引用传递的标准方式。
C++ 引入了引用类型作为表示引用的更好方式,并在技术英语中引入了歧义,因为我们现在可以使用术语 "pass by reference" 来指代使用引用类型通过引用传递对象。
在 C++ 上下文中,IMO 已弃用前一种用法。但是,我相信前一种用法在没有歧义的其他上下文(例如纯 C)中很常见。
你的教授是对的。 按值,它被复制。 参考一下,没抄,参考说在哪
通过值,您将一个 int 传递给一个函数,它被复制,对副本的更改不会影响原始。
通过引用,传递与指针相同的 int,它不是复制的,您正在修改原始文件。
通过引用,数组总是通过引用,你的数组中可能有十亿个项目,只说它在哪里会更快,你正在修改原始数据。
Does C even have ``pass by reference''?
Not really.
Strictly speaking, C always uses pass by value. You can simulate pass by reference yourself, by defining functions which accept pointers and then using the
&
operator when calling, and the compiler will essentially simulate it for you when you pass an array to a function (by passing a pointer instead, see question 6.4 et al.).Another way of looking at it is that if an parameter has type, say,
int *
then an integer is being passed by reference and a pointer to an integer is being passed by value.Fundamentally, C has nothing truly equivalent to formal pass by reference or c++ reference parameters.
为了证明指针是按值传递的,让我们考虑一个使用指针交换数字的例子。
int main(void)
{
int num1 = 5;
int num2 = 10;
int *pnum1 = &num1;
int *pnum2 = &num2;
int ptemp;
printf("Before swap, *Pnum1 = %d and *pnum2 = %d\n", *pnum1, *pnum2);
temp = pnum1;
pnum1 = pnum2;
pnum2 = ptemp;
printf("After swap, *Pnum1 = %d and *pnum2 = %d\n", *pnum1, *pnum2);
}
不是交换数字,而是交换指针。现在为相同的
创建一个函数void swap(int *pnum1, int *pnum2)
{
int *ptemp = pnum1;
pnum1 = pnum2;
pnum2 = temp;
}
int main(void)
{
int num1 = 5;
int num2 = 10;
int *pnum1 = &num1;
int *pnum2 = &num2;
printf("Before swap, *pnum1 = %d and *pnum2 = %d\n", *pnum1, *pnum2);
swap(pnum1, pnum2);
printf("After swap, *pnum1 = %d and *pnum2 = %d\n", *pnum1, *pnum2);
}
轰!没有交换!
一些tutorials mention pointer reference as call by reference which is misleading. See the this answer for the difference between passing by reference and passing by value。
C 按值、句点传递参数。但是,指针是一种机制,可用于有效 通过引用传递参数。就像一枚硬币可以 有效地 用作螺丝刀一样,如果你有合适的螺丝类型:一些螺丝槽甚至被选择为可以很好地与硬币一起使用。他们仍然没有把硬币变成真正的螺丝刀。
C++ 仍然按值传递参数。 C++ 引用比指针更受限制(尽管有更多的隐式转换)并且不能成为数据结构的一部分,并且它们的使用看起来更像通常的引用调用代码,但是它们的语义非常迎合为了满足按引用调用参数的需要,仍然比纯按引用调用实现(如 Fortran 参数或 Pascal var
参数)更切实,并且您可以在函数调用上下文之外很好地使用引用。
在支持按引用传递的语言中,存在一种方法,通过该方法可以为函数提供一些东西,这些东西可用于标识调用者知道的变量,直到被调用的函数 returns,但只能存储在之后不存在的地方。因此,调用者可以知道,由于将某个函数传递给它的引用而将对变量执行的任何操作都将在函数 returns.
时完成。比较 C 和 C# 程序:
// C // C#
int x=0; int x=0;
foo(&x); foo(ref x);
x++; x++;
bar(); bar();
x++; x++;
boz(x); boz(x);
C 编译器无法知道 "bar" 是否会改变 x,因为 foo() 收到一个不受限制的指向它的指针。相比之下,C# 编译器 知道 bar() 不可能改变 x,因为 foo() 只接收一个 对它的临时引用(在 .NET 术语中称为 "byref") 该 byref 的任何副本都无法在 foo() returns.
传递指向事物的指针允许代码做可以用 pass-by-ref 语义完成的相同事情,但是 pass-by-ref 语义使代码成为可能为它不会做的事情提供更有力的保证。
"Passing by reference"是一个概念。是的,您正在将指针的值传递给函数,但在那个实例中,该指针的值被用于引用变量。
有人用螺丝刀类比来解释,将指针的传递称为引用传递是错误的,说你可以用硬币拧螺丝,但这并不意味着你会调用硬币螺丝刀。我会说这是一个很好的类比,但他们得出了错误的结论。事实上,虽然你不会说硬币是螺丝刀,但你仍然会说你用它拧紧了螺丝。即,即使指针与 C++ 引用不同,您使用它们所做的事情 IS 通过引用传递。