C中的指针:何时使用&符号和星号?

我刚刚开始用指针,我有点困惑。 我知道&意味着一个variables的地址,这个*可以在一个指针variables的前面被用来获得指针指向的对象的值。 但是当你使用数组,string或者当你用一个variables的指针副本调用函数时,事情会有不同的工作。 在这个内部很难看到一种逻辑模式。

我应该什么时候使用&*

你有指针和值:

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

您将指针转换为具有*的值:

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

您将值转换为带有&的指针:

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

编辑:在数组的情况下,他们非常像指针。 如果你把它们看作是指针,那么你将会使用*来获得上面的值,但是使用[]运算符还有另一种更常用的方法:

 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 

要获得第二个元素:

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

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

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

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

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

因此,当你用一个数组expression式作为参数来调用函数时,函数将会收到一个指针,而不是一个数组:

 int arr[10]; ... foo(arr); ... void foo(int *arr) { ... } 

这就是为什么在scanf() 不要使用&运算符对应于“%s”的参数:

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

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

在实践中,你可能永远不会用数组expression式来使用&运算符来调用一个函数,如下所示:

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

这样的代码不是很常见, 你必须知道函数声明中数组的大小,函数只能用于指向特定大小数组的指针(指向10个元素的T数组的指针与指向11个元素数组的指针是不同的types的T)。

当数组expression式作为&操作数出现时,结果expression式的types是“指向T的N元素数组的指针”,或者T (*)[N] ,它与指针数组( T *[N] )和一个指向基types( T * )的指针。

处理函数和指针时,要记住的规则是:如果要更改参数的值并将其反映到调用代码中,则必须将指针传递给要修改的对象。 再次,arrays会把一些猴子的扳手扔进作品里,但是我们会首先处理正常情况。

请记住,C通过值传递所有的函数参数; forms参数接收实际参数中的值的副本,并且forms参数的任何更改都不会反映在实际参数中。 常见的例子是交换function:

 void swap(int x, int y) { int tmp = x; x = y; y = x; } ... 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); 

你会得到以下输出:

交换前:a = 1,b = 2
交换后:a = 1,b = 2

forms参数xyab中不同的对象,所以对xy更改不会反映在ab 。 既然我们要修改ab的值,我们必须把指针传给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); 

现在你的输出将是

交换前:a = 1,b = 2
交换后:a = 2,b = 1

请注意,在交换函数中,我们不会更改xy的值,而是更改xy 指向的值。 写入*x与写入x不同; 我们不更新x本身的值,我们从x得到一个位置并更新那个位置的值。

如果我们想修改一个指针值,这也是一样的。 如果我们写

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

那么我们正在修改input参数stream的值,而不是什么stream 指向 ,所以改变streamin的值没有影响; 为了这个工作,我们必须传递一个指向指针的指针:

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

再次,arrays把一些猴子扳手投入作品。 当你将一个数组expression式传递给一个函数时,函数收到的是一个指针。 由于如何定义数组下标,因此可以像使用数组一样在指针上使用下标运算符:

 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;} 

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

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

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

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

将无法工作。

简单地说

  • &表示的地址 ,你会看到,在函数的占位符修改参数variables在C中,参数variables传递的值,使用&符号意味着通过引用传递。
  • *表示取消引用一个指针variables,意思是获取该指针variables的值。
 int foo(int * x){
    * X ++;
 }

 int main(int argc,char ** argv){
    int y = 5;
    FOO(Y);  //现在y递增,范围在这里
    printf(“y的值=%d \ n”,y);  //输出是6
    / * ... * /
 }

上面的例子说明了如何通过使用传递引用来调用函数foo ,与此相比较

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

 int main(int argc,char ** argv){
    int y = 5;
    FOO(Y);  //现在y仍然是5
    printf(“y的值=%d \ n”,y);  //输出是5
    / * ... * /
 }

这是一个使用解除引用的例子

 int main(int argc,char ** argv){
    int y = 5;
    int * p = NULL;
    p =&y;
    printf(“value of * p =%d \ n”,* p);  //输出是5
 }

上面说明了我们如何获得y地址并将其分配给指针variablesp 。 然后我们通过将*附加到它的前面来解引用 p来获得p的值,即*p

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

如果*出现在已经声明的variables/函数之前,则意味着:

  • a) *可以访问该variables的值(如果该variables的types是指针types,或者重载了*运算符)。
  • b) *具有乘法运算符的含义,在这种情况下, *的左边必须有另一个variables,

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

 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 aswell 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 indentical void func_takes_int_ptr1(int *int_ptr){} // these two are indentical void func_takes int_ptr2(int int_ptr[]){}// and legal 

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

如果&出现在已经声明的variables的前面,它将返回该variables的地址

另外你应该知道,当把一个数组传递给一个函数的时候,你总是必须传递该数组的数组大小,除非数组是像0终止的cstring(char数组)。

当你声明一个指针variables或函数参数时,使用*:

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

注意:每个声明的variables都需要自己的*。

当你想取一个值的地址时,使用&。 当你想读或写一个指针的值,使用*。

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

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

函数指针是唯一不符合规则的东西。 你可以在不使用&的情况下获取一个函数的地址,你可以不使用*来调用一个函数指针。

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

本教程对初学者非常有用(清楚地说明了& * )。 是的,不要忘记阅读Kenneth Reek的“ C指针 ”一书。

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

例:

 #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 ie x */ printf("x is %d\n", x); (*p)++; /* increment what p points to ie x */ printf("x is %d\n", x); return 0; } 

其实,你已经把它拍下来了,没有什么你需要知道的:-)

我只是添加以下几点:

  • 这两个操作是频谱的两端。 &采取一个variables,并给你的地址, *取地址,并给你variables(或内容)。
  • 当你将它们传递给函数时,数组“降级”成指针。
  • 你可以实际上有多个间接级别( char **p意味着p是一个指向char的指针。

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

  • 如前所述,当传递给函数时,数组会降级为指针(指向数组中的第一个元素); 他们不保存大小信息。
  • C中没有string,只是字符数组,按照惯例,它表示由零( \0 )字符终止的string。
  • 当你将一个variables的地址传递给一个函数时,你可以去引用指针来改变variables本身(通常variables是通过值传递的(数​​组除外))。

好的,看起来像你的文章被编辑…

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

看看如何使用&来得到数组结构开始的地址? 下列

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

将做同样的事情。

我正在翻阅所有冗长的解释,转而用新南威尔士大学的video来解救。下面是简单的解释:如果我们有一个地址为x ,值为7的单元格,值7&7 ,要求在地址x处的值的间接方式是*x .So (cell: x , value: 7) == (cell: &7 , value: *x) 。另一种查看方式: John坐在7th seat*7th seat将指向John&John将给7th seat address /位置。 这个简单的解释帮助了我,并希望它也能帮助别人。 以下是优秀video的链接: 点击此处。

这是另一个例子:

 #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(); } 

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