C 指向数组/指针数组的指针消歧

发布于 2024-07-20 20:38:46 字数 116 浏览 10 评论 0原文

以下声明之间有什么区别:

int* arr1[8];
int (*arr2)[8];
int *(arr3[8]);

理解更复杂声明的一般规则是什么?

What is the difference between the following declarations:

int* arr1[8];
int (*arr2)[8];
int *(arr3[8]);

What is the general rule for understanding more complex declarations?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

何必那么矫情 2024-07-27 20:38:46
int* arr[8]; // An array of int pointers.
int (*arr)[8]; // A pointer to an array of integers

第三个与第一个相同。

一般规则是运算符优先级。 当函数指针出现时,它会变得更加复杂。

int* arr[8]; // An array of int pointers.
int (*arr)[8]; // A pointer to an array of integers

The third one is same as the first.

The general rule is operator precedence. It can get even much more complex as function pointers come into the picture.

千纸鹤带着心事 2024-07-27 20:38:46

按照 K&R 的建议,使用 cdecl 程序。

$ cdecl
Type `help' or `?' for help
cdecl> explain int* arr1[8];
declare arr1 as array 8 of pointer to int
cdecl> explain int (*arr2)[8]
declare arr2 as pointer to array 8 of int
cdecl> explain int *(arr3[8])
declare arr3 as array 8 of pointer to int
cdecl>

反之亦然。

cdecl> declare x as pointer to function(void) returning pointer to float
float *(*x)(void )

Use the cdecl program, as suggested by K&R.

$ cdecl
Type `help' or `?' for help
cdecl> explain int* arr1[8];
declare arr1 as array 8 of pointer to int
cdecl> explain int (*arr2)[8]
declare arr2 as pointer to array 8 of int
cdecl> explain int *(arr3[8])
declare arr3 as array 8 of pointer to int
cdecl>

It works the other way too.

cdecl> declare x as pointer to function(void) returning pointer to float
float *(*x)(void )
[旋木] 2024-07-27 20:38:46

我不知道它是否有正式名称,但我称之为 Right-Left Thingy(TM)。

从变量开始,然后向右、向左、向右......等等。

int* arr1[8];

arr1 是一个由 8 个指向整数的指针组成的数组。

int (*arr2)[8];

arr2 是一个指向数组的指针(括号左右) 8 个整数。

int *(arr3[8]);

arr3 是一个由 8 个整数指针组成的数组。

这应该可以帮助您处理复杂的声明。

I don't know if it has an official name, but I call it the Right-Left Thingy(TM).

Start at the variable, then go right, and left, and right...and so on.

int* arr1[8];

arr1 is an array of 8 pointers to integers.

int (*arr2)[8];

arr2 is a pointer (the parenthesis block the right-left) to an array of 8 integers.

int *(arr3[8]);

arr3 is an array of 8 pointers to integers.

This should help you out with complex declarations.

臻嫒无言 2024-07-27 20:38:46
int *a[4]; // Array of 4 pointers to int

int (*a)[4]; //a is a pointer to an integer array of size 4

int (*a[8])[5]; //a is an array of pointers to integer array of size 5 
int *a[4]; // Array of 4 pointers to int

int (*a)[4]; //a is a pointer to an integer array of size 4

int (*a[8])[5]; //a is an array of pointers to integer array of size 5 
反差帅 2024-07-27 20:38:46

后两项的答案也可以从C语言的黄金法则中推导出来:

声明遵循使用。

int (*arr2)[8];

如果取消引用 arr2 会发生什么? 您将得到一个包含 8 个整数的数组。

int *(arr3[8]);

如果从 arr3 中获取一个元素会发生什么? 你得到一个指向整数的指针。

这在处理函数指针时也很有帮助。 以 sigjuice 为例:

float *(*x)(void )

当您取消引用 x 时会发生什么? 您将获得一个可以不带参数调用的函数。 当你调用它时会发生什么? 它将返回一个指向float的指针。

不过,运算符优先级总是很棘手。 然而,使用括号实际上也可能会造成混淆,因为声明紧随使用。 至少,对我来说,直观上 arr2 看起来像是一个由 8 个指向整数的指针组成的数组,但实际上恰恰相反。 只是需要一些时间来适应。 如果你问我的话,有足够的理由总是向这些声明添加注释:)

编辑:示例

顺便说一句,我刚刚偶然发现了以下情况:一个具有静态矩阵并使用指针的函数算术以查看行指针是否越界。 示例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define NUM_ELEM(ar) (sizeof(ar) / sizeof((ar)[0]))

