C语言 C 中的指针:何时使用与号和星号?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2094666/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 04:11:26  来源:igfitidea点击:

Pointers in C: when to use the ampersand and the asterisk?

cpointers

提问by Pieter

I'm just starting out with pointers, and I'm slightly confused. I know &means the address of a variable and that *can be used in front of a pointer variable to get the value of the object that is pointed to by the pointer. But things work differently when you're working with arrays, strings or when you're calling functions with a pointer copy of a variable. It's difficult to see a pattern of logic inside all of this.

我刚开始使用指针,我有点困惑。我知道&意味着变量的地址,*可以在指针变量前面使用它来获取指针指向的对象的值。但是,当您使用数组、字符串或使用变量的指针副本调用函数时,事情会有所不同。很难看到所有这些中的逻辑模式。

When should I use &and *?

我什么时候应该使用&*

回答by Dan Olson

You have pointers and values:

你有指针和值:

int* p; // variable p is pointer to integer type
int i; // integer value

You turn a pointer into a value with *:

你把一个指针变成一个值*

int i2 = *p; // integer i2 is assigned with integer value that pointer p is pointing to

You turn a value into a pointer with &:

你把一个值变成一个指针&

int* p2 = &i; // pointer p2 will point to the address of integer i

Edit: In the case of arrays, they are treated very much like pointers. If you think of them as pointers, you'll be using *to get at the values inside of them as explained above, but there is also another, more common way using the []operator:

编辑:在数组的情况下,它们被视为非常像指针。如果您将它们视为指针,您将使用*如上所述获取它们内部的值,但还有另一种更常见的使用[]运算符的方法:

int a[2];  // array of integers
int i = *a; // the value of the first element of a
int i2 = a[0]; // another way to get the first element

To get the second element:

获取第二个元素:

int a[2]; // array
int i = *(a + 1); // the value of the second element
int i2 = a[1]; // the value of the second element

So the []indexing operator is a special form of the *operator, and it works like this:

所以[]索引运算符是运算符的一种特殊形式*,它的工作原理是这样的:

a[i] == *(a + i);  // these two statements are the same thing

回答by John Bode

There is a pattern when dealing with arrays and functions; it's just a little hard to see at first.

处理数组和函数时有一个模式;刚开始有点难看。

When dealing with arrays, it's useful to remember the following: when an array expression appears in most contexts, the type of the expression is implicitly converted from "N-element array of T" to "pointer to T", and its value is set to point to the first element in the array. The exceptions to this rule are when the array expression appears as an operand of either the &or sizeofoperators, or when it is a string literal being used as an initializer in a declaration.

在处理数组时,记住以下几点很有用:当数组表达式出现在大多数上下文中时,表达式的类型从“T的N元素数组”隐式转换为“指向T的指针”,并设置其值指向数组中的第一个元素。此规则的例外情况是当数组表达式作为 the&sizeof运算符的操作数出现时,或者当它是在声明中用作初始化器的字符串文字时。

Thus, when you call a function with an array expression as an argument, the function will receive a pointer, not an array:

因此,当您使用数组表达式作为参数调用函数时,该函数将接收一个指针,而不是数组:

int arr[10];
...
foo(arr);
...

void foo(int *arr) { ... }

This is why you don'tuse the &operator for arguments corresponding to "%s" in scanf():

这就是为什么&运算符用于对应于 "%s" in 的参数的原因scanf()

char str[STRING_LENGTH];
...
scanf("%s", str);

Because of the implicit conversion, scanf()receives a char *value that points to the beginning of the strarray. This holds true for any function called with an array expression as an argument (just about any of the str*functions, *scanfand *printffunctions, etc.).

由于隐式转换,scanf()接收一个char *指向str数组开头的值。这适用于使用数组表达式作为参数调用的任何函数(几乎任何str*函数*scanf*printf函数等)。

In practice, you will probably never call a function with an array expression using the &operator, as in:

实际上,您可能永远不会使用&运算符调用带有数组表达式的函数,如下所示:

int arr[N];
...
foo(&arr);

void foo(int (*p)[N]) {...}

Such code is not very common; you have to know the size of the array in the function declaration, and the function only works with pointers to arrays of specific sizes (a pointer to a 10-element array of T is a different type than a pointer to a 11-element array of T).

这样的代码不是很常见;您必须知道函数声明中数组的大小,并且该函数仅适用于指向特定大小数组的指针(指向 T 的 10 元素数组的指针与指向 11 元素数组的指针的类型不同)的)。

When an array expression appears as an operand to the &operator, the type of the resulting expression is "pointer to N-element array of T", or T (*)[N], which is different from an array of pointers (T *[N]) and a pointer to the base type (T *).

