Pointers in C: when to use the ampersand and the asterisk?
我刚开始用指针,我有点困惑。我知道
我什么时候应该使用
型
您有指针和值:
1 2 | int* p; // variable p is pointer to integer type int i; // integer value |
使用
1 | int i2 = *p; // integer i2 is assigned with integer value that pointer p is pointing to |
。
使用
1 | int* p2 = &i; // pointer p2 will point to the address of integer i |
编辑:在数组的情况下,它们被视为非常像指针。如果您将它们视为指针,您将使用
1 2 3 | 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 |
。
要获取第二个元素:
1 2 3 | int a[2]; // array int i = *(a + 1); // the value of the second element int i2 = a[1]; // the value of the second element |
。
因此,
1 | a[i] == *(a + i); // these two statements are the same thing |
在处理数组和函数时有一个模式;刚开始有点难看到。
在处理数组时,记住以下几点很有用:当数组表达式出现在大多数上下文中时,表达式的类型将隐式地从"t的n元素数组"转换为"指向t的指针",其值将设置为指向数组中的第一个元素。此规则的例外情况是,数组表达式显示为
因此,当使用数组表达式作为参数调用函数时,该函数将接收指针,而不是数组:
1 2 3 4 5 6 | int arr[10]; ... foo(arr); ... void foo(int *arr) { ... } |
这就是为什么您不使用
1 2 3 |
由于隐式转换,
实际上,您可能永远不会使用
1 2 3 4 5 | int arr[N]; ... foo(&arr); void foo(int (*p)[N]) {...} |
这种代码并不常见;您必须在函数声明中知道数组的大小,并且该函数只与指向特定大小数组的指针一起工作(指向t的10元素数组的指针与指向t的11元素数组的指针的类型不同)。
当数组表达式显示为
在处理函数和指针时,要记住的规则是:如果要更改参数的值并将其反映在调用代码中,则必须将指针传递给要修改的对象。同样,数组也会在工作中使用一些活动扳手,但我们将首先处理正常情况。
记住,C按值传递所有函数参数;形参接收实际参数中值的副本,形参的任何更改都不会反映在实际参数中。常见的例子是交换函数:
1 2 3 4 5 6 7 8 |
您将得到以下输出:
1 2 | before swap: a = 1, b = 2 after swap: a = 1, b = 2 |
形式参数
1 2 3 4 5 6 7 8 |
现在你的输出将是
1 2 | before swap: a = 1, b = 2 after swap: a = 2, b = 1 |
注意,在交换函数中,我们不会更改
如果我们想修改一个指针值,这也是一样的;如果我们写
1 2 3 4 |
然后我们修改输入参数
1 2 3 4 |
阵列再一次向工程中投入了一点活扳手。将数组表达式传递给函数时,函数接收的是指针。由于数组下标是如何定义的,因此可以在指针上使用下标运算符,方法与在数组上使用下标运算符的方法相同:
1 2 3 4 | 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;} |
请注意,数组对象可能未被分配;也就是说,您不能执行类似的操作
1 2 3 | int a[10], b[10]; ... a = b; |
所以在处理指向数组的指针时要小心;比如
1 2 3 4 5 | void (int (*foo)[N]) { ... *foo = ...; } |
不起作用。
简单地说
& 表示的地址,您将看到在用于修改参数变量的函数的占位符中,参数变量是通过值传递的,使用与符号和方法通过引用传递。* 表示指针变量的解引用,即获取该指针变量的值。
1 2 3 4 5 6 7 8 9 10 11 | 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 ", y); // output is 6 /* ... */ } |
上面的示例说明了如何使用pass-by引用调用函数
1 2 3 4 5 6 7 8 9 10 11 | 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 ", y); // output is 5 /* ... */ } |
下面是使用取消引用的示例
1 2 3 4 5 6 7 | int main(int argc, char **argv){ int y = 5; int *p = NULL; p = &y; printf("value of *p = %d ", *p); // output is 5 } |
上面说明了如何获取EDOCX1的地址(12),并将其分配给指针变量
是的,这是相当复杂的,因为EDCOX1的0度用于C/C++中的许多不同用途。
如果
- a)
* 允许访问该变量的值(如果该变量的类型是指针类型,或重载* 运算符)。 - b)
* 具有乘法运算符的含义,在这种情况下,* 左边必须有另一个变量。
如果
1 2 3 4 5 6 7 8 9 | 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 |
如果
如果
此外,您应该知道,当将数组传递给函数时,也必须传递该数组的数组大小,除非该数组类似于以0结尾的CString(char数组)。
型
声明指针变量或函数参数时,请使用*:
1 2 3 4 5 |
注意:每个声明的变量都需要自己的*。
如果要获取值的地址,请使用&;。当您要读取或写入指针中的值时,请使用*。
1 2 3 4 5 6 | int a; int *b; b = f(&a); a = *b; a = *f(&a); |
号
数组通常被视为指针。当您在函数中声明数组参数时,您可以很容易地将其声明为指针(这意味着相同的事情)。当向函数传递数组时,实际上是向第一个元素传递指针。
函数指针是唯一不完全遵循规则的东西。您可以不使用&;获取函数的地址,也可以不使用*调用函数指针。
型
我觉得你有点困惑。你应该阅读一本关于指针的好教程/书。
本教程非常适合初学者(清楚地解释了
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #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 ", x); printf("*p is %d ", *p); *p += 1; /* increment what p points to i.e x */ printf("x is %d ", x); (*p)++; /* increment what p points to i.e x */ printf("x is %d ", x); return 0; } |
。
型
事实上,你已经把它拍下来了,你再也不需要知道什么了:—)
我只需添加以下位:
- 百万千克1这两个操作是频谱的两端。
型
对于工作方式不同的事情,不是:
- 百万千克1如前所述,数组在传递给函数时降级为指针(指向数组中的第一个元素);它们不保留大小信息。百万千克1百万千克1C中没有字符串,只是字符数组,按照约定,它表示以零(
型
我看了一遍所有冗长的解释,转而看了新南威尔士大学的一段视频来救援。下面是一个简单的解释:如果我们有一个单元格的地址是
下面是另一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #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 ", *p ); /* Note the use of the * to get the value */ getchar(); } |
附加组件:在使用指针之前总是初始化指针。如果不初始化,指针将指向任何可能导致程序崩溃的东西,因为操作系统会阻止您访问它知道您不拥有的内存。但只要将
型
好吧,看来你的文章被编辑了…
1 2 | double foo[4]; double *bar_1 = &foo[0]; |
看看如何使用
1 2 | Foo_1(double *bar, int size){ return bar[size-1]; } Foo_2(double bar[], int size){ return bar[size-1]; } |
号
会做同样的事情。