为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C
慕丝7291255 2019-08-23 14:33:03
C中的指针:何时使用&符号和星号?我刚开始用指针,我有点困惑。我知道&一个变量的地址,它*可以在指针变量前面使用,以获取指针指向的对象的值。但是当您使用数组,字符串或使用变量的指针副本调用函数时,情况会有所不同。在所有这些内部很难看到逻辑模式。什么时候应该使用&和*?
查看完整描述

3 回答

?
湖上湖

TA贡献2003条经验 获得超2个赞

你有指针和价值观:


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

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


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


查看完整回答
反对 回复 2019-08-23
?
拉莫斯之舞

TA贡献1820条经验 获得超10个赞

处理数组和函数时有一种模式; 起初有点难以看到。

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

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

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

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

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

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

在实践中,您可能永远不会使用&运算符调用带有数组表达式的函数,如:

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

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

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

在处理函数和指针时,要记住的规则是:如果要更改参数的值并将其反映在调用代码中,则必须将指针传递给要修改的事物。同样,数组会投入一些动作,但我们会首先处理正常情况。

请记住,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);

您将获得以下输出:

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

形式参数xy从不同的对象ab,所以要改变xy未在反射ab。因为我们要修改的值ab,我们必须通过指针,以他们的交换功能:

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

请注意,在交换函数中,我们不会更改xand y的值,而是更改what xy 指向的值。写作*x不同于写作x; 我们没有更新价值x本身,我们从该位置获取位置x并更新该位置的值。

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

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

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

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

再次,阵列投入了一些猴子扳手。将数组表达式传递给函数时,函数接收的是指针。由于如何定义数组下标,您可以在指针上使用下标运算符,就像在数组上使用它一样:

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

不行。


查看完整回答
反对 回复 2019-08-23
  • 3 回答
  • 0 关注
  • 755 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信