int *
put_off(const int newrow[2])
{
    static int mymatrix[3][2];
    static int (*rowp)[2] = mymatrix;
    int (* const border)[] = mymatrix + NUM_ELEM(mymatrix);

    memcpy(rowp, newrow, sizeof(*rowp));
    rowp += 1;
    if (rowp == border) {
        rowp = mymatrix;
    }

    return *rowp;
}

int
main(int argc, char *argv[])
{
    int i = 0;
    int row[2] = {0, 1};
    int *rout;

    for (i = 0; i < 6; i++) {
        row[0] = i;
        row[1] += i;
        rout = put_off(row);
        printf("%d (%p): [%d, %d]\n", i, (void *) rout, rout[0], rout[1]);
    }

    return 0;
}

输出:

0 (0x804a02c): [0, 0]
1 (0x804a034): [0, 0]
2 (0x804a024): [0, 1]
3 (0x804a02c): [1, 2]
4 (0x804a034): [2, 4]
5 (0x804a024): [3, 7]

请注意,border 的值永远不会改变,因此编译器可以对其进行优化。 这与您最初可能想要使用的不同:const int (*border)[3]:它将 border 声明为指向 3 个整数的数组的指针,只要变量存在。 但是,该指针可以随时指向任何其他此类数组。 相反,我们希望参数具有这种行为(因为该函数不会更改任何这些整数)。 使用后声明。

(ps:请随意改进此示例!)

The answer for the last two can also be deducted from the golden rule in C:

Declaration follows use.

int (*arr2)[8];

What happens if you dereference arr2? You get an array of 8 integers.

int *(arr3[8]);

What happens if you take an element from arr3? You get a pointer to an integer.

This also helps when dealing with pointers to functions. To take sigjuice's example:

float *(*x)(void )

What happens when you dereference x? You get a function that you can call with no arguments. What happens when you call it? It will return a pointer to a float.

Operator precedence is always tricky, though. However, using parentheses can actually also be confusing because declaration follows use. At least, to me, intuitively arr2 looks like an array of 8 pointers to ints, but it is actually the other way around. Just takes some getting used to. Reason enough to always add a comment to these declarations, if you ask me :)

edit: example

By the way, I just stumbled across the following situation: a function that has a static matrix and that uses pointer arithmetic to see if the row pointer is out of bounds. Example:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define NUM_ELEM(ar) (sizeof(ar) / sizeof((ar)[0]))

int *
put_off(const int newrow[2])
{
    static int mymatrix[3][2];
    static int (*rowp)[2] = mymatrix;
    int (* const border)[] = mymatrix + NUM_ELEM(mymatrix);

    memcpy(rowp, newrow, sizeof(*rowp));
    rowp += 1;
    if (rowp == border) {
        rowp = mymatrix;
    }

    return *rowp;
}

int
main(int argc, char *argv[])
{
    int i = 0;
    int row[2] = {0, 1};
    int *rout;

    for (i = 0; i < 6; i++) {
        row[0] = i;
        row[1] += i;
        rout = put_off(row);
        printf("%d (%p): [%d, %d]\n", i, (void *) rout, rout[0], rout[1]);
    }

    return 0;
}

Output:

0 (0x804a02c): [0, 0]
1 (0x804a034): [0, 0]
2 (0x804a024): [0, 1]
3 (0x804a02c): [1, 2]
4 (0x804a034): [2, 4]
5 (0x804a024): [3, 7]

Note that the value of border never changes, so the compiler can optimize that away. This is different from what you might initially want to use: const int (*border)[3]: that declares border as a pointer to an array of 3 integers that will not change value as long as the variable exists. However, that pointer may be pointed to any other such array at any time. We want that kind of behaviour for the argument, instead (because this function does not change any of those integers). Declaration follows use.

(p.s.: feel free to improve this sample!)

毁梦 2024-07-27 20:38:46
typedef int (*PointerToIntArray)[];
typedef int *ArrayOfIntPointers[];
typedef int (*PointerToIntArray)[];
typedef int *ArrayOfIntPointers[];
星軌x 2024-07-27 20:38:46

根据经验,右一元运算符(如 []() 等)优先于左一元运算符。 因此,int *(*ptr)()[];将是一个指针,它指向一个函数,该函数返回一个指向int的指针数组(一旦获得,请尽快获得正确的运算符)括号外)

As a rule of thumb, right unary operators (like [], (), etc) take preference over left ones. So, int *(*ptr)()[]; would be a pointer that points to a function that returns an array of pointers to int (get the right operators as soon as you can as you get out of the parenthesis)

星光不落少年眉 2024-07-27 20:38:46