当数组表达式作为操作数出现给&运算符时,结果表达式的类型是“指向 T 的 N 元素数组的指针”,或T (*)[N],它不同于指针数组 ( T *[N]) 和指向基类型的指针 ( T *)。

When dealing with functions and pointers, the rule to remember is: if you want to change the value of an argument and have it reflected in the calling code, you must pass a pointer to the thing you want to modify. Again, arrays throw a bit of a monkey wrench into the works, but we'll deal with the normal cases first.

在处理函数和指针时,要记住的规则是:如果要更改参数的值并使其反映在调用代码中,则必须将指针传递给要修改的内容。同样,数组在工作中有点麻烦,但我们将首先处理正常情况。

Remember that C passes allfunction arguments by value; the formal parameter receives a copy of the value in the actual parameter, and any changes to the formal parameter are not reflected in the actual parameter. The common example is a swap function:

请记住,C按值传递所有函数参数;形参接收实参中值的副本,形参的任何变化都不会反映在实参中。常见的例子是一个交换函数:

void swap(int x, int y) { int tmp = x; x = y; y = tmp; }
...
int a = 1, b = 2;
printf("before swap: a = %d, b = %d\n", a, b);
swap(a, b);
printf("after swap: a = %d, b = %d\n", a, b);

You'll get the following output:

您将获得以下输出:

before swap: a = 1, b = 2
after swap: a = 1, b = 2

The formal parameters xand yare distinct objects from aand b, so changes to xand yare not reflected in aand b. Since we want to modify the values of aand b, we must pass pointersto them to the swap function:

形式参数xy从不同的对象ab,所以要改变xy未在反射ab。由于我们要修改aand的值b,我们必须将指向它们的指针传递给 swap 函数:

void swap(int *x, int *y) {int tmp = *x; *x = *y; *y = tmp; }
...
int a = 1, b = 2;
printf("before swap: a = %d, b = %d\n", a, b);
swap(&a, &b);
printf("after swap: a = %d, b = %d\n", a, b);

Now your output will be

现在你的输出将是

before swap: a = 1, b = 2
after swap: a = 2, b = 1

Note that, in the swap function, we don't change the values of xand y, but the values of what xand ypoint to. Writing to *xis different from writing to x; we're not updating the value in xitself, we get a location from xand update the value in that location.

请注意,在交换函数中,我们不会更改xandy的值,而是更改whatxy指向的值。写入*x与写入不同x;我们不会更新值x本身,而是从该位置获取位置x并更新该位置中的值。

This is equally true if we want to modify a pointer value; if we write

如果我们想修改一个指针值,这同样适用;如果我们写

int myFopen(FILE *stream) {stream = fopen("myfile.dat", "r"); }
...
FILE *in;
myFopen(in);

then we're modifying the value of the input parameter stream, not what streampoints to, so changing streamhas no effect on the value of in; in order for this to work, we must pass in a pointer to the pointer:

那么我们正在修改输入参数的值stream,而不是stream指向stream的值,因此更改对 的值没有影响in;为了使其工作,我们必须传入一个指向该指针的指针:

int myFopen(FILE **stream) {*stream = fopen("myFile.dat", "r"); }
...
FILE *in;
myFopen(&in);

Again, arrays throw a bit of a monkey wrench into the works. When you pass an array expression to a function, what the function receives is a pointer. Because of how array subscripting is defined, you can use a subscript operator on a pointer the same way you can use it on an array:

再一次,数组给工作带来了一些麻烦。当您将数组表达式传递给函数时,该函数接收的是一个指针。由于数组下标的定义方式,您可以在指针上使用下标运算符,就像在数组上使用它一样:

int arr[N];
init(arr, N);
...
void init(int *arr, int N) {size_t i; for (i = 0; i < N; i++) arr[i] = i*i;}

Note that array objects may not be assigned; i.e., you can't do something like

请注意,可能不会分配数组对象;即,你不能做类似的事情

int a[10], b[10];
...
a = b;

so you want to be careful when you're dealing with pointers to arrays; something like

所以在处理指向数组的指针时要小心;就像是

void (int (*foo)[N])
{
  ...
  *foo = ...;
}

won't work.

不会工作。

回答by t0mm13b

Put simply

简单地说

  • &means the address-of, you will see that in placeholders for functions to modify the parameter variable as in C, parameter variables are passed by value, using the ampersand means to pass by reference.
  • *means the dereferenceof a pointer variable, meaning to get the value of that pointer variable.
  • &表示address-of,您将看到在用于修改参数变量的函数的占位符中,如在 C 中一样,参数变量是按值传递的,使用和号表示按引用传递。
  • *意味着取消对指针变量的引用,即获取该指针变量的值。