我认为我们可以使用简单的规则..

example int * (*ptr)()[];
start from ptr 

ptr 是一个指向”的指针
向右走..它的“)”现在向左走它的“(”
出来后向右走“()”所以
” 到一个不带参数的函数“ go left ”并返回一个指针“ go right ”
整数数组“向左”

I think we can use the simple rule ..

example int * (*ptr)()[];
start from ptr 

" ptr is a pointer to "
go towards right ..its ")" now go left its a "("
come out go right "()" so
" to a function which takes no arguments " go left "and returns a pointer " go right "to
an array" go left " of integers "

末骤雨初歇 2024-07-27 20:38:46

我是这样解释的:

int *something[n];

关于优先级的注意事项:数组下标运算符 ([]) 的优先级高于
取消引用运算符 (*)。

因此,这里我们将在 * 之前应用 [],使语句等效于:

int *(something[i]);

注意声明的意义:int num 表示 numintint *ptrint (*ptr) 表示(ptr 处的值)是
int,它使 ptr 成为指向 int 的指针。

这可以理解为,((某物的第 i 个索引处的值)的值)是一个整数。 因此,(something 的第 i 个索引处的值) 是一个 (整数指针),这使得该 thing 成为一个整数指针数组。

在第二个中,

int (*something)[n];

为了理解这一说法,您必须熟悉以下事实:

关于数组指针表示的注意事项:somethingElse[i] 相当于 *(somethingElse + i)

因此,将 somethingElse 替换为 ( *something),我们得到*(*something + i),根据声明它是一个整数。 因此,(*something) 给了我们一个数组,这使得某些东西相当于(指向数组的指针)

Here's how I interpret it:

int *something[n];

Note on precedence: array subscript operator ([]) has higher priority than
dereference operator (*).

So, here we will apply the [] before *, making the statement equivalent to:

int *(something[i]);

Note on how a declaration makes sense: int num means num is an int, int *ptr or int (*ptr) means, (value at ptr) is
an int, which makes ptr a pointer to int.

This can be read as, (value of the (value at ith index of the something)) is an integer. So, (value at the ith index of something) is an (integer pointer), which makes the something an array of integer pointers.

In the second one,

int (*something)[n];

To make sense out of this statement, you must be familiar with this fact:

Note on pointer representation of array: somethingElse[i] is equivalent to *(somethingElse + i)

So, replacing somethingElse with (*something), we get *(*something + i), which is an integer as per declaration. So, (*something) given us an array, which makes something equivalent to (pointer to an array).

无法回应 2024-07-27 20:38:46

我想第二个声明让很多人感到困惑。 这是一个简单的方法来理解它。

让我们有一个整数数组,即int B[8]

我们还有一个指向 B 的变量 A。现在,A 的值为 B,即 (*A) == B。 因此 A 指向一个整数数组。 在你的问题中,arr类似于A。

同样,在int* (*C) [8]中,C是一个指向整数指针数组的指针。

I guess the second declaration is confusing to many. Here's an easy way to understand it.

Lets have an array of integers, i.e. int B[8].

Let's also have a variable A which points to B. Now, value at A is B, i.e. (*A) == B. Hence A points to an array of integers. In your question, arr is similar to A.

Similarly, in int* (*C) [8], C is a pointer to an array of pointers to integer.

权谋诡计 2024-07-27 20:38:46
int *arr1[5]

在此声明中,arr1 是一个由 5 个整数指针组成的数组。
原因:方括号的优先级高于 *(解引用运算符)。
在这种类型中,行数是固定的(此处为 5),但列数是可变的。

int (*arr2)[5]

在此声明中,arr2 是指向包含 5 个元素的整数数组的指针。
原因:这里,()括号的优先级高于[]。
在这种类型中,行数是可变的,但列数是固定的(此处为 5)。

int *arr1[5]

In this declaration, arr1 is an array of 5 pointers to integers.
Reason: Square brackets have higher precedence over * (dereferncing operator).
And in this type, number of rows are fixed (5 here), but number of columns is variable.

int (*arr2)[5]

In this declaration, arr2 is a pointer to an integer array of 5 elements.
Reason: Here, () brackets have higher precedence than [].
And in this type, number of rows is variable, but the number of columns is fixed (5 here).

南风起 2024-07-27 20:38:46

在指向整数的指针中,如果指针递增,则它会进入下一个整数。

在指针数组中,如果指针递增,它将跳转到下一个数组

In pointer to an integer if pointer is incremented then it goes next integer.

in array of pointer if pointer is incremented it jumps to next array

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文