int foo(int *x){
   *x++;
}

int main(int argc, char **argv){
   int y = 5;
   foo(&y);  // Now y is incremented and in scope here
   printf("value of y = %d\n", y); // output is 6
   /* ... */
}

The above example illustrates how to call a function fooby using pass-by-reference, compare with this

上面的例子说明了如何foo使用pass-by-reference来调用一个函数,与这个比较

int foo(int x){
   x++;
}

int main(int argc, char **argv){
   int y = 5;
   foo(y);  // Now y is still 5
   printf("value of y = %d\n", y); // output is 5
   /* ... */
}

Here's an illustration of using a dereference

这是使用取消引用的说明

int main(int argc, char **argv){
   int y = 5;
   int *p = NULL;
   p = &y;
   printf("value of *p = %d\n", *p); // output is 5
}

The above illustrates how we got the address-ofyand assigned it to the pointer variable p. Then we dereferencepby attaching the *to the front of it to obtain the value of p, i.e. *p.

上面说明了我们如何获得address-ofy并将其分配给指针变量p。然后我们通过将 附加到它的前面来取消引用以获得 的值,即。p*p*p

回答by smerlin

Yeah that can be quite complicated since the *is used for many different purposes in C/C++.

是的,这可能非常复杂,因为它*在 C/C++ 中用于许多不同的目的。

If *appears in front of an already declared variable/function, it means either that:

如果*出现在已声明的变量/函数之前,则表示:

  • a) *gives access to the value of that variable (if the type of that variable is a pointer type, or overloaded the *operator).
  • b) *has the meaning of the multiply operator, in that case, there has to be another variable to the left of the *
  • a)*允许访问该变量的值(如果该变量的类型是指针类型,或者*运算符重载)。
  • b)*具有乘法运算符的含义,在这种情况下,必须在左侧有另一个变量*

If *appears in a variable or function declaration it means that that variable is a pointer:

如果*出现在变量或函数声明中,则表示该变量是一个指针:

int int_value = 1;
int * int_ptr; //can point to another int variable
int   int_array1[10]; //can contain up to 10 int values, basically int_array1 is an pointer as well which points to the first int of the array
//int   int_array2[]; //illegal, without initializer list..
int int_array3[] = {1,2,3,4,5};  // these two
int int_array4[5] = {1,2,3,4,5}; // are identical

void func_takes_int_ptr1(int *int_ptr){} // these two are identical
void func_takes int_ptr2(int int_ptr[]){}// and legal

If &appears in a variable or function declaration, it generally means that that variable is a reference to a variable of that type.

如果&出现在变量或函数声明中,通常意味着该变量是对该类型变量的引用。

If &appears in front of an already declared variable, it returns the address of that variable

如果&出现在已声明的变量前面,则返回该变量的地址

Additionally you should know, that when passing an array to a function, you will always have to pass the array size of that array as well, except when the array is something like a 0-terminated cstring (char array).

此外,您应该知道,将数组传递给函数时,您始终必须传递该数组的数组大小,除非该数组类似于以 0 结尾的 cstring(字符数组)。

回答by smerlin

I was looking through all the wordy explanations so instead turned to a video from University of New South Wales for rescue.Here is the simple explanation: if we have a cell that has address xand value 7, the indirect way to ask for address of value 7is &7and the indirect way to ask for value at address xis *x.So (cell: x , value: 7) == (cell: &7 , value: *x).Another way to look into it: Johnsits at 7th seat.The *7th seatwill point to Johnand &Johnwill give address/location of the 7th seat. This simple explanation helped me and hope it will help others as well. Here is the link for the excellent video: click here.

我正在浏览所有冗长的解释,所以转而使用新南威尔士大学的视频进行救援。这是一个简单的解释:如果我们有一个具有地址x和值的单元格7,则间接请求值地址的方法7&7并且在地址处请求值的间接方法x*x.So 。(cell: x , value: 7) == (cell: &7 , value: *x)另一种查看它的方法:John坐在7th seat.The *7th seatwill 指向John&John给出 . 的address/location 7th seat。这个简单的解释帮助了我,希望它也能帮助其他人。这是优秀视频的链接:单击此处。

Here is another example:

这是另一个例子:

#include <stdio.h>

int main()
{ 
    int x;            /* A normal integer*/
    int *p;           /* A pointer to an integer ("*p" is an integer, so p
                       must be a pointer to an integer) */

    p = &x;           /* Read it, "assign the address of x to p" */
    scanf( "%d", &x );          /* Put a value in x, we could also use p here */
    printf( "%d\n", *p ); /* Note the use of the * to get the value */
    getchar();
}

Add-on:Always initialize pointer before using them.If not, the pointer will point to anything, which might result in crashing the program because the operating system will prevent you from accessing the memory it knows you don't own.But simply putting p = &x;, we are assigning the pointer a specific location.

附加:在使用它们之前总是初始化指针。如果没有,指针将指向任何东西,这可能会导致程序崩溃,因为操作系统会阻止你访问它知道你不拥有的内存。但简单地把 p = &x;,我们正在为指针分配一个特定的位置。

回答by Jay Conrod

When you are declaring a pointer variable or function parameter, use the *:

声明指针变量或函数参数时,请使用 *:

int *x = NULL;
int *y = malloc(sizeof(int)), *z = NULL;
int* f(int *x) {
    ...
}

NB: each declared variable needs its own *.

注意:每个声明的变量都需要自己的 *.

When you want to take the address of a value, use &. When you want to read or write the value in a pointer, use *.

当您想要获取值的地址时,请使用 &。当您想读取或写入指针中的值时,请使用 *。

int a;
int *b;
b = f(&a);
a = *b;

a = *f(&a);

Arrays are usually just treated like pointers. When you declare an array parameter in a function, you can just as easily declare it is a pointer (it means the same thing). When you pass an array to a function, you are actually passing a pointer to the first element.

数组通常被视为指针。当你在函数中声明一个数组参数时,你可以很容易地声明它是一个指针(这意味着同样的事情)。当您将数组传递给函数时,您实际上是在传递指向第一个元素的指针。

Function pointers are the only things that don't quite follow the rules. You can take the address of a function without using &, and you can call a function pointer without using *.

函数指针是唯一不完全遵循规则的东西。不用&就可以取函数的地址,不用*就可以调用函数指针。

回答by paxdiablo

Actually, you have it down pat, there's nothing more you need to know :-)

事实上,你已经知道了,没有什么需要知道的:-)

I would just add the following bits:

我只想添加以下位:

  • the two operations are opposite ends of the spectrum. &takes a variable and gives you the address, *takes an address and gives you the variable (or contents).
  • arrays "degrade" to pointers when you pass them to functions.
  • you can actually have multiple levels on indirection (char **pmeans that pis a pointer to a pointer to a char.
  • 这两个操作是频谱的两端。&获取一个变量并为您提供地址,*获取一个地址并为您提供变量(或内容)。
  • 当您将数组传递给函数时,数组会“降级”为指针。
  • 您实际上可以在间接上有多个级别(char **p意味着这p是一个指向char.

As to things working differently, not really:

至于工作方式不同的事情,并不是真的:

  • arrays, as already mentioned, degrade to pointers (to the first element in the array) when passed to functions; they don't preserve size information.
  • there are no strings in C, just character arrays that, by convention, represent a string of characters terminated by a zero (\0) character.
  • When you pass the address of a variable to a function, you can de-reference the pointer to change the variable itself (normally variables are passed by value (except for arrays)).
  • 如前所述,数组在传递给函数时会降级为指针(指向数组中的第一个元素);它们不保留大小信息。
  • C 中没有字符串,只有字符数组,按照惯例,它们表示以零 ( \0) 字符结尾的字符串。
  • 当您将变量的地址传递给函数时,您可以取消引用指针以更改变量本身(通常变量是按值传递的(数​​组除外))。

回答by Prasoon Saurav

I think you are a bit confused. You should read a good tutorial/book on pointers.

我觉得你有点困惑。你应该阅读一本关于指针的好教程/书。

Thistutorial is very good for starters(clearly explains what &and *are). And yeah don't forget to read the book Pointers in Cby Kenneth Reek.

教程非常适合初学者(清楚地解释了什么&*是什么)。是的,别忘了阅读Kenneth Reek所著的Pointers in C一书。

The difference between &and *is very clear.

&和之间的区别*非常明显。

Example:

例子:

#include <stdio.h>

int main(){
  int x, *p;

  p = &x;         /* initialise pointer(take the address of x) */
  *p = 0;         /* set x to zero */
  printf("x is %d\n", x);
  printf("*p is %d\n", *p);

  *p += 1;        /* increment what p points to i.e x */
  printf("x is %d\n", x);

  (*p)++;         /* increment what p points to i.e x */
  printf("x is %d\n", x);

  return 0;
}

回答by wheaties

Ok, looks like your post got editted...

好的,看来你的帖子被编辑了......

double foo[4];
double *bar_1 = &foo[0];

See how you can use the &to get the address of the beginning of the array structure? The following

看看如何使用&来获取数组结构的开头地址?下列

Foo_1(double *bar, int size){ return bar[size-1]; }
Foo_2(double bar[], int size){ return bar[size-1]; }

will do the same thing.

会做同样的事